事件,使用这些事件的方法和继承

本文关键字:事件 方法 继承 | 更新日期: 2023-09-27 18:08:03

我正在创建一个用WPF开发的软件的程序端体系结构,我设计的体系结构符合MVVM模式。

出于多种原因(设计、一致性、可重用性、可维护性、可伸缩性等),我创建了类BaseViewModel,实现了接口INotifyPropertyChanged和其他一些方法:

public class BaseViewModel: INotifyPropertyChanged
{
    private PropertyChangedEventHandler property_changed;
    public event PropertyChangedEventHandler PropertyChanged
    {
        add { property_changed += value; }
        remove { property_changed -= value; }
    }
    //Here several methods using PropertyChanged and easing the usage of ViewModels
    public BaseViewModel() { }
}

上面定义的类BaseViewModel用作应用程序中所有其他ViewModel的基类(或者,至少,打算这样做),例如:

public class SampleViewModel : BaseViewModel
{
    //private PropertyChangedEventHandler property_changed;
    //public event PropertyChangedEventHandler PropertyChanged
    //{
    //    add { property_changed += value; }
    //    remove { property_changed -= value; }
    //}
    public String Name
    {
        get { return name; }
        set
        {
            if(value != name)
            {
                 name = value;
                 var handler = PropertyChanged;
                 if(handler != null)
                 {
                    handler(this, new PropertyChangedEventArgs("Name"));
                 }
            }
        }
    }
    private String name = "";
    public SampleViewModel ()
        : base() { }
}

我使用类SampleViewModel作为SampleUserControlDataContext,它具有DependencyProperty:

public partial class SampleUserControl : UserControl
{
    #region ViewModel
    public SampleViewModel ViewModel
    {
        get { return view_model; }
    }
    private SampleViewModel view_model = new SampleViewModel();
    #endregion
    #region DependencyProperty
    public String Text
    {
        get { return (String)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }
    public static readonly DependencyProperty TextProperty =
        DependencyProperty.Register("Text", typeof(String), typeof(SampleUserControl),
                new FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.AffectsRender,
                        new PropertyChangedCallback(TextPropertyChangedCallback)));
    private static void TextPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        SampleUserControl sender = d as SampleUserControl;
        if (sender != null)
        {
            sender.ViewModel.Name = (String)e.NewValue;
        }
    }
    #endregion
    public SampleUserControl()
    {
        InitializeComponent();
        LayoutRoot.DataContext = ViewModel;
        ViewModel.PropertyChanged += new PropertyChangedEventHandler(ViewModel_PropertyChanged);
    }
    void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        SampleViewModel viewmodel = sender as SampleViewModel;
        if (viewmodel != null)
        {
            switch (e.PropertyName)
            {
                case "Name":
                    SetValue(TextProperty, viewmodel.Name);
                    break;
                default:
                    break;
            }
        }
    }
}

综上所述,与SampleUserControl相关的数据包含在三个位置:SampleViewModel的实例、TextPropertySampleUserControl的xaml部分中TextBox的属性Text(该属性Text通过BindingViewModel的字段Name双向绑定)。

为了同步这三个值,我添加了TextPropertyChangedCallbackViewModel_PropertyChanged方法,它们更新需要更新的字段。

上面的代码可以工作,并且上面提到的三个位置保持最新,事件触发等等,当SampleUsercontrol与数据绑定一起使用时,一切都很好。

但是SampleViewModel触发事件BaseViewModel.PropertyChanged,并且由于BaseViewModel意味着被广泛使用,我希望每个ViewModel都有自己的事件PropertyChanged,至少为了避免重叠事件。

所以我取消了SampleViewModel的注释,从而重新定义了事件PropertyChanged,但是它破坏了SampleViewModel实例的字段NameSampleUserControl的属性TextProperty之间的同步。

我是否在构思方面犯了一些错误?你能给我一些指导吗?为继承BaseViewModel的每个ViewModel定义不同的事件PropertyChanged,同时仍然使用该基类中定义的通用方法(此类方法使用PropertyChanged)的最佳经济方法是什么?(我希望避免有大量的代码需要复制粘贴。)

我知道这更多的是关于优化,但是这样的优化可以使一个慢的软件和一个快的软件之间的差异。我正处于代码分解的阶段,所以我喜欢形状漂亮、优雅、分解的代码。

一天结束了,我可能会错过一些明显的解决方案。

提前感谢任何线索,朱利安

事件,使用这些事件的方法和继承

TL;DR:基本上,我会仔细检查您是否正确地在用户控件上执行DC/DP,并抛弃任何PropertyChanged多重定义的概念

在细节:

  1. 您在基类中定义了PropertyChanged,这很棒。没有理由在 else的任何地方重新定义它。真的,你这样做是在自找麻烦。
  2. 与此相关的是,你应该真的只是做一个方法来做事件调用,而不是在setter中做整个handler位。复制粘贴的还原。
  3. 事实上,你不得不使用TextPropertyChanged是一个巨大的危险信号。这涉及到真正的问题,你可能正在滥用你的依赖属性。dp用于允许控件绑定到用户控件的属性。通常不会将它们与控件内部的数据上下文结合使用,因为正如您所看到的,保持它们同步是一场噩梦。
  4. 一般来说,如果用户控件被设置为与任何其他控件(即子视图)分开,则用户控件应该只有自己的数据上下文。如果它们只是一个花哨的控件,那么给它们一个视图模型很少给你任何东西。