5

我在 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>

这是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>

这是依赖属性:

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 的视图中:

<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 应该更新,但目前它没有这样做。我已经将绑定放在本地 TextBox 上,它更新得很好,只是没有放在DependencyProperty. 任何帮助表示赞赏。

4

5 回答 5

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}"/>

您可以更好地组织 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>

当前 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>

如果用户控件在命令和其他高级逻辑等方面依赖于根视图模型,则将 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 发生变化时,它会更新所有的依赖绑定。例如,如果您将 PlayerDetails DataContext 更改为另一个 UserData 实例,则 BalanceContent 属性也会更新。但是,在这种情况下,BalanceContent 取决于 UserData 的 SelectedUser 的属性。所以它将监听该用户实例的属性更改。如果 SelectedUser.Balance 发生变化(并且 User 实现了 INotifyPropertyChanged,或者它是一个 DependencyProperty),BalanceContent 将更新。现在,如果 UserData 中的 SelectedUser 实例发生更改,我不确定 BalanceContent 是否会更新,因为我认为绑定不会监听其路径中每个对象的更改。

编辑

最后一点可能是我在使用 xaml 开发时遇到的第一个问题。我在 Silverlight 中有一个 DataGrid,其实体类型具有复杂类型的属性。其中一列取决于复杂类型的属性。如果我更改了复杂类型的值,该列会更新得很好(它实现了 INPC)。如果我更改了实体的复杂类型实例,该列将不会... 解决方案是级联 DataContexts:我创建了一个模板列,为复杂类型设置列的绑定,而不是其属性。然后我将模板的 TextBox 的文本绑定到 complextype 的属性,因为它现在是 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>
于 2012-11-21T11:49:41.913 回答
1

请在更改用户控件内的文本框绑定以绑定到作为用户控件依赖属性的 BalanceContent 后尝试测试(您的原始绑定源似乎是数据上下文属性)

Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type UserControl}}, Path=BalanceContent}"

编辑:请尝试以下代码

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

public string SelectedUserBalance
    {
        get
        {
            return _selectedUser.Balance;
        } 
    }

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

</Game:PlayerDetails>

<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>
于 2012-11-20T16:31:29.963 回答
0

文本框正在尝试绑定到 UserControls DataContext。给x:NameUsercontrol 定义并将 TextBox 的 DataContext 设置为DataContext="{Binding ElementName=[YourControlName]}"

于 2012-11-20T16:23:55.640 回答
0

您正在将 StaticResource 绑定到该属性。与 DynamicResources 不同,StaticResources 仅在初始化 Window(或 UserControl)时加载一次。DynamicResources 仅在需要时加载(并且每次都在需要时)。对 DynamicResource 所做的任何更改都会立即获取并相应地更新属性。只需将关键字“StaticResource”替换为“DynamicResource”,每次资源更改时属性绑定都会更新。

注意:如果 StaticResource 是从 Freezable 类派生的对象,它的行为也有点像 DynamicResource。例如,如果您的资源是 Brush,则每次您以任何方式更改 Brush 对象(例如,通过更改其不透明度)时,绑定属性都会更新,但这是由于继承自 Freezable 类的行为所致。但是,如果您将 StaticResource 中的 Brush 对象替换为新的 Brush 对象,则不会执行此更改,因为已对 Resource 进行了更改,它是 Static,而不是 Brush。

另请注意:即使是仅作为静态资源可用的资源,例如数据 SystemColors、SystemFonts(提供对系统设置的访问)也可以包装在 DynamicResource 中,以确保在每次更改时更新属性。这可以通过以下方式完成:

<Control Property="{DynamicResource {x:Static SystemColors.XXX}}"></Control>.

于 2014-07-29T22:43:48.763 回答
0
<TextBox VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2" 
       Text="{Binding SelectedItem.BalanceContent, ElementName=lstAccounts}" Grid.Row="7"></TextBox>

忘记绑定 UserControl ,直接绑定 TextBox 到 SelectedItem 。我希望这将有所帮助。

于 2012-11-20T16:29:36.947 回答