7.【DevExpress MVVM】行为

211 阅读4分钟

行为在不修改对象的情况下向对象添加额外的功能。例如,close按钮关闭选项卡或表单,并额外显示确认对话框。您可以使用MVVM应用程序中的行为来实现这一点。

  • 确认类行为
  • Event-To-Command类行为
  • Key-To-Command类行为
  • 自定义行为

1. 确认类行为

一个简单的确认行为只能附加到一个可取消的事件(例如,表单关闭或编辑值更改)。要实现自定义行为,定义一个派生自 ConfirmationBehavior 类的类。它包含确认消息框的标题和文本的两个虚拟字符串属性。重写这些属性来分配文本字符串。类构造函数应该继承基类构造函数,其参数等于触发此行为的事件的名称。

public class FormCloseBehavior : ConfirmationBehavior<FormClosingEventArgs> {
    public FormCloseBehavior() : base("FormClosing") { }

    protected override string GetConfirmationCaption() {
        return "Confirm exit";
    }

    protected override string GetConfirmationText() {
        return "Do you really want to exit the application?";
    }
}

提示:
ConfirmationBehavior 类的最后一个虚拟属性是布尔型的Confirm属性。您还可以覆盖它以指定相关事件的取消条件。

//手工把确认逻辑给反转了
protected override bool Confirm() {
    return MessageBox.Show(GetConfirmationText(), GetConfirmationCaption(), MessageBoxButtons.YesNo) != DialogResult.Yes;
}

使用 MvvmContext 组件的API将此行为附加到目标UI元素。

//View
mvvmContext.AttachBehavior<FormCloseBehavior>(this);
//通过将行为声明从单独的类移到泛型类中,可以简化这个过程。
mvvmContext1.AttachBehavior<ConfirmationBehavior<ChangingEventArgs>>(checkEdit1, behavior => {
    behavior.Caption = "CheckEdit State Changing";
    behavior.Text = "This checkEdit's checked-state is about to be changed. Are you sure?";
    behavior.Buttons = ConfirmationButtons.YesNo;
    behavior.ShowQuestionIcon = true;
}, "EditValueChanging");

Fluent API也支持的。

mvvmContext1.WithEvent<ChangingEventArgs>(checkEdit1, "EditValueChanging").Confirmation(behavior => {
    behavior.Caption = "CheckEdit State changing";
    behavior.Text = "This checkEdit's checked-state is about to be changed. Are you sure?";
});

2. Event-To-Command类行为

如果确认行为需要接收CancelEventArgs类型参数的事件,则Event-to-command 类行为适合所有还需处理的事件。此行为将命令绑定到目标UI元素,当该元素触发所需事件时,将执行该命令。这可以用于:
没有实现ISupportCommandBinding接口的第三方UI元素,因此,不能使用MvvmContext组件的API (mvvmContext.BindCommand的方法)进行绑定。
需要拓展功能的DevExpress控件。例如,如果您需要一个SimpleButton来处理MouseHover 事件。
Event-to-command 类行为的实现类似于确认行为:你需要定义一个独立的类,它派生自DevExpress的EventToCommandBehavior类。在类构造函数中,指定目标事件名称和事件上应该执行的命令。

public class ClickToSayHello : DevExpress.Utils.MVVM.EventToCommandBehavior<ViewModel, EventArgs> {
    public ClickToSayHello()
        : base("Click", x => x.SayHello()) {
    }
}

附加事件到命令行为与确认行为是一模一样的。

mvvmContext.AttachBehavior<ClickToSayHello>(thirdPartyButton);

使用Fluent API允许你实现Event-to-command类行为,而无需单独创建类。

mvvmContext
    .WithEvent<ViewModel, EventArgs>(thirdPartyButton, "Click")
    .EventToCommand(x => x.SayHello());

3. Key-To-Command和Keys-To-Command行为

运行例子
这些行为允许您在终端用户按下特定键盘键时执行命令。

3.1 绑定单个键盘快捷键

