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 ...
随机推荐
- js同步、异步、回调的执行顺序以及闭包的理解
首先,记住同步第一.异步第二.回调最末的口诀 公式表达:同步=>异步=>回调 看一道经典的面试题: for (var i = 0; i < 5; i++) { setTimeout( ...
- JAVA中的责任链模式(CH01)
责任链模式的关键在于每一个任务处理者都必须持有下一个任务处理者的作用 纯的责任链:纯的责任链是只能也必须只有一个任务处理者去处理这个任务, 不会出现没有处理者处理的情况,也不会出现有多个处 ...
- Docker——入门实战
I. Docker简介Docker是一种新兴的虚拟化技术,能够一定程度上的代替传统虚拟机.不过,Docker 跟传统的虚拟化方式相比具有众多的优势.我也将Docker类比于Python虚拟环境,可以有 ...
- selenium配置文件定位元素
之前的写的selenium的定位元素进行测试的代码,现在一运行就报找不到元素了,之前运行的好好的. 我查看网站源码后,发现网站元素确实是变了,原来的定位的xpath代码压根全部找不到了,于是 想着,以 ...
- linux存储管理之磁盘配额
磁盘配额 1 相关命令:quota.quotacheck.edquota.quotaon.quotaoffquota要使用的命令有两种:一种用于查询功能,包括quota.quotacheck.quo ...
- Sign Up Account In CloudAMQP
CloudAMQP 有多种账号级别,请参考下面的链接的内容访问你可以注册的级别:https://www.cloudamqp.com/plans.html 作为测试来说,你可以注册免费的的消息. 你可以 ...
- 【转】前端的BFC、IFC、GFC和FFC
什么是BFC.IFC.GFC和FFC CSS2.1中只有BFC和IFC, CSS3中才有GFC和FFC. FC的全称是:Formatting Contexts,是W3C CSS2.1规范中的一个概念. ...
- 八大排序算法——选择排序(动图演示 思路分析 实例代码Java 复杂度分析)
一.动图演示 二.思路分析 1. 第一个跟后面的所有数相比,如果小于(或小于)第一个数的时候,暂存较小数的下标,第一趟结束后,将第一个数,与暂存的那个最小数进行交换,第一个数就是最小(或最大的数) ...
- 微信开发】【Asp.net MVC】-- 微信分享功能
[微信开发][Asp.net MVC]-- 微信分享功能 2017-01-15 09:09 by stoneniqiu, 12886 阅读, 15 评论, 收藏, 编辑 内嵌在微信中的网页,右上角都会 ...
- web工程启动时,在一个类中延迟加载Bean,因为该Bean类可能还没被JVM加载
问题描述: (1)javaWeb项目启动中,还没启动完成,在下面这个类加载另一个Bean类, (2)通过getBean方法获取到该Bean,可以获取到,不为null (3)但是,调用该Bean的方法 ...