概括总结备忘
express
我本身的使用设计模式
MVVM是Model-View-ViewModel,是一种专为WPF开发而设计的架构设计模式,相似MVC。MVVM 就是将其中的View 的状态和行为抽象化,让咱们将视图 UI 和业务逻辑分开。 ViewModel 根据databindings,commond,notification等与view层链接,能够取出 Model 的数据同时帮忙处理 View 中因为须要展现内容而涉及的业务逻辑,充当视图层与数据层的通讯桥梁。
好处:markdown
DevExpress全称Developer Express,是全球著名的控件开发公司,其.NET界面控件DXperience Universal Suite(Dev宇宙版)全球知名,获奖无数。DevExpress控件以界面美观和功能强大著称,拥有大量的示例和帮助文档,开发者可以快速上手。在国内,DevExpress亦拥有大量的用户,资料比较完善,交流方便。DevExpress普遍应用于ECM企业内容管理、 成本管控、进程监督、生产调度,在企业/政务信息化管理中占据一席重要之地。架构
官网:https://www.devexpress.com/框架
如上所说,mvvm专为WPF设计,而没有第三方MVVM框架的 winform平台缺少灵活的绑定以及绑定commad等基本特性,必须手动实现,而devexpress为这些特性提供了完整支持,是开发更关心自己业务逻辑。异步
在devexpress中viewModel全部的 virtual 属性都将是可绑定的,在更改值时会自动传递PropertyChanged消息(在未有devexpress的winform程序类必须继承 INotifyPropertyChanged并实现该接口才能实现双向绑定),当没有virtual属性时,只有主动调用 this.RaisePropertyChanged(x => x.你的属性)才会向视图层传递PropertyChanged消息。
下面例子:
viewmodelasync
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层mvvm
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 单向绑定 });
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);
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);
两个按钮控制进度条滚动开始中止
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);
四种常见使用状况
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);
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?"; });
事件转命令,效果与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);
按键转命令
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));