简体   繁体   English

Wpf绑定到对象属性不起作用

[英]Wpf Binding to object property didn't work

I have ViewModel 我有ViewModel

public class MessengerViewModel : INotifyBaseClass
{
    public ServiceManager ServiceManager { get; set; }

    private ObservableCollection<Conversation> _conversations;
    private Conversation _currentConversation;
    private MessagesPage _parent;
    private List<Conversation> _tempList;
    private bool _canClear;
    private bool _isSearching;
    private Random _random;

    public ObservableCollection<Conversation> Conversations
    {
        get { return _conversations; }
        set { SetField(ref _conversations, value); }
    }

    public Conversation CurrentConversation
    {
        get { return _currentConversation; }
        set
        {
            _parent.MessagesListBox.ItemsSource = value.Messages;

            if (_tempList != null)
            {

                if (_tempList.Contains(value))
                {
                    _tempList.Remove(value);
                }

                ClearSearchUsers();
                _parent.ConversationsListBox.Items.Refresh();
            }

            SetField(ref _currentConversation, value);
        }
    }
  ...
 }

Code of Conversation 会话代码

public class Conversation : INotifyBaseClass
{
    private string _interlocutorId;
    private ObservableCollection<Message> _messages;
    private string _name;
    private string _username;
    private Brush _brush;
    private bool _isActive;

    public bool IsActive
    {
        get { return _isActive; }
        set { SetField(ref _isActive, value); }
    }

    public string InterlocutorId
    {
        get { return _interlocutorId; }
        set { SetField(ref _interlocutorId, value); }
    }

    public string Name
    {
        get { return _name; }
        set { SetField(ref _name, value); }
    }

    public Brush Color
    {
        get { return _brush; }
        set { SetField(ref _brush, value); }
    }

    public string ShortName
    {
        get
        {
            var arr = _name.Split(' ');
            if (arr.Length == 1)
                return arr[0].ToUpper()[0].ToString();
            return arr.Aggregate((x, y) => $"{x[0]}{y[0]}").ToUpper();
        }
    }

    public string Username
    {
        get { return _username; }
        set { SetField(ref _username, value); }
    }

    public ObservableCollection<Message> Messages
    {
        get { return _messages; }
        set { SetField(ref _messages, value); }
    }
}

My Xaml code: 我的Xaml代码:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" MinWidth="260"/>
        <ColumnDefinition Width="auto"/>
        <ColumnDefinition Width="*" MinWidth="260"/>
    </Grid.ColumnDefinitions>
    <GridSplitter Grid.Column="1" x:Name="InterfaceSplitter" HorizontalAlignment="Center"  Width="3"/>
    <Grid Grid.Column="0" x:Name="ConversationsGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="65"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid x:Name="SearchAndMenuGrid" Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Image Source="../Resources/menuIcon.png" Width="40" VerticalAlignment="Center"/>
            <TextBox x:Name="SearchTextBox" Grid.Column="1" Height="30" Margin="15" FontFamily="Arial" VerticalContentAlignment="Center" TextChanged="SearchTextBox_TextChanged"/>
        </Grid>
        <ListBox x:Name="ConversationsListBox" Grid.Row="1" ItemsSource="{Binding Conversations}" SelectedItem="{Binding CurrentConversation}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Background="White" BorderThickness="0">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Margin="5" Height="55" Orientation="Horizontal" ClipToBounds="True">
                        <Border Background="{Binding Color}" Width="40" Height="40" VerticalAlignment="Center">
                            <Border.Clip>
                                <EllipseGeometry RadiusX="20" RadiusY="20" Center="20,20"/>
                            </Border.Clip>
                            <TextBlock FontSize="18" Text="{Binding Path=ShortName}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                        </Border>
                        <TextBlock FontSize="18" Text="{Binding Path=Name}" Margin="15,2.5" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                    </StackPanel>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsActive}" Value="False">
                            <Setter Property="Visibility" Value="Collapsed"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
    <Grid Grid.Column="2" x:Name="MessagesGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0" x:Name="ConversationPropertiesGrid" Background="White">
            <TextBlock Text="{Binding Path = CurrentConversation.Name, Converter={StaticResource DebugDummyConverter}}"/></Grid>
        <ListBox x:Name="MessagesListBox" Grid.Row="1" Background="Transparent" HorizontalContentAlignment="Stretch" ItemsSource="{Binding CurrentConversation.Messages}" ItemContainerStyle="{StaticResource RemoveSelectionStyle}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="0,5">
                        <Border x:Name="MessageBorder" CornerRadius="20">
                            <TextBlock x:Name="MessageTextBlock" FontSize="18" Text="{Binding Path = Content,PresentationTraceSources.TraceLevel=High}" HorizontalAlignment="Right" Margin="10,15"/>
                        </Border>
                    </Grid>
                    <DataTemplate.Triggers>
                        <DataTrigger Binding="{Binding IsAuthor}" Value="true">
                            <Setter TargetName="MessageBorder" Property="Background" Value="White"/>
                            <Setter TargetName="MessageBorder" Property="HorizontalAlignment" Value="Right"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsAuthor}" Value="false">
                            <Setter TargetName="MessageBorder" Property="Background" Value="Lime"/>
                            <Setter TargetName="MessageBorder" Property="HorizontalAlignment" Value="Left"/>
                        </DataTrigger>
                    </DataTemplate.Triggers>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Grid Grid.Row="2" x:Name="SendMessageGrid" Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <TextBox Name="MessageTextBox" Grid.Column="0" BorderThickness="0" Margin="10,10" VerticalContentAlignment="Center" AcceptsReturn="True" PreviewKeyDown="MessageTextBox_PreviewKeyDown"/>
        </Grid>
    </Grid>