下面的例子中ViewModel 定义了“OnAKey”和“OnAltKey”命令,它显示了基于服务的通知。

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");
    }
}

使用以下MvvmContext组件的Fluent API方法将这些命令绑定到相关的键:

方法名参数说明
WithKey第一个方法参数是一个UI元素,当最终用户按下特定的键时,必须对其进行聚焦。第二个参数是一个键组合
KeyToCommand指应该执行的命令。

下面的代码分别将“OnAKey”和“OnAltKey”命令绑定到“A”和“Alt+A”键。只有当memo编辑控件当前有焦点时,按下这两个组合键才能触发相关命令。

mvvmContext.ViewModelType = typeof(KeyAwareViewModel);
    // Binding the "A" key
    mvvmContext.OfType<KeyAwareViewModel>()
        .WithKey(memo, Keys.A)
        .KeyToCommand(x => x.OnAKey());
    // Binding the "Alt+A" shortcut
    mvvmContext.OfType<KeyAwareViewModel>()
        .WithKey(memo, Keys.A | Keys.Alt)
        .KeyToCommand(x => x.OnAltAKey());

3.2 将多个按键绑定到同一个命令

如果希望将多个键绑定到同一个命令并将这些键作为参数传递,可以使用WithKeysKeysToCommands方法。下面是例子中KeyAwareViewModelViewModel ,它包含参数化的“OnKey”和“OnKeyArgs”命令。这些命令通知用户按下了什么键。

public class KeyAwareViewModel {
    protected IMessageBoxService MessageBoxService {
        get { return this.GetService<IMessageBoxService>(); }
    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 + "}");
    }
}

下面的代码将这些命令一次绑定到多个热键。

mvvmContext.ViewModelType = typeof(KeyAwareViewModel);
    // Binding to the OnKey command
    mvvmContext.OfType<KeyAwareViewModel>()
        .WithKeys(memo, new Keys[] { Keys.A, Keys.B, Keys.C })
        .KeysToCommand(x => x.OnKey(Keys.None), args => args.KeyCode);
    // Binding to the OnKeyArgs command
    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);

4. 自定义行为

如果没有满足您需求的现成DevExpress行为,您可以实现自定义行为。例如,默认情况下,Ctrl+C键盘组合会复制整个GridView行。如果只需要复制所选行单元格的值,则可以附加自己的行为。

public class ControlCBehavior : EventTriggerBase<System.Windows.Forms.KeyEventArgs> {
     public ControlCBehavior() : base("KeyDown") {
     }
     protected override void OnEvent() {
         if (Args.Control && Args.KeyCode == System.Windows.Forms.Keys.C) {
             var cbService = this.GetService<Services.IClipboardService>();
             GridView View = Source as GridView;
             if (View.GetRowCellValue(View.FocusedRowHandle, View.FocusedColumn) != null && View.GetRowCellValue(View.FocusedRowHandle, View.FocusedColumn).ToString() != String.Empty)
                 cbService.SetText(View.GetRowCellValue(View.FocusedRowHandle, View.FocusedColumn).ToString());
             else
                 XtraMessageBox.Show("The value in the selected cell is null or empty!");
             Args.Handled = true;
         }
     }
 }

下面行为使用将文本复制到剪贴板的自定义IClipboardService服务。

public class ClipboardService : IClipboardService {
    public void SetText(string text) {
        Clipboard.SetText(text);
    }
}

public interface IClipboardService {
    void SetText(string text);
}

自定义行为准备好之后,注册服务并调用AttachBehavior方法将行为附加到GridView。

mvvmContext1.RegisterService(new Services.ClipboardService());
mvvmContext1.AttachBehavior<Behaviors.ControlCBehavior>(gridView1);

自定义行为现在取消默认快捷处理程序并只复制选定的单元格值。

【DevExpress MVVM】中文翻译系列.文章目录

DevExpress.WindowsForms.v20.1.chm离线英文原版文档下载