简体   繁体   English

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

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

so I have a model which contains 2 variables, a List and a DateTime. 所以我有一个模型,其中包含2个变量,一个List和一个DateTime。 In my UserControl I have a DependencyProperty and I also defined a PropertyChangedCallback. 在我的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
}

On my form there is a button, which do the changes on the other model variable (on the DateTime). 在我的表单上有一个按钮,用于对另一个模型变量(在DateTime上)进行更改。

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

And finally here is my model. 最后是我的模型。

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 declaration is the following. XAML声明如下。

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

So my problem is the after I hit the run, it fires the OnMyProperty once, after that if I hit the button, it changes the DateTime property well, but the OnMyProperty callback doesn't firing again. 所以我的问题是,在我点击运行后,它会触发一次OnMyProperty,然后如果我按下按钮,它将很好地更改DateTime属性,但是OnMyProperty回调不会再次触发。 However I noticed that if I modify my model like this 但是我注意到如果我像这样修改我的模型

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

now it fires it every time when I hit the button. 现在每次按下按钮时都会触发它。 How can I trigger the second behaviour without that modification? 如果不进行修改,如何触发第二种行为?

After setting the value of a DependencyProperty it first checks if the new value is different to the old one. 设置DependencyProperty的值后,它首先检查新值是否与旧值不同。 Only in this case the PropertyChangedCallback method you registered with that DependencyProperty is called. 仅在这种情况下,才调用您在该DependencyProperty注册的PropertyChangedCallback方法。 So the name Property Changed makes sense. 因此,名称Property Changed很有意义。

In your (not modified) case you not even try to change My (only Date ). 在您(未修改)的情况下,您甚至都不会尝试更改My (仅Date )。 So there is no reason to raise the callback function. 因此,没有理由提高回调函数。

The answer is that you almost certainly do not need to do this. 答案是您几乎肯定不需要这样做。 When you ask a question about how to make the framework do something it really does not want to do, always say why you think you need to do that . 当您询问有关如何使框架执行其确实不希望执行的操作的问题时,请始终说出为什么您认为需要执行此操作 It's very likely that there's a much easier answer that everybody else is already using. 很有可能其他人已经在使用一个更简单的答案。

The only thing you have bound to the control is My . 您绑定到控件的唯一东西是My Therefore, if My hasn't changed, then the state of the control should not change. 因此,如果My尚未更改,则控件的状态不应更改。 If you want the state of the control to change when Date changes, bind Date to some property of the control. 如果你想控制的状态改变时, Date的变化,结合Date到控制的某些属性。 The only way the control should ever get information from any viewmodel is through binding one of its dependency properties to a property of the viewmodel. 控件应该从任何视图模型获取信息的唯一方法是将其依赖项属性之一绑定到视图模型的属性。

The control should not ever know or care who or what is providing values for its properties. 该控件永远不应该知道或关心谁或什么为其属性提供值。 It should be able to do its job knowing only the property values it has been given. 它仅应知道已赋予的属性值就能够执行其工作。

If the contents of My have changed -- you added an item or removed one -- of course the control has no way of knowing that, because you refused to tell it. 如果My的内容已更改-您添加了一个项目或删除了一个项目-则控件无法知道这一点,因为您拒绝告诉它。 You're just telling it there's a new list. 您只是在告诉它有一个新列表。 It checks, sees it's still got the same old list, and ignores you. 它检查,发现它仍然有相同的旧列表,并忽略了您。 The My property of your viewmodel should be an ObservableCollection , because that will notify the control when you add or remove items in the collection. 您的viewmodel的My属性应该是ObservableCollection ,因为当您添加或删除集合中的项目时,它将通知控件。

The items themselves, your MyContainer class, must implement INofityPropertyChanged as well, if you want to be able to change their properties while they are displayed in the UI. 如果您想要在UI中显示项目时更改其属性,则项目本身(您的MyContainer类)也必须实现INofityPropertyChanged

The dependency property My on your control must not be of type List<T> . 您控件上的依赖项属性My的类型不能为List<T> It should probably be type object , just like ItemsControl.ItemsSource . 它可能应该是object类型,就像ItemsControl.ItemsSource一样。 Then your control template can display it in an ItemsControl which knows what to do with it. 然后,您的控件模板可以在知道如何使用它的ItemsControl显示它。 If an ObservableCollection is bound to it as I suggested above, the ItemsControl will update automatically. 如果如上所述将ObservableCollection绑定到它,则ItemsControl将自动更新。 In OnMyProperty , your control class can check to see if it's an observable collection as well: 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