</Grid>

The problem is when I'm trying to use Binding like in MessageListBox or in TextBlock {Binding CurrentConversation.Property}, binding fails with 问题是当我尝试在MessageListBox或TextBlock {Binding CurrentConversation.Property}中使用Binding时,绑定失败

System.Windows.Data Warning: 67 : BindingExpression (hash=8769005): Resolving source 
System.Windows.Data Warning: 70 : BindingExpression (hash=8769005): Found data context element: TextBlock (hash=46431654) (OK)
System.Windows.Data Warning: 78 : BindingExpression (hash=8769005): Activate with root item MessengerViewModel (hash=32244734)
System.Windows.Data Warning: 107 : BindingExpression (hash=8769005):   At level 0 using cached accessor for MessengerViewModel.CurrentConversation: RuntimePropertyInfo(CurrentConversation)
System.Windows.Data Warning: 104 : BindingExpression (hash=8769005): Replace item at level 0 with MessengerViewModel (hash=32244734), using accessor RuntimePropertyInfo(CurrentConversation)
System.Windows.Data Warning: 101 : BindingExpression (hash=8769005): GetValue at level 0 from MessengerViewModel (hash=32244734) using RuntimePropertyInfo(CurrentConversation): <null>
System.Windows.Data Warning: 106 : BindingExpression (hash=8769005):   Item at level 1 is null - no accessor
System.Windows.Data Warning: 80 : BindingExpression (hash=8769005): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 88 : BindingExpression (hash=8769005): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=8769005): TransferValue - using final value ''

But all properties of CurrentConversation are initiated. 但是,CurrentConversation的所有属性都已启动。 At the beginnig CurrentConversation is null, until user select it in ConversationsListBox. 在beginnig,CurrentConversation为null,直到用户在ConversationsListBox中选择它。 I thought may be that is problem, but I add _currentConversation = new Conversation() and binding stil doesn't work. 我认为这可能是问题,但我添加_currentConversation = new Conversation()并且绑定stil不起作用。

Update 更新

My INotifyBaseClass: 我的INotifyBaseClass:

public class INotifyBaseClass : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetField<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value))
            return false;
        field = value;
        OnPropertyChanged();
        return true;
    }
}

Add ,"" in each setter ( SetField ) 在每个setter( SetField )中添加,""

Example: 例:

public bool IsActive
{
    get { return _isActive; }
    set { SetField(ref _isActive, value, ""); }
}

If you have such a function in the class: INotifyBaseClass 如果你在类中有这样的函数: INotifyBaseClass

protected bool SetField<T>(ref T field, T value, string propertyName)
{
    if (EqualityComparer<T>.Default.Equals(field, value)) return false;
    field = value;
    OnPropertyChanged(propertyName);
    return true;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM