繁体   English   中英

实际未更改时如何触发属性更改事件

[英]How to fire Property Changed Event when it's not actually changing

所以我有一个模型,其中包含2个变量,一个List和一个DateTime。 在我的UserControl中,我具有DependencyProperty,并且还定义了PropertyChangedCallback。

public static readonly DependencyProperty MyProperty = DependencyProperty.Register("My", typeof(List<MyContainer>), typeof(UC), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnMyProperty)));

public List<MyContainer> My
{
    get
    {
        return GetValue(MyProperty) as List<MyContainer>;
    }
    set
    {
        SetValue(MyProperty, value);
    }
}
private static void OnMyProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    UC control = d as UC;
    //do stuff
}

在我的表单上有一个按钮,用于对另一个模型变量(在DateTime上)进行更改。

private void Date_Click(object sender, RoutedEventArgs e)
{
    MyModel model = DataContext as MyModel;
    if (model != null)
    {
        model.Date = model.Date.AddDays(1);
    }
}

最后是我的模型。

public class MyModel : INotifyPropertyChanged
{
    private List<MyContainer> _My;
    private DateTime _Date;

    public MyModel()
    {
        _Date = DateTime.Now.Date;
        _My = new List<MyContainer>();
    }

    public List<MyContainer> My
    {
        get
        {
            return _My;
        }
        set
        {
            _My = value;
            OnPropertyChanged("My");
        }
    }

    public DateTime Date
    {
        get
        {
            return _Date;
        }
        set
        {
            _Date = value;
            OnPropertyChanged("Date");
            OnPropertyChanged("My");
        }
    }

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

XAML声明如下。

<local:UC My="{Binding My}" />

所以我的问题是,在我点击运行后,它会触发一次OnMyProperty,然后如果我按下按钮,它将很好地更改DateTime属性,但是OnMyProperty回调不会再次触发。 但是我注意到如果我像这样修改我的模型

public DateTime Date
{
    get
    {
       return _Date;
    }
    set
    {
        _Date = value;
        _My = new List<MyContainer>(_My); //added
        OnPropertyChanged("Date");
        OnPropertyChanged("My");
    }
}

现在每次按下按钮时都会触发它。 如果不进行修改,如何触发第二种行为?

设置DependencyProperty的值后,它首先检查新值是否与旧值不同。 仅在这种情况下,才调用您在该DependencyProperty注册的PropertyChangedCallback方法。 因此,名称Property Changed很有意义。

在您(未修改)的情况下,您甚至都不会尝试更改My (仅Date )。 因此,没有理由提高回调函数。

答案是您几乎肯定不需要这样做。 当您询问有关如何使框架执行其确实不希望执行的操作的问题时,请始终说出为什么您认为需要执行此操作 很有可能其他人已经在使用一个更简单的答案。

您绑定到控件的唯一东西是My 因此,如果My尚未更改,则控件的状态不应更改。 如果你想控制的状态改变时, Date的变化,结合Date到控制的某些属性。 控件应该从任何视图模型获取信息的唯一方法是将其依赖项属性之一绑定到视图模型的属性。

该控件永远不应该知道或关心谁或什么为其属性提供值。 它仅应知道已赋予的属性值就能够执行其工作。

如果My的内容已更改-您添加了一个项目或删除了一个项目-则控件无法知道这一点,因为您拒绝告诉它。 您只是在告诉它有一个新列表。 它检查,发现它仍然有相同的旧列表,并忽略了您。 您的viewmodel的My属性应该是ObservableCollection ,因为当您添加或删除集合中的项目时,它将通知控件。

如果您想要在UI中显示项目时更改其属性,则项目本身(您的MyContainer类)也必须实现INofityPropertyChanged

您控件上的依赖项属性My的类型不能为List<T> 它可能应该是object类型,就像ItemsControl.ItemsSource一样。 然后,您的控件模板可以在知道如何使用它的ItemsControl显示它。 如果如上所述将ObservableCollection绑定到它,则ItemsControl将自动更新。 OnMyProperty ,您的控件类还可以检查它是否也是可观察的集合:

private static void OnMyProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    UC control = d as UC;

    if (e.NewValue is INotifyCollectionChanged)
    {
        (e.NewValue as INotifyCollectionChanged).CollectionChanged +=
            (s, ecc) => {
                //  Do stuff with UC and ecc.NewItems, ecc.OldItems, etc.
            };
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM