在依赖项 属性 中更新 属性 未显示在视图中
Updating property within Dependency property doesn't show within view
我有一个 class,叫做 Clan。 Clan 中的一个 属性 是一个 bool Voiced,默认为 false。
我有一个观点,ClanUI。这具有 Clan 类型的依赖项 属性。
在 VM 中,我有一个 属性 类型的 Clan,它作为依赖项传递到视图中 属性:
<UC:ClanUI Clan="{Binding Meilyr}" />
在 ClanUI 视图中,我有一个图像,它在 VM 中调用一个命令。它使用正确的 DataContext:
...
<i:InvokeCommandAction Command="{Binding DataContext.ClanVoiced, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" CommandParameter="{Binding Clan.Name}" />
...
在 VM 中的那个命令中,我在 属性 Meilyr 上设置了 Voiced 的值,它作为 DP 从假到真传递到视图中。
在视图中,我有一个数据触发器,它应该反映声音的变化。
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<DataTrigger Binding="{Binding Clan.Voiced}" Value="false">
<Setter Property="BorderThickness" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
我试过从 Voiced 默认为 true 开始,这显示边框粗细为 2。所以绑定工作正常。我已经调试,代码正确命中 VM,Meilyr voiced 属性 被更改为 true,并且正确调用 On属性Changed。
我不知道为什么,当我从 VM 更改 DP 中的值时,它不会在视图中反映这些更改。
编辑: 根据要求提供更多代码
这是视图中的边框和图像。单击图像调用 VM 中的命令
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
...
<Border BorderBrush="Red" Margin="5">
<Image Source="{Binding Clan.Image, FallbackValue='../Media/Clans/Meilyr.png'}" Height="40" VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding DataContext.ClanVoiced, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" CommandParameter="{Binding Clan.Name}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<DataTrigger Binding="{Binding Clan.Voiced}" Value="false">
<Setter Property="BorderThickness" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
...
</Grid>
这里是 xaml.cs 中的依赖项 属性:
public Clan Clan
{
get { return (Clan)GetValue(ClanProperty); }
set { SetValue(ClanProperty, value); }
}
public static readonly DependencyProperty ClanProperty =
DependencyProperty.Register("Clan", typeof(Clan),
typeof(ClanUI), new PropertyMetadata(null));
在主视图中,我是这样放置视图的:
<UC:ClanUI Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2" Clan="{Binding Meilyr}" />
以下是 VM 中的一些片段:
private Clan _Meilyr = new Clan();
public Clan Meilyr
{
get
{
return _Meilyr;
}
set
{
_Meilyr = value;
OnPropertyChanged("Meilyr");
}
}
...
private ICommand _ClanVoiced;
public ICommand ClanVoiced
{
get
{
if (_ClanVoiced == null)
{
_ClanVoiced = new RelayCommand(ClanVoicedEx, null);
}
return _ClanVoiced;
}
}
private void ClanVoicedEx(object p)
{
if(Clans.FindAll(C => C.Voiced).Count >= 2)
{
//TODO
}
//Clans.First(C => C.Name == p.ToString()).Voiced = true; //<< This is how I will eventually be doing it, the next line was to ensure I was setting the correct thing.
Meilyr.Voiced = true; //When debugging, when I click the image this line is hit, and after it has executed, inspecting Meilyr.Voiced shows it as being true.
}
最后,这里是 Clan.cs 中的浊音 属性,以及 On属性Changed.
private bool _Voiced = false; //<< When I default this to true instead, it displays how I expect in the view. Initial bindings seem to work fine. It just doesn't seem to know when Voiced changes for some reason...
public bool Voiced
{
get
{
return _Voiced;
}
set
{
_Voiced = value;
OnPropertyChanged("Voiced");
}
}
...
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
if (handler.Target is CollectionView)
{
((CollectionView)handler.Target).Refresh();
}
else
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
#endregion
你能post ViewModel 代码吗?
我假设您更新的是 Clan 属性 已更改但语音 属性 未更改。换句话说,有声需要是一个 属性,它自己 属性 改变了事件触发。
确保 Clan
class 实现了 INotifyPropertyChanged
接口并在有声 属性 的 setter 中引发了 PropertyChanged
事件].
由于您要绑定到 Clan.Voiced 属性,因此定义 Meilyr 和 ClanVoided 属性的视图模型 class 是否实现 INotifyPropertyChanged
并不重要接口。
我有一个 class,叫做 Clan。 Clan 中的一个 属性 是一个 bool Voiced,默认为 false。
我有一个观点,ClanUI。这具有 Clan 类型的依赖项 属性。
在 VM 中,我有一个 属性 类型的 Clan,它作为依赖项传递到视图中 属性:
<UC:ClanUI Clan="{Binding Meilyr}" />
在 ClanUI 视图中,我有一个图像,它在 VM 中调用一个命令。它使用正确的 DataContext:
...
<i:InvokeCommandAction Command="{Binding DataContext.ClanVoiced, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" CommandParameter="{Binding Clan.Name}" />
...
在 VM 中的那个命令中,我在 属性 Meilyr 上设置了 Voiced 的值,它作为 DP 从假到真传递到视图中。
在视图中,我有一个数据触发器,它应该反映声音的变化。
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<DataTrigger Binding="{Binding Clan.Voiced}" Value="false">
<Setter Property="BorderThickness" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
我试过从 Voiced 默认为 true 开始,这显示边框粗细为 2。所以绑定工作正常。我已经调试,代码正确命中 VM,Meilyr voiced 属性 被更改为 true,并且正确调用 On属性Changed。
我不知道为什么,当我从 VM 更改 DP 中的值时,它不会在视图中反映这些更改。
编辑: 根据要求提供更多代码
这是视图中的边框和图像。单击图像调用 VM 中的命令
<Grid DataContext="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}">
...
<Border BorderBrush="Red" Margin="5">
<Image Source="{Binding Clan.Image, FallbackValue='../Media/Clans/Meilyr.png'}" Height="40" VerticalAlignment="Center">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseUp">
<i:InvokeCommandAction Command="{Binding DataContext.ClanVoiced, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" CommandParameter="{Binding Clan.Name}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Image>
<Border.Style>
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness" Value="2" />
<Style.Triggers>
<DataTrigger Binding="{Binding Clan.Voiced}" Value="false">
<Setter Property="BorderThickness" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
...
</Grid>
这里是 xaml.cs 中的依赖项 属性:
public Clan Clan
{
get { return (Clan)GetValue(ClanProperty); }
set { SetValue(ClanProperty, value); }
}
public static readonly DependencyProperty ClanProperty =
DependencyProperty.Register("Clan", typeof(Clan),
typeof(ClanUI), new PropertyMetadata(null));
在主视图中,我是这样放置视图的:
<UC:ClanUI Grid.Column="1" Grid.Row="0" Grid.ColumnSpan="2" Clan="{Binding Meilyr}" />
以下是 VM 中的一些片段:
private Clan _Meilyr = new Clan();
public Clan Meilyr
{
get
{
return _Meilyr;
}
set
{
_Meilyr = value;
OnPropertyChanged("Meilyr");
}
}
...
private ICommand _ClanVoiced;
public ICommand ClanVoiced
{
get
{
if (_ClanVoiced == null)
{
_ClanVoiced = new RelayCommand(ClanVoicedEx, null);
}
return _ClanVoiced;
}
}
private void ClanVoicedEx(object p)
{
if(Clans.FindAll(C => C.Voiced).Count >= 2)
{
//TODO
}
//Clans.First(C => C.Name == p.ToString()).Voiced = true; //<< This is how I will eventually be doing it, the next line was to ensure I was setting the correct thing.
Meilyr.Voiced = true; //When debugging, when I click the image this line is hit, and after it has executed, inspecting Meilyr.Voiced shows it as being true.
}
最后,这里是 Clan.cs 中的浊音 属性,以及 On属性Changed.
private bool _Voiced = false; //<< When I default this to true instead, it displays how I expect in the view. Initial bindings seem to work fine. It just doesn't seem to know when Voiced changes for some reason...
public bool Voiced
{
get
{
return _Voiced;
}
set
{
_Voiced = value;
OnPropertyChanged("Voiced");
}
}
...
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
if (handler.Target is CollectionView)
{
((CollectionView)handler.Target).Refresh();
}
else
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
#endregion
你能post ViewModel 代码吗?
我假设您更新的是 Clan 属性 已更改但语音 属性 未更改。换句话说,有声需要是一个 属性,它自己 属性 改变了事件触发。
确保 Clan
class 实现了 INotifyPropertyChanged
接口并在有声 属性 的 setter 中引发了 PropertyChanged
事件].
由于您要绑定到 Clan.Voiced 属性,因此定义 Meilyr 和 ClanVoided 属性的视图模型 class 是否实现 INotifyPropertyChanged
并不重要接口。