繁体   English   中英

如何通过Presenter中的界面将我的View按钮数据绑定到Model

[英]How to data-bind my View's button to the Model, via its interface in the Presenter

为冗长的代码道歉,这就像我能得到它一样浓缩。 下面是一个人为的例子,后面有一个解释:

namespace Contrived.Example
{
    internal class Model : INotifyPropertyChanged
    {
        private bool _isAccountEmpty;

        public bool IsAccountEmpty
        {
            get { return _isAccountEmpty; }
            set
            {
                if (_isAccountEmpty == value) return;
                _isAccountEmpty = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

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

    internal interface IView
    {
        event EventHandler WithdrawalButtonClick;
    }

    internal class View : IView
    {
        private Button WithdrawalButton;
        private void InitializeComponent()
        {
            WithdrawalButton = new Button();
            WithdrawalButton.Location = new System.Drawing.Point(0, 0);
            WithdrawalButton.Size = new System.Drawing.Size(75, 25);
            WithdrawalButton.Click += WithdrawalButton_Click;
        }

        private void WithdrawalButton_Click(object sender, EventArgs e)
        {
            WithdrawalButtonClick?.Invoke(sender, e);
        }

        public event EventHandler WithdrawalButtonClick;
    }

    internal class Presenter
    {
        private readonly IView _view;
        private readonly Model _model;
        //private readonly BindingSource bindSource;


        public Presenter(IView view)
        {
            _view = view;
            _model = new Model();
            view.WithdrawalButtonClick += OnWithDrawalButtonClick;

            /* The behavior that follows is what I am after: 
             * how do I bind my button control to its model counterpart here? 
             * You can't expose the control directly on the IView interface, can you?
             * 
             * bindSource = new BindingSource {DataSource = typeof(Model)};
             * bindSource.Add(_model);
             * 
             * This next line would throw an exception because 
             * _view isn't actually exposing the button:
             * _view.WithdrawalButton
             *     .DataBindings
             *     .Add("Enabled", bindSource, "IsAccountEmpty");
             */
        }

        private void OnWithDrawalButtonClick(object sender, EventArgs e)
        {
            // Pretend we withdrew too much money
            _model.IsAccountEmpty = true;
        }
    }
}

所以这基本上是我的程序的结构。 我想通过演示者将我的视图按钮绑定到其模型上的属性。 注释代码在没有界面的情况下对我很好,并且 vb.Net中(控件具有Friend修饰符而不是Private,因此它们对于演示者是可见的)。

现在在C#中按钮是私有的,此外我试图通过将一个接口抛入混合来练习松耦合。 现在我遇到了一个问题,我不能再按照以前的方式将我的按钮绑定到模型了。 任何人都可以告诉我解决这个问题的正确方法是什么? 非常感谢。

PS如果这个设置完全错误,我想也知道,这是我能够自己想出的最好的,没有在学校对这个主题进行任何真正的集中培训。

首先让我告诉你,你的构造并不是完全松耦合的。 如果您查看Presenter,可以找到以下行:

_model = new Model();

如果你想创建松散耦合的程序,可以将新关键字视为邪恶。 因为在这里你被绑定到模型。 不是任何模型,而是完全属于那个模型。 如果你想要UnitTest你的Presenter你将无法模拟一个模型。 所以你应该更好地创建一个进一步的接口IModel并在构造函数中传递它。

public Presenter(IView view, IModel model)
{
   this.model = model;
   this.view = view;
}

要了解更多关于为什么要这样做以及如何处理这个问题的信息,请阅读...... 关于DependencyInjection 完成此步骤后,您可以传递适合您的界面的任何模型。

在此之后我应该回答你的问题;-)。 首先,您可以创建一个处理DataBinding功能的新接口。 然后创建一个新的Button,它可以从Standardbutton开始,并实现新的Interface。 然后你的IView包含一个Property,它包含一个IBindingObject或者你的新接口被调用的任何东西。 这看起来像这样:

    public interface IBindingObject
    {
       ControlBindingsCollection DataBinding {get;}   
    }

    public class MyButton : Button, IBindingObject
    {
       //Nothing to do here because the Button contains a DataBinding Property by default
    }

    public interface IView
    {
       IBindingObject WithdrawalButton {get;}
    }

    public class View : Form, IView
    {
      public IBindingObject WithdrawalButton {get {return new MyButton()}}
    }    

    public class Presenter
    {
        public Presenter(IView view, IModel model)
        {
           view.WithdrawalButton.DataBindings.Add(//do your binding);
        }
    }

注意这种方法与ControlBindingCollection耦合,但我认为这种妥协是可以的。 否则你总是必须让你的View访问你的模型,反之亦然。 这会违反模式。 DataBinding和Winforms并不像WPF那样舒服。 所以,如果你有机会使用WPF我会建议。

暂无
暂无

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

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