WPF 绑定依赖属性

paj*_*777 5 c# wpf xaml binding dependency-properties

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

这是我绑定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>
Run Code Online (Sandbox Code Playgroud)

这是TextBoxUserControl

 <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>
Run Code Online (Sandbox Code Playgroud)

这是依赖属性:

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

    public string BalanceContent
    {
        get
        {return (string) GetValue(BalanceContentProperty);}
        set
        {SetValue(BalanceContentProperty, value);}
    }
Run Code Online (Sandbox Code Playgroud)

以下是更新所选用户的列表,该列表位于使用 UserControl 的视图中:

<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}"
Run Code Online (Sandbox Code Playgroud)

SelectedUser在一个实现的类中定义INotifyPropertyChanged

 public User SelectedUser
    {
        get
        {
            return _selectedUser;
        } 
        set
        {
            _selectedUser = value;
            OnPropertyChanged(new PropertyChangedEventArgs("SelectedUser"));
        }
    }
Run Code Online (Sandbox Code Playgroud)

这个想法是当在列表中选择一个新用户时 TextBox 应该更新,但目前它没有这样做。我已经将绑定放在本地 TextBox 上并且它更新得很好,只是不在DependencyProperty. 任何帮助表示赞赏。

Art*_*nes 4

您可以尝试以下一些可能性:

首先,您的 ListView 可能不会更新您的 ViewModel 的 SelectedUser 属性。尝试将 ListView 中的绑定设置为“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}"/>
Run Code Online (Sandbox Code Playgroud)

您可以更好地组织 DataContext 的定义方式。请记住,UserControl 的所有子控件都可以访问其 DataContext,而无需使用相对绑定(它们继承它)。由于您的 PlayerInfo 控件依赖于 SelectedUser,因此请考虑将其 DataContext 设置为 SelectedUser,将其绑定到 ListView 的 SelectedUser 或 UserData 视图模型中的 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>
Run Code Online (Sandbox Code Playgroud)

当前 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>
Run Code Online (Sandbox Code Playgroud)

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

<TextBox  VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2" 
     Text="{Binding Balance}" 
         Grid.Row="7"></TextBox>
Run Code Online (Sandbox Code Playgroud)

如果用户控件依赖于根视图模型来执行命令和其他高级逻辑等操作,则以可以轻松访问 SelectedUser 的方式将 DataContext 设置为它。

<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>
Run Code Online (Sandbox Code Playgroud)

所以你可以这样做:

<TextBox  VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2" 
     Text="{Binding SelectedUser.Balance}" 
         Grid.Row="7"></TextBox>
Run Code Online (Sandbox Code Playgroud)

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

编辑

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

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

<TextBox  VerticalAlignment="Center" DataContext="{Binding SelectedUser}" FontFamily="Formata" FontSize="20" Grid.Column="2" 
 Text="{Binding Balance}" 
     Grid.Row="7"></TextBox>
Run Code Online (Sandbox Code Playgroud)