c# - WPF 绑定(bind)依赖属性

标签 c# wpf xaml binding dependency-properties

我在绑定(bind) UserControl 中的依赖属性时遇到问题。当它初始化时它得到一个值但随后它不会更新。我可能错过了一些明显的东西,这里有一些代码片段:

这是我绑定(bind) BalanceContent 依赖属性的地方:

<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4" 
                          BalanceContent="{Binding Source={StaticResource UserData}, Path=SelectedUser.Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">

    </Game:PlayerDetails>

这是 UserControl 中的 TextBox:

 <TextBox  VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2" 
         Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}, Path=BalanceContent}" 
             Grid.Row="7"></TextBox>

这是依赖属性:

public static readonly DependencyProperty BalanceContentProperty = DependencyProperty.Register(
        "BalanceContent", typeof(string), typeof(PlayerDetails));

    public string BalanceContent
    {
        get
        {return (string) GetValue(BalanceContentProperty);}
        set
        {SetValue(BalanceContentProperty, value);}
    }

这是更新所选用户的列表,它位于使用 UserControl 的 View 中:

<ListView x:Name="lstAccounts"  Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Grid.RowSpan="4" 
              ItemsSource="{Binding Source={StaticResource UserData}, Path=CurrentUserSearch}" 
              SelectedItem="{Binding Source={StaticResource UserData}, Path=SelectedUser}"

SelectedUser 在这里定义在一个实现了 INotifyPropertyChanged 的类中:

 public User SelectedUser
    {
        get
        {
            return _selectedUser;
        } 
        set
        {
            _selectedUser = value;
            OnPropertyChanged(new PropertyChangedEventArgs("SelectedUser"));
        }
    }

想法是,当在列表中选择新用户时,TextBox 应该更新,但目前它没有这样做。我已将绑定(bind)放在本地 TextBox 上,它更新正常,只是不在 DependencyProperty 上。任何帮助表示赞赏。

最佳答案

您可以尝试一些可能性:

首先,您的 ListView 可能不会更新您的 ViewModel 的 SelectedUser 属性。尝试将 ListView 中的绑定(bind)设置为“TwoWay”模式:

<ListView x:Name="lstAccounts"  Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="2" Grid.RowSpan="4" 
          ItemsSource="{Binding Source={StaticResource UserData}, Path=CurrentUserSearch}" 
          SelectedItem="{Binding Source={StaticResource UserData}, Path=SelectedUser, Mode=TwoWay}"/>

您可以更好地组织 DataContext 的定义方式。请记住,您的 UserControl 的所有子控件都可以访问其 DataContext 而无需使用相对绑定(bind)(它们继承它)。由于您的 PlayerInfo 控件依赖于 SelectedUser,请考虑将其 DataContext 设置为 SelectedUser,将其绑定(bind)到 ListView 的 SelectedUser 或 UserData View 模型中的 SelectedUser。

 <Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4" DataContext="{Binding Source={StaticResource UserData}, Path=SelectedUser}"
                      BalanceContent="{Binding Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">

</Game:PlayerDetails>

当前SelectedUser的来源也可以是ListView:

<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4" DataContext="{Binding SelectedItem, ElementName=lstAccounts}"
                      BalanceContent="{Binding Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">

</Game:PlayerDetails>

无论哪种方式,您都可以在 TextBox 上执行以下操作,因为它的 DataContext 将与其父项之一相同:

<TextBox  VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2" 
     Text="{Binding Balance}" 
         Grid.Row="7"></TextBox>

如果 usercontrol 依赖于 Root View 模型来执行命令和其他高级逻辑,则将 DataContext 设置为可以轻松访问 SelectedUser 的方式。

<Game:PlayerDetails x:Name="SelectedPlayerDetails" Grid.Row="1" Grid.Column="2" Grid.ColumnSpan="2" Grid.RowSpan="4" DataContext="{StaticResource UserData}"
                      BalanceContent="{Binding SelectedUser.Balance, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">

</Game:PlayerDetails>

所以你可以这样做:

<TextBox  VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2" 
     Text="{Binding SelectedUser.Balance}" 
         Grid.Row="7"></TextBox>

但是,在第二种方法中,您必须检查一件我不确定的事情。我知道当控件的 DataContext 发生变化时,它会更新所有相关的绑定(bind)。例如,如果您将 PlayerDetails DataContext 更改为另一个 UserData 实例,则 BalanceContent 属性也会更新。但是,在这种情况下,BalanceContent 取决于 UserData 的 SelectedUser 的属性。因此它将监听该用户实例的属性更改。如果 SelectedUser.Balance 发生变化(并且 User 实现了 INotifyPropertyChanged,或者它是一个 DependencyProperty),BalanceContent 将更新。现在,如果 UserData 中的 SelectedUser 实例发生变化,我不确定 BalanceContent 是否会更新,因为我认为绑定(bind)不会监听其路径中每个对象的变化。

编辑

最后一点可能是我在使用 xaml 进行开发时遇到的第一个问题。我在 Silverlight 中有一个 DataGrid,其实体类型具有复杂类型的属性。其中一列取决于复杂类型的属性。如果我更改复杂类型的值,该列将更新正常(它实现了 INPC)。如果我更改实体的复杂类型实例,该列将不会... 解决方案是级联 DataContexts:我创建了一个模板列,为复杂类型设置列的绑定(bind),而不是它的属性。然后我将模板的 TextBox 的文本绑定(bind)到复杂类型的属性,因为它现在是 TextBox 的 DataContext。

在您的情况下,您可以为 TextBox.Text 执行此操作,但不能为 PlayerDetails.BalanceContent 执行此操作。您可以将 TextBox.DataContext 绑定(bind)到 UserData 的 SelectedUser,然后将 Text 绑定(bind)到 Balance 属性。

<TextBox  VerticalAlignment="Center" DataContext="{Binding SelectedUser}" FontFamily="Formata" FontSize="20" Grid.Column="2" 
 Text="{Binding Balance}" 
     Grid.Row="7"></TextBox>

关于c# - WPF 绑定(bind)依赖属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13477486/

相关文章:

c# - 我如何使用线程到 'tick' 计时器以供其他线程访问?

c# - 为什么我的 comboBox 的 SelectedValuePath 属性行为不正常?

xaml - 将项目添加到嵌套列表后更新 GridView

c# - iOS 上的 SQLite - 从一个文件复制到另一个文件的 SQL

c# - Signalr:当用户为特定用户发送消息时无法发回消息

c# - 在 C# 中过滤巨大列表的最高效方法?

c# - 如何在 visual studio 中添加程序集 DocumentFormat.OpenXml.Wordprocessin

c# - SelectiveScrollingGrid 是否只卡住第一列的列?

除非我重新创建整个列表,否则 WPF 绑定(bind)不会更新?

xaml - 如何禁用 ListView 中的单击? xamarin.形式