更新Dependency属性中的属性不会在视图中显示

时间:2017-01-25 03:30:54

标签: c# wpf mvvm dependency-properties

我有一个名为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从false传递到视图中。

在视图中,我有一个数据触发器,它应该反映语音的变化。

<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浊音属性被更改为true,并且正在正确调用OnPropertyChanged。

我不知道为什么,当我在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中的Dependency属性:

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中的Voiced属性,以及OnPropertyChanged。

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

2 个答案:

答案 0 :(得分:1)

确保Clan类实现INotifyPropertyChanged接口,并在Voiced属性的setter中引发PropertyChanged事件。

由于您绑定了Clan.Voiced属性,因此定义Meilyr和ClanVoided属性的视图模型类是否实现INotifyPropertyChanged接口并不重要。

答案 1 :(得分:0)

请你发布ViewModel代码吗。

我假设您正在更新已更改的Clan属性,但未更改Voice属性。换句话说,声音需要是一个属性,它自己的属性改变了事件发生。