简体   繁体   English

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

[英]Events, methods using these events and inheritance

I am creating the program-side architecture of a software developped in WPF, I designed the architecture as being compliant with the MVVM pattern. 我正在创建使用WPF开发的软件的程序端体系结构,并且将该体系结构设计为符合MVVM模式。

For many sakes (design, coherence, reusability, maintainability, scalability, etc) I created the class BaseViewModel implementing the interface INotifyPropertyChanged and some other methods: 出于许多原因(设计,一致性,可重用性,可维护性,可伸缩性等),我创建了实现接口INotifyPropertyChanged和其他方法的BaseViewModel类:

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() { }
}

The above-defined class BaseViewModel is used as a base class for all the other ViewModel s of the application (or, at least, is meant to be so), for example: 上面定义的类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() { }
}

I use the class SampleViewModel as the DataContext of SampleUserControl which bares a DependencyProperty : 我使用类SampleViewModel作为SampleViewModelDataContext ,它SampleUserControlDependencyProperty

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;
            }
        }
    }
}

To sum up, the data relative to SampleUserControl are contained at three locations : the instance of SampleViewModel , within TextProperty and within the property Text of a TextBox in the xaml part of SampleUserControl (this property Text is twoway-bound through Binding with the field Name of ViewModel ). 总而言之,与SampleUserControl有关的数据包含在三个位置: SampleViewModel的实例,位于TextProperty和位于SampleUserControl的xaml部分中的TextBox属性Text中(此属性Text是通过Binding与字段Name双向Binding的)的ViewModel )。

To synchronize the three values, I added the methods TextPropertyChangedCallback and ViewModel_PropertyChanged which update the fields which need to be updated. 为了同步这三个值,我添加了TextPropertyChangedCallbackViewModel_PropertyChanged方法,它们更新了需要更新的字段。

The above code works and the three above-mentionned locations are kept up-to-date, events fire and so on, things are fine when SampleUsercontrol is consumed with data-binding. 上面的代码可以正常工作,并且上面提到的三个位置都保持最新,事件发生等,当使用SampleUsercontrol进行数据绑定时,一切都很好。

But SampleViewModel fires the event BaseViewModel.PropertyChanged , and since BaseViewModel is meant to be extensively used, I would like each ViewModel to have its own event PropertyChanged , at least in order to avoid overlapping events. 但是SampleViewModel会触发事件BaseViewModel.PropertyChanged ,并且由于打算广泛使用BaseViewModel ,因此我希望每个ViewModel都有自己的事件PropertyChanged ,至少是为了避免事件重叠。

So I uncomment the code of SampleViewModel thus redefining the event PropertyChanged but it breaks down the synchronization between the field Name of the instance of SampleViewModel and the property TextProperty of SampleUserControl . 所以我取消的代码SampleViewModel从而重新定义了事件PropertyChanged ,但它打破了该领域之间的同步Name的实例SampleViewModel和财产TextPropertySampleUserControl

Am I making some mistakes on the conception side? 我在构思方面犯了一些错误吗? Do you have any guidance for me? 您对我有什么指导吗? What is the best economic way of defining a different event PropertyChanged for each ViewModel inheriting from BaseViewModel while still using the general-purpose methods defined within that base class (such methods use PropertyChanged )? 为每个继承自BaseViewModel ViewModel定义不同事件PropertyChanged的最佳经济方法是什么,同时仍使用该基类中定义的通用方法(此类方法使用PropertyChanged )? (I would like to avoid having heavy pieces of code to copy-paste.) (我想避免要粘贴大量代码。)

I know that it is more about optimization, but such optimizations can make a difference between a slow software and a fast one. 我知道更多的是关于优化的,但是这种优化可以在速度较慢的软件和速度较快的软件之间产生区别。 I am at the stage of code-factoring, so I fancy nicely-shaped, elegant and factorized code. 我处于代码分解的阶段,因此我喜欢形状优美,优雅且分解的代码。

End of the day happening, I may miss some obvious solutions. 一天结束了,我可能会错过一些明显的解决方案。

Thanks in advance for any clue, Julien 预先感谢您提供任何线索,朱利安

TL;DR: Basically, I would double-check that you are doing your DC/DP on that user control correctly, and toss out any concept of multiple definitions of PropertyChanged TL; DR:基本上,我会仔细检查您是否在该用户控件上正确执行了DC / DP,并抛出了PropertyChanged多个定义的任何概念

In detail: 详细:

  1. You defined PropertyChanged in the base class, which is great. 您在基类中定义了PropertyChanged ,这很棒。 There is no reason to ever redefine it anywhere else . 没有理由其他任何地方重新定义它 Really, you are just asking for trouble by doing this. 确实,您只是在通过这样做自找麻烦。
  2. Related to that, you should really just make a method to do the event invocation rather than doing the whole handler bit in the settter. 与此相关的是,您实际上应该仅创建一种方法来执行事件调用,而不要执行setter中的整个handler Insta-reduction of copy paste. 减少复制粘贴。
  3. The fact that you are having to use TextPropertyChanged is a huge red flag here. 您必须使用TextPropertyChanged的事实在这里是一个巨大的 TextPropertyChanged信号。 Which relates to the real problem, that you are probably abusing your dependency property. 与真正的问题有关,您可能正在滥用依赖项属性。 DPs are used to allow parent controls to bind to a property of your user control. DP用于允许控件绑定到用户控件的属性。 You typically won't use them in conjunction with a data context internal to the control because, as you have seen, keeping them in sync is a nightmare. 通常,您不会将它们与控件内部的数据上下文一起使用,因为如您所见,保持它们同步是一场噩梦。
  4. In general, user controls should only have their own data context if they are set up to stand apart from any other control (ie, a sub-view). 通常,如果将用户控件设置为与任何其他控件(例如,子视图)区分开,则它们仅应具有自己的数据上下文。 If they are just a fancy control, then giving them a view model rarely gets you anything. 如果它们只是一个花哨的控件,那么给他们一个视图模型几乎不会给您任何帮助。

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

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