Devexpress Winform MVVM
归纳总结备忘
Devexpress Winform MVVM Practice
(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));
Devexpress Winform MVVM的更多相关文章
- DevExpress winform XtraEditor常用控件
最近在公司里面开始使用DevExpress winform的第三方控件进行开发和维护,这里整理一些常用控件的资料以便于后续查看 ComboBoxEdit 这个控件和winform自带的控件差不多,使用 ...
- DevExpress Winform 常用控件
Ø 前言 DevExpress 控件的功能比较强大,是全球知名控件开发公司,对于开发 B/S 或 C/S 都非常出色,可以实现很炫且功能强大的效果. DevExpress Winform 常用控件是 ...
- DevExpress Winform 通用控件打印方法(允许可自定义边距) z
DevExpress Winform 通用控件打印方法,包括gridcontrol,treelist,pivotGridControl,ChartControl,LayoutControl...(所有 ...
- DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法
原文:DevExpress Winform使用单例运行程序方法和非DevExpress使用Mutex实现程序单实例运行且运行则激活窗体的方法 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA ...
- Devexpress Winform 使用MVVM
MVVM在WPF里很早就有了,在Winform里Devexpress最近几个大版本才有的事,上一段代码. 现在对话框上添加三个控件simpleButton1,simpleButton2,textEdi ...
- devexpress WinForms MVVM
WinForms MVVM This section is dedicated to the Model-View-ViewModel (MVVM) architectural pattern. Yo ...
- Devexpress Winform初学笔记
作为一个软件开发人员来说,得有自己的博客,可以用来ZB,哈哈!玩笑话..... 写博客并不仅仅是用来ZB的,他可以用来记录你在技术道路上探索遇到的坎,当然也有提高逼格的次然因素啦!小弟刚入博客园不久, ...
- Devexpress Winform Gridcontrol 中根据条件单元格的值改变单元格的颜色等属性。
提供一下三种方法 1.使用设计器 点击gridcontrol控件,run designer,format Condtions, add,然后进行各种条件的设置. 2.用代码代替设计器. 实例代码: p ...
- 强大DevExpress,Winform LookUpEdit 实现多列查询 gridview弹出下拉选择 z
关键代码请参考http://www.devexpress.com/Support/Center/p/K18333.aspx 最新DEMO 下载 The current GridLookUpEdit's ...
随机推荐
- hdu 6010 Daylight Saving Time 泰勒公式
Daylight Saving Time Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- Redhat配置yum源(使用阿里云yum Repo)
1. 查看版本号和系统类别: cat /etc/redhat-release archor cat /etc/issue && arch 2.检查yum是否安装,以及安装了哪些依赖源并 ...
- [C#]统计文本文件txt中的行数(快速读取)
快速统计文本文件中的行数( StreamReader.ReadLine() ): 测试代码如下: //读取txt文件中总行数的方法 public static int requestMethod(St ...
- C++类的大小计算
转自http://www.tuicool.com/articles/uiUJry 一个空的class在内存中多少字节?如果加入一个成员函数后是多大?这个成员函数存储在内存中什么部分? 一个Class对 ...
- [easyUI] 列表
一. 简述: 对一个层级的ul/ol进行调用menu()函数,即可简单做成层叠列表. 二. 实例: <ul id="menu3"> <li>Menu1 &l ...
- selenium java maven自动化测试环境搭建
版本说明: JDK 版本:1.8.0_112: Eclipse IDE: 4.6.1: Maven 版本:apache-maven-3.3.9: Selenium 版本: 3.0.1: Firefox ...
- CSS样式表与HTML结合的方法
从此王子和公主幸福的生活在了一起:) 层叠样式表(英文全称:Cascading Style Sheets)是一种用来表现HTML(标准通用标记语言的一个应用)或XML(标准通用标记语言的一个子集)等文 ...
- Dropout, DropConnect ——一个对输出,一个对输入
Deep learning: Dropout, DropConnect from:https://www.jianshu.com/p/b349c4c82da3 Dropout 训练神经网络模型时,如果 ...
- redis可执行文件说明
redis-server :redis服务器 redis-cli :redis命令客户端 redis-benchmark :redis性能压测工具 redis-check-dump ...
- vue和react全面对比(详解)
vue和react对比(详解) 放两张图镇压小妖怪 本文先讲共同之处, 再分析区别 大纲在此: 共同点: a.都使用虚拟dom b.提供了响应式和组件化的视图组件 c.注意力集中保持在核心库,而将其他 ...