我遇到了在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>
以下是TextBox
中的UserControl
:
<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
。任何帮助表示赞赏。
答案 0 :(得分:3)
您可以尝试一些可能性:
首先,您的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>
如果usercontrol依赖于命令和其他高级逻辑之类的根视图模型,则以可以轻松访问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>
所以你可以这样做:
<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的属性。所以它会监听User实例的Property更改。如果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>
答案 1 :(得分:1)
请在更改用户控件中文本框的绑定后尝试测试,以绑定到BalanceContent,即User Control Dependency Property(您的原始绑定源似乎是数据上下文属性)
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>
答案 2 :(得分:0)
Textbox正在尝试绑定到UserControls DataContext
。给Usercontrol定义一个x:Name
并将TextBox的DataContext设置为DataContext="{Binding ElementName=[YourControlName]}"
答案 3 :(得分:0)
<TextBox VerticalAlignment="Center" FontFamily="Formata" FontSize="20" Grid.Column="2"
Text="{Binding SelectedItem.BalanceContent, ElementName=lstAccounts}" Grid.Row="7"></TextBox>
忘记绑定UserControl,直接将TextBox绑定到SelectedItem。我希望这会有所帮助。
答案 4 :(得分:0)
您正在将StaticResource绑定到该属性。与DynamicResources相反,StaticResources仅在初始化Window(或UserControl)时加载一次。 DynamicResources仅在需要时(每次需要时)加载。将立即获取对DynamicResource所做的任何更改,并相应地更新属性。只需将关键字“StaticResource”替换为“DynamicResource”,每次资源更改时都应更新属性绑定。
注意:如果StaticResource是一个派生自Freezable类的对象,它的行为也会像DynamicResource。例如,如果您的资源是Brush,则每次以任何方式更改Brush对象时都会更新bound属性(例如,通过更改其不透明度),但这是由于从Freezable类继承的行为。但是,如果使用新的Brush对象替换StaticResource中的Brush对象,则不会拾取此更改,因为已对Resource进行了更改,即Static,而不是Brush。
另请注意:即使只作为StaticResources可用的资源(例如数据SystemColors,SystemFonts(提供对系统设置的访问权限))也可以包装在DynamicResource中,以确保在每次更改时更新属性。这可以这样做:
<Control Property="{DynamicResource {x:Static SystemColors.XXX}}"></Control>
。