归纳总结备忘

(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));

最新文章

  1. dataTables添加序号和行选中框
  2. windows下 安装Kali Linux到 U盘的方法
  3. JAVASE02-Unit07: 基本IO操作 、 文本数据IO操作
  4. 【mysql】Blob类型
  5. Linux内核补丁升级
  6. Acronis True Image Home 2011 PXE服务器配置_qxxz_新浪博客
  7. CN_Week1_Receptive_Field
  8. 解决No enclosing instance of type * is accessible
  9. WiFi文件上传框架SGWiFiUpload
  10. 使用ES6的模块编写web页面碰到的坑
  11. Spring扩展自定义的XML标签
  12. PHP字符串处理 单引号 双引号 heredoc nowdoc 定界符
  13. django创建上下文
  14. vscode插件和快捷键
  15. Warning: Function created with compilation errors.
  16. wampserver的配置教程
  17. docker镜像基本操作
  18. iOS 关于MVC和MVVM设计模式的那些事
  19. mysql拼接字符串和过滤字符的方法
  20. leetcode hashmap

热门文章

  1. 【转载】Selenium WebDriver的简单操作说明
  2. 微信H5页面嵌入百度地图---解决手机的webKit定位,ios系统对非https网站不提供支持问题
  3. grpc(二)记一次grpc debug--io.grpc.StatusRuntimeException: UNKNOWN
  4. python报错函数传参数传多了
  5. 学习笔记-AngularJs(八)
  6. ID基本操作(在框架内处理文本)5.28
  7. linux服务管理 服务管理
  8. Python connect mariadb(Python连接mysql)
  9. 3D打印GCODE文件学习(二)
  10. chrome扩展应用实例