UserControl DependencyProperty propertyChangedCallback未调用

时间:2018-07-18 03:37:56

标签: wpf xaml mvvm

因此我在xaml中设置了一个ItemsControl,例如:

<ItemsControl ItemsSource="{Binding Items}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal" />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <local:ToggleButton Command="{Binding DataContext.ItemSelectedCommand, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type WrapPanel}}}" 
                                    CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}}" 
                                    Text="{Binding DataContext.ItemEnum, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}, Converter={StaticResource EnumToStringConverter}}" 
                                    IsActive="{Binding DataContext.Selected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}, UpdateSourceTrigger=PropertyChanged}"
                                    Width="96" 
                                    Height="88" 
                                    Margin="5" />
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

我有4个依赖项属性CommandCommandParameterTextIsActive。 前三个依赖项属性正常工作,设置了文本,命令回调与参数一起工作。

IsActive属性不起作用。 主视图模型中的Items属性定义为:

List<ItemViewModel> Items { get; set; }

ItemViewModel定义为:

public class ItemViewModel : INotifyPropertyChanged
{
    public ItemViewModel()
    {
        this.Selected = true;
    }

    private bool? _selected;

    public event PropertyChangedEventHandler PropertyChanged;

    public ItemEnum ItemEnum { get; set; }

    public bool? Selected
    {
        get { return this._selected; }

        set
        {
            this._selected = value;
            this.OnPropertyChanged(nameof(this.Selected));
        }
    }

    protected virtual void OnPropertyChanged(string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

ToggleButton.xaml.cs文件中IsActive属性的依赖项属性如下:

public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register(nameof(IsActive), typeof(bool?), typeof(ToggleButton), new PropertyMetadata(null, IsActiveSetCallback));

private static void IsActiveSetCallback(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var button = (ToggleButton)obj;

    button.IsActive = (bool)(e.NewValue ?? e.OldValue);0xa5, 0xa5));
}

我在主视图模型中的命令回调如下:

this.ItemSelectedCommand = 
      new DelegateCommand(
          itemVm =>
          {
               bool? setTo = !((ItemViewModel) itemVm).Selected;
               this.Items.ForEach(i => i.Selected = false);
               ((ItemViewModel) itemVm).Selected = setTo;
          });

同样,其他依赖项属性(定义与IsActiveProperty基本相同)也正常工作,因此,当我单击该项目时,上述命令被调用(由断点验证),该项目的Selected标志被正确切换,但是IsActiveSetCallback永远不会被击中。我看不到我在做什么错,但是很明显这是什么。

有人看到我没看到的东西吗?

谢谢!

1 个答案:

答案 0 :(得分:-1)

花了太多时间尝试解决这个问题后,我当然会在发布此问题后半小时内自己解决问题。

我从Microsoft DependencyProperty文档(特别是有关“依赖项属性设置优先级列表”的部分)中提取了此信息:

  

本地值。可以通过“包装器”属性的便利性来设置局部值,该属性还等同于在XAML中设置为属性或属性元素,或者通过使用特定实例的属性来调用SetValue API。如果您通过使用绑定或资源来设置本地值,则这些值将像设置直接值一样优先工作。

因此,我在ToggleButton.xaml.cs中的两个位置设置了this.Active,一次是在构造函数中将其设置为默认值,一次是在IsActiveSetCallback ..这样做的结果是,我覆盖了绑定,无论如何都不需要这些调用。很简单!