zoukankan      html  css  js  c++  java
  • Devexpress Winform MVVM

    归纳总结备忘

    (Devexpress Winform MVVM Practice)

     我自己的使用

    前言

    MVVM

           MVVM是Model-View-ViewModel,是一种专为WPF开发而设计的架构设计模式,类似MVC。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。 ViewModel 根据databindings,commond,notification等与view层连接,可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑,充当视图层与数据层的通信桥梁。
    在这里插入图片描述
    好处:

    • 逻辑低耦合
    • 可重用性
    • 方便单元测试

    Devexpress

           DevExpress全称Developer Express,是全球著名的控件开发公司,其.NET界面控件DXperience Universal Suite(Dev宇宙版)全球知名,获奖无数。DevExpress控件以界面美观和功能强大著称,拥有大量的示例和帮助文档,开发者能够快速上手。在国内,DevExpress亦拥有大量的用户,资料比较完善,交流方便。DevExpress广泛应用于ECM企业内容管理、 成本管控、进程监督、生产调度,在企业/政务信息化管理中占据一席重要之地。

    官网:https://www.devexpress.com/

           如上所说,mvvm专为WPF设计,而没有第三方MVVM框架的 winform平台缺乏灵活的绑定以及绑定commad等基本特性,必须手动实现,而devexpress为这些特性提供了完整支持,是开发更关心本身业务逻辑。

    正文

    databindings及 UI Triggers

    在devexpress中viewModel所有的 virtual 属性都将是可绑定的,在更改值时会自动传递PropertyChanged消息(在未有devexpress的winform程序类必须继承 INotifyPropertyChanged并实现该接口才能实现双向绑定),当没有virtual属性时,只有主动调用 this.RaisePropertyChanged(x => x.你的属性)才会向视图层传递PropertyChanged消息。
    下面例子:
    viewmodel

    public class ViewModel {
    
    		public  virtual  string Test {get;private set ; }//标准
    		
    		[Bindable(false)]
    		public  virtual  string Test1 {get; private set ; }  //取消 bindable property generation支持
    		
    		string testCore;
    		[BindableProperty]  //带backing  field的属性将被忽略,使用该显示标记以使该属性支持databinding
    		public virtual string Test2
    		{
    		    get { return testCore; }
    		    set { testCore = value; }
    		}
    }
     

    view层

        TextEdit editor = new TextEdit();
        editor.Parent = this;
     	mvvmContext.ViewModelType = typeof(ViewModel);
        // Data binding for the Title property (via MVVMContext API)
        var fluentAPI = mvvmContext.OfType<ViewModel>();//支持 fluentAPI特性
        fluentAPI.SetBinding(editor, e => e.EditValue, x => x.Test);//双向绑定
         fluentAPI.SetTrigger(x => x.Test, (active) =>
        {
            label.Text = active;  //UI Triggers 单向绑定
        });
     

     

    Command

    委托Command

    		MVVMContext mvvmContext = new MVVMContext();
       		mvvmContext.ContainerControl = this;
    		SimpleButton commandButton = new SimpleButton();
    		commandButton.Parent = this;
    		Func<int, bool> canExecute = (p) => (2 + 2 == p);
                // This command is created as parameterized and with `canExecute` parameter.
            DelegateCommand<int> command = new DelegateCommand<int>((v) => {
                    XtraMessageBox.Show(string.Format(
                        "Hello! The parameter passed to command is {0}." + Environment.NewLine +
                        "And I'm running, because the `canExecute` condition is `True` for this parameter." + Environment.NewLine +
                        "Try to change this parameter!", v));
                }, canExecute);
                //
                int parameter = 4;
                // UI binding for button with the `queryParameter` function
                commandButton.BindCommand(command, () => parameter);
     

     

    POCO Commands

    viewmodel

           public class ViewModelWithParametrizedConditionalCommand { //viewmodel
                // A parameterized POCO-command will be created from this method.
                public void DoSomething(int p) {
                    XtraMessageBox.Show(string.Format(
                        "Hello! The parameter passed to command is {0}." + Environment.NewLine +
                        "And I'm running, because the `canExecute` condition is `True` for this parameter." + Environment.NewLine +
                        "Try to change this parameter!", p));
                }
                // A parameterized `CanExecute` method for the `Say` command.
                public bool CanDoSomething(int p) {
                    return (2 + 2) == p;  //自行修改条件
                }
            }
     

    view

     	MVVMContext mvvmContext = new MVVMContext();
         mvvmContext.ContainerControl = this;
      
          SimpleButton commandButton = new SimpleButton();
          commandButton.Text = "Execute Command";
          commandButton.Dock = DockStyle.Top;
          commandButton.Parent = this;
          mvvmContext.ViewModelType = typeof(ViewModelWithParametrizedConditionalCommand);
          //
          int parameter = 4;
          // UI binding for button with the `queryParameter` function
          var fluentAPI = mvvmContext.OfType<ViewModelWithParametrizedConditionalCommand>();
          fluentAPI.BindCommand(commandButton, (x, p) => x.DoSomething(p), x => parameter);
     

    异步command

    两个按钮控制进度条滚动开始停止
    viewmodel

        public class ViewModelWithAsyncCommandAndCancellation {
                // An asynchronous POCO-command will be created from this method.
                public Task DoSomethingAsynchronously() {
                    return Task.Factory.StartNew(() => {
                        var asyncCommand = this.GetAsyncCommand(x => x.DoSomethingAsynchronously());
                        for (int i = 0; i <= 100; i++) {
                            if (asyncCommand.IsCancellationRequested) // cancellation check
                                break;
                            System.Threading.Thread.Sleep(25); // do some work here
                            UpdateProgressOnUIThread(i);
                        }
                        UpdateProgressOnUIThread(0);
                    });
                }
                // Property for progress
                public int Progress { get; private set; }
                protected IDispatcherService DispatcherService {
                    get { return this.GetService<IDispatcherService>(); }
                }
                void UpdateProgressOnUIThread(int progress) {
                    DispatcherService.BeginInvoke(() => {
                        Progress = progress;
                        this.RaisePropertyChanged(x => x.Progress);
                    });
                }
            }
     

    view

    			 MVVMContext mvvmContext = new MVVMContext();
                mvvmContext.ContainerControl = this;
            
                ProgressBarControl progressBar = new ProgressBarControl();
                progressBar.Dock = DockStyle.Top;
            
                SimpleButton commandButton = new SimpleButton();
                commandButton.Text = "Start Command Execution";
                commandButton.Dock = DockStyle.Top;
            
                SimpleButton cancelButton = new SimpleButton();
                cancelButton.Text = "Cancel Command Execution";
                cancelButton.Dock = DockStyle.Top;
            
                cancelButton.Parent = this;
                commandButton.Parent = this;
                progressBar.Parent = this;
    
                mvvmContext.ViewModelType = typeof(ViewModelWithAsyncCommandAndCancellation);
                var fluentAPI = mvvmContext.OfType<ViewModelWithAsyncCommandAndCancellation>();
                // UI binding for the button
                fluentAPI.BindCommand(commandButton, x => x.DoSomethingAsynchronously());
                // UI binding for cancelation
                fluentAPI.BindCancelCommand(cancelButton, x => x.DoSomethingAsynchronously());
                // UI binding for progress
                fluentAPI.SetBinding(progressBar, p => p.EditValue, x => x.Progress);
     

    WithCommand extension

    四种常见使用情况

    viewmodel

        public class ViewModelWithAsyncCommandAndCancellation {
                // An asynchronous POCO-command will be created from this method.
                public Task DoSomethingAsynchronously() {
                    return Task.Factory.StartNew(() => {
                        var asyncCommand = this.GetAsyncCommand(x => x.DoSomethingAsynchronously());
                        for (int i = 0; i <= 100; i++) {
                            if (asyncCommand.IsCancellationRequested) // cancellation check
                                break;
                            System.Threading.Thread.Sleep(25); // do some work here
                            UpdateProgressOnUIThread(i);
                        }
                        UpdateProgressOnUIThread(0);
                    });
                }
                // Property for progress
                public int Progress { get; private set; }
                protected IDispatcherService DispatcherService {
                    get { return this.GetService<IDispatcherService>(); }
                }
                void UpdateProgressOnUIThread(int progress) {
                    DispatcherService.BeginInvoke(() => {
                        Progress = progress;
                        this.RaisePropertyChanged(x => x.Progress);
                    });
                }
            }
     

    view

     			MVVMContext mvvmContext = new MVVMContext();
                mvvmContext.ContainerControl = this;
            
                ProgressBarControl progressBar = new ProgressBarControl();
                progressBar.Dock = DockStyle.Top;
                 
                 SimpleButton commandButton2 = new SimpleButton();
                commandButton2.Text = "Execute Command 2";
                commandButton2.Dock = DockStyle.Top;
                commandButton2.Parent = this;
                commandButton2.Visible = false;
            
                SimpleButton commandButton1 = new SimpleButton();
                commandButton1.Text = "Execute Command 1";
                commandButton1.Dock = DockStyle.Top;
                commandButton1.Parent = this;
            
                SimpleButton commandButton = new SimpleButton();
                commandButton.Text = "Start Command Execution";
                commandButton.Dock = DockStyle.Top;
            
                SimpleButton cancelButton = new SimpleButton();
                cancelButton.Text = "Cancel Command Execution";
                cancelButton.Dock = DockStyle.Top;
            
                cancelButton.Parent = this;
                commandButton.Parent = this;
                progressBar.Parent = this;
    
                mvvmContext.ViewModelType = typeof(ViewModelWithAsyncCommandAndCancellation);
                var fluentAPI = mvvmContext.OfType<ViewModelWithAsyncCommandAndCancellation>();
                // UI binding for buttons
                fluentAPI.WithCommand(x => x.DoSomethingAsynchronously())  //功能如上一例子
                    .Bind(commandButton)
                    .BindCancel(cancelButton);
    
    		    fluentAPI.WithCommand(x => x.DoSomething())  //多控件绑定一command
    		        .Bind(commandButton1)
    		        .Bind(commandButton2);
    		   fluentAPI.WithCommand(x => x.DoSomething()) //单绑定
           			 .Bind(commandButton1);
    		  fluentAPI.WithCommand(x => x.DoSomething())//OnCanExecuteChanged,Before,After  三种command triggers
    		        .OnCanExecuteChanged(() => XtraMessageBox.Show("The CanExecute condition has changed"));
    			//	 .Before(() => XtraMessageBox.Show("The target command is about to be executed"));
    		//		.After(() => XtraMessageBox.Show("The target command has been executed"));
    
                // UI binding for progress
                fluentAPI.SetBinding(progressBar, p => p.EditValue, x => x.Progress);
     

    Attaching Behaviors

    Confirmation behavior.

    checkBox修改的再确认
    view

                MVVMContext mvvmContext = new MVVMContext();
                mvvmContext.ContainerControl = this;
            
                CheckEdit editor = new CheckEdit();
                editor.Dock = DockStyle.Top;
                editor.Text = "Please, try to change checked state of this editor";
                editor.Parent = this;
            
                #endregion SetUp
    
                #region #confirmationBehaviorFluentAPI
                // UI binding for the generic ConfirmationBehavior behavior with some specific parameters
                mvvmContext.WithEvent<ChangingEventArgs>(editor, "EditValueChanging")
                    .Confirmation(behavior =>
                    {
                        behavior.Caption = "CheckEdit State changing";
                        behavior.Text = "This checkEdit's checked-state is about to be changed. Are you sure?";
                    });
     

    Event To Command.

    事件转命令,效果与POCO Commands例子一致
    viewmodel

           public class ViewModelWithParametrizedConditionalCommand { //viewmodel
                // A parameterized POCO-command will be created from this method.
                public void DoSomething(int p) {
                    XtraMessageBox.Show(string.Format(
                        "Hello! The parameter passed to command is {0}." + Environment.NewLine +
                        "And I'm running, because the `canExecute` condition is `True` for this parameter." + Environment.NewLine +
                        "Try to change this parameter!", p));
                }
                // A parameterized `CanExecute` method for the `Say` command.
                public bool CanDoSomething(int p) {
                    return (2 + 2) == p;  //自行修改条件
                }
            }
     

    view

     	MVVMContext mvvmContext = new MVVMContext();
         mvvmContext.ContainerControl = this;
      
          SimpleButton commandButton = new SimpleButton();
          commandButton.Text = "Execute Command";
          commandButton.Dock = DockStyle.Top;
          commandButton.Parent = this;
          mvvmContext.ViewModelType = typeof(ViewModelWithParametrizedConditionalCommand);
          //
          int parameter = 4;
          // UI binding for button with the `queryParameter` function
          var fluentAPI = mvvmContext.OfType<ViewModelWithParametrizedConditionalCommand>();
    		fluentAPI.WithEvent(commandButton, "Click")
    		               .EventToCommand((x) => x.DoSomething(new int()), x => parameter);
     

    Key(s)-To-Command

    按键转命令
    viewModel

     public class KeyAwareViewModel {
                protected IMessageBoxService MessageBoxService {
                    get { return this.GetService<IMessageBoxService>(); }
                }
                public void OnAKey() {
                    MessageBoxService.ShowMessage("Key Command: A");
                }
                public void OnAltAKey() {
                    MessageBoxService.ShowMessage("Key Command: Alt+A");
                }
                public void OnKey(Keys keys) {
                    MessageBoxService.ShowMessage("Key Command: " + keys.ToString());
                }
                public void OnKeyArgs(KeyEventArgs args) {
                    string message = string.Join(", ",
                        "KeyValue: " + args.KeyValue.ToString(),
                        "KeyData: " + args.KeyData.ToString(),
                        "KeyCode: " + args.KeyCode.ToString(),
                        "Modifiers: " + args.Modifiers.ToString());
                    MessageBoxService.ShowMessage("Args = {" + message + "}");
                }
            }
     

    view

                MVVMContext mvvmContext = new MVVMContext();
                mvvmContext.ContainerControl = this;
            
                UserControl panel = new UserControl();
                panel.Dock = DockStyle.Top;
                panel.Parent = this;
            
                MemoEdit memo = new MemoEdit();
                memo.Dock = DockStyle.Fill;
                memo.ReadOnly = true;
                memo.MinimumSize = new Size(0, 100);
                memo.Parent = panel;
    
                memo.Text = "Click here and press the A or Alt+A keys to execute a command";
                //
                mvvmContext.ViewModelType = typeof(KeyAwareViewModel);
                // UI binding for the KeyToCommand behavior
                mvvmContext.OfType<KeyAwareViewModel>()
                    .WithKey(memo, Keys.A)  //单按键
                    .KeyToCommand(x => x.OnAKey());
                mvvmContext.OfType<KeyAwareViewModel>()
                    .WithKey(memo, Keys.A | Keys.Alt) //   使用|代表复选
                    .KeyToCommand(x => x.OnAltAKey());
    		    mvvmContext.OfType<KeyAwareViewModel>()
    		        .WithKeys(memo, new Keys[] { Keys.A, Keys.B, Keys.C })  //多选择单按键
    		        .KeysToCommand(x => x.OnKey(Keys.None), args => args.KeyCode);
    		    // UI binding for the KeysToCommand behavior
    		    mvvmContext.OfType<KeyAwareViewModel>()
    		        .WithKeys(memo, new Keys[] { Keys.Shift | Keys.A, Keys.Shift | Keys.B, Keys.Shift | Keys.C })//多选择多按键
    		        .KeysToCommand(x => x.OnKeyArgs((KeyEventArgs)null), args => (KeyEventArgs)args);
     

    出处:https://blog.csdn.net/weixin_43862847/article/details/86750608


    最后在附加一个我自己的使用吧!

    ViewModel中的代码

            public void KeyDown(System.Windows.Forms.KeyEventArgs args)
            {
                if (args.KeyCode == System.Windows.Forms.Keys.Enter)
                {
                    args.Handled = true;   //将Handled设置为true,指示已经处理过KeyPress事件
                    Login();
                }
            }

    View中的代码

                //fluent.WithEvent<KeyEventArgs>(textEdit2, "KeyDown").EventToCommand(vm => vm.KeyDown(new KeyEventArgs(Keys.Enter)));//①
                //fluent.WithEvent<KeyEventArgs>(textEdit2, "KeyDown").EventToCommand(vm => vm.KeyDown((KeyEventArgs)null));//②
                fluent.WithKeys(textEdit2, new Keys[] { Keys.Shift | Keys.A, Keys.Shift | Keys.B, Keys.Shift | Keys.C })//多选择多按键  //③
                    .KeysToCommand(x => x.KeyDown((KeyEventArgs)null), args => (KeyEventArgs)args);

    以上三种方式,你都可以使用,具体自己看着办。

    第①和②二种方式效果一样,当光标在textEdit2中的时候,按任何键盘都会进入KeyDown的方法中

    第③种方式,则是必须满足:  new Keys[] 中设置的按键才会触发KeyDown的方法

    多说一句

    1)在设置为窗体的事件的时候,需要设置窗体的KeyPreview属性为true

    2)在Event To Command的时候,需要注意:我们平常使用的是:private void button1_Click(object sender, EventArgs e) 注意的方法签名,而在ViewModel的时候只有private void button1_Click(EventArgs e) 就可以了,调用:fluentAPI.WithEvent(commandButton, "Click").EventToCommand((x) => x.DoSomething(null));

  • 相关阅读:
    Django view(视图)
    Django ORM
    Django 路由系统(URLconf)
    Django简介
    Ubuntu 18.04安装MySQL指南
    一只简单的网络爬虫(基于linux C/C++)————配置文件设计及读取
    一只简单的网络爬虫(基于linux C/C++)————开篇
    单例模式及单例类的两种实现
    对象析构不析构?
    C++11的mutex和lock_guard,muduo的MutexLock 与MutexLockGuard
  • 原文地址:https://www.cnblogs.com/mq0036/p/10573440.html
Copyright © 2011-2022 走看看