zoukankan      html  css  js  c++  java
  • DevExpress WinForm MVVM数据和属性绑定指南(Part 3)

    根据您绑定的属性,存在以下三种可能的情况:

    • 常规绑定 - ViewModel属性绑定到任何不可编辑的View元素属性。由于该元素不可编辑,因此您无需将更新通知发送回绑定属性(单向绑定)。
    • 数据绑定 - Model属性(数据字段)绑定到编辑器属性。如果用户可以更改编辑器值,则需要更新绑定属性(双向绑定)。
    • 属性依赖 - 来自同一个ViewModel的两个属性被绑定。

    获取工具下载 - DevExpress WinForm v21.2

    属性依赖

    属性依赖是来自同一个ViewModel的两个属性之间的关系,当一个属性发生变化时,另一个属性会更新其值。

    在“MVVM 最佳实践”演示中,多个模块演示了以下设置:

    • 两个TextEdit控件绑定到ViewModel“Operand1”和“Operand2”属性。
    • 当用户更改 TextEdit 值时,操作数属性会刷新其值。
    • 当操作数属性更改时,它们会更新数字 “Result”属性(依赖项 #1)。
    • “Result”属性更新字符串“ResultText”属性(依赖项#2)。
    DevExpress WinForm控件入门指南:WinForms MVVM - 数据和属性绑定(Part 3)

    对于使用示例 UI 的每个演示模块,将 View 元素绑定到 ViewModel 属性的代码都是相同的。

    C#

    mvvmContext.ViewModelType = typeof(MultViewModel);
    var fluentAPI = mvvmContext.OfType<MultViewModel>();
    fluentAPI.SetBinding(editor1, e => e.EditValue, x => x.Operand1);
    fluentAPI.SetBinding(editor2, e => e.EditValue, x => x.Operand2);
    fluentAPI.SetBinding(resultLabel, l => l.Text, x => x.ResultText);

    VB.NET

    mvvmContext.ViewModelType = GetType(MultViewModel)
    Dim fluentAPI = mvvmContext.OfType(Of MultViewModel)()
    fluentAPI.SetBinding(editor1, Sub(e) e.EditValue, Sub(x) x.Operand1)
    fluentAPI.SetBinding(editor2, Sub(e) e.EditValue, Sub(x) x.Operand2)
    fluentAPI.SetBinding(resultLabel, Sub(l) l.Text, Sub(x) x.ResultText)

    然而,属性依赖在每个模块中的声明都不同。

    OnPropertyChanged 方法

    在POCO ViewModels中,您可以声明OnXChanged方法,其中 X 是属性名称。 当相关属性的值发生变化时,框架会调用这些方法。

    C#

    public class MultViewModel {
    public virtual int Operand1 { get; set; }
    public virtual int Operand2 { get; set; }
    public virtual int Result { get; set; }
    public virtual string ResultText { get; set; }
    
    protected void OnOperand1Changed() {
    UpdateResult();
    }
    protected void OnOperand2Changed() {
    UpdateResult();
    }
    protected void OnResultChanged() {
    UpdateResultText();
    }
    void UpdateResult() {
    Result = Operand1 * Operand2;
    }
    void UpdateResultText() {
    ResultText = string.Format("The result is: {0:n0}", Result);
    }
    }

    VB.NET

    Public Class MultViewModel
    Public Overridable Property Operand1() As Integer
    Public Overridable Property Operand2() As Integer
    Public Overridable Property Result() As Integer
    Public Overridable Property ResultText() As String
    
    Protected Sub OnOperand1Changed()
    UpdateResult()
    End Sub
    Protected Sub OnOperand2Changed()
    UpdateResult()
    End Sub
    Protected Sub OnResultChanged()
    UpdateResultText()
    End Sub
    Private Sub UpdateResult()
    Result = Operand1 * Operand2
    End Sub
    Private Sub UpdateResultText()
    ResultText = String.Format("The result is: {0:n0}", Result)
    End Sub
    End Class

    自定义更新方法

    如果您的更新方法未被称为“On...Changed”,请使用 DevExpress.Mvvm.DataAnnotations.BindableProperty 属性告诉框架它应该在属性值更改时调用此方法。 在下面的代码示例中,DevExpress.Mvvm.POCO.RaisePropertyChanged 是一个 DevExpress 扩展方法,它将更新通知发送到依赖属性。

    C#

    public class SumViewModel {
    [BindableProperty(OnPropertyChangedMethodName = "NotifyResultAndResultTextChanged")]
    public virtual int Operand1 { get; set; }
    [BindableProperty(OnPropertyChangedMethodName = "NotifyResultAndResultTextChanged")]
    public virtual int Operand2 { get; set; }
    public int Result {
    get { return Operand1 + Operand2; }
    }
    public string ResultText {
    get { return string.Format("The result is: {0:n0}", Result); }
    }
    protected void NotifyResultAndResultTextChanged() {
    this.RaisePropertyChanged(x => x.Result);
    this.RaisePropertyChanged(x => x.ResultText);
    }
    }

    VB.NET

    Public Class SumViewModel
    <BindableProperty(OnPropertyChangedMethodName := "NotifyResultAndResultTextChanged")>
    Public Overridable Property Operand1() As Integer
    <BindableProperty(OnPropertyChangedMethodName := "NotifyResultAndResultTextChanged")>
    Public Overridable Property Operand2() As Integer
    Public ReadOnly Property Result() As Integer
    Get
    Return Operand1 + Operand2
    End Get
    End Property
    Public ReadOnly Property ResultText() As String
    Get
    Return String.Format("The result is: {0:n0}", Result)
    End Get
    End Property
    Protected Sub NotifyResultAndResultTextChanged()
    Me.RaisePropertyChanged(Function(x) x.Result)
    Me.RaisePropertyChanged(Function(x) x.ResultText)
    End Sub
    End Class

    依赖属性

    使用 DevExpress.Mvvm.DataAnnotations.DependsOnProperties 属性标记依赖属性。 请注意,与前面的示例不同,下面的代码仅使用一个依赖项:“ResultText”取决于两个“Operand”属性,您不能使用此属性创建链式依赖项。

    C#

    public class MultViewModelEx {
    public virtual int Operand1 { get; set; }
    public virtual int Operand2 { get; set; }
    
    [DependsOnProperties("Operand1", "Operand2")]
    public string ResultText {
    get { return string.Format("The result is: {0:n0}", Operand1 * Operand2); }
    }
    }

    VB.NET

    Public Class MultViewModelEx
    Public Overridable Property Operand1() As Integer
    Public Overridable Property Operand2() As Integer
    
    <DependsOnProperties("Operand1", "Operand2")>
    Public ReadOnly Property ResultText() As String
    Get
    Return String.Format("The result is: {0:n0}", Operand1 * Operand2)
    End Get
    End Property
    End Class

    Metadata类

    在这种方法中,您创建自定义更新方法并使用单独的元数据类将属性与这些方法链接起来。 如果 BindableProperty 属性按名称引用更新方法,则 OnPropertyChangedCall 方法使用 lambda 表达式来检索方法。 重命名自定义更新方法时,元数据类显示编译错误。

    C#

    //View Model code
    [System.ComponentModel.DataAnnotations.MetadataType(typeof(Metadata))]
    public class SumViewModel_MetaPOCO {
    public virtual int Operand1 { get; set; }
    public virtual int Operand2 { get; set; }
    public virtual int Result { get; set; }
    public string ResultText {
    get { return string.Format("The result is: {0:n0}", Result); }
    }
    protected void NotifyResultAndResultTextChanged() {
    Result = Operand1 + Operand2;
    this.RaisePropertyChanged(x => x.Result);
    this.RaisePropertyChanged(x => x.ResultText);
    }
    //Metadata class
    public class Metadata : IMetadataProvider<SumViewModel_MetaPOCO> {
    void IMetadataProvider<SumViewModel_MetaPOCO>.BuildMetadata(MetadataBuilder<SumViewModel_MetaPOCO> builder) {
    builder.Property(x => x.Result)
    .DoNotMakeBindable();
    builder.Property(x => x.Operand1).
    OnPropertyChangedCall(x => x.NotifyResultAndResultTextChanged());
    builder.Property(x => x.Operand2).
    OnPropertyChangedCall(x => x.NotifyResultAndResultTextChanged());
    }
    }
    }

    VB.NET

    <System.ComponentModel.DataAnnotations.MetadataType(GetType(Metadata))>
    Public Class SumViewModel_MetaPOCO
    Public Overridable Property Operand1() As Integer
    Public Overridable Property Operand2() As Integer
    Public Overridable Property Result() As Integer
    Public ReadOnly Property ResultText() As String
    Get
    Return String.Format("The result is: {0:n0}", Result)
    End Get
    End Property
    Protected Sub NotifyResultAndResultTextChanged()
    Result = Operand1 + Operand2
    Me.RaisePropertyChanged(Function(x) x.Result)
    Me.RaisePropertyChanged(Function(x) x.ResultText)
    End Sub
    'Metadata class
    Public Class Metadata
    Implements IMetadataProvider(Of SumViewModel_MetaPOCO)
    
    Private Sub IMetadataProviderGeneric_BuildMetadata(ByVal builder As MetadataBuilder(Of SumViewModel_MetaPOCO)) Implements IMetadataProvider(Of SumViewModel_MetaPOCO).BuildMetadata
    builder.Property(Function(x) x.Result).DoNotMakeBindable()
    builder.Property(Function(x) x.Operand1).OnPropertyChangedCall(Function(x) x.NotifyResultAndResultTextChanged())
    builder.Property(Function(x) x.Operand2).OnPropertyChangedCall(Function(x) x.NotifyResultAndResultTextChanged())
    End Sub
    End Class
    End Class

    集合绑定

    要使用数据源记录填充多项目控件,请使用 SetItemsSourceBinding 方法。

    C#

    var fluentApi = mvvmContext1.OfType<ViewModelClass>();
    fluentApi.SetItemsSourceBinding(
    Target
    ItemSelector,
    SourceSelector,
    MatchExpression,
    CreateExpression,
    DisposeExpression,
    ChangeExpression
    );

    VB.NET

    Dim fluentApi = mvvmContext1.OfType(Of ViewModelClass)()
    fluentApi.SetItemsSourceBinding(Target ItemSelector, SourceSelector, MatchExpression, CreateExpression, DisposeExpression, ChangeExpression)
    • Target - 您需要填充的目标 UI 元素。
    • Item Selector - 一个表达式,用于检索应从数据源填充的 UI 元素的项目集合。
    • Source Selector - 定位数据源的表达式,其项目应用于填充目标。
    • Match Expression -将数据源项与目标子项进行比较的表达式。 当您更改或删除数据源记录时,框架会运行此表达式以确定是否应更新相应的 Target 集合项。
    • Create Expression - 出现新数据源记录时创建新目标集合项的表达式。
    • Dispose Expression - 一个表达式,当它的相关数据源记录被删除时处理一个 Target 集合项。
    • Change Expression - 指定当匹配表达式得出此项目与数据源记录不同时如何更新目标集合项目。

    在 MVVM 最佳实践演示中,以下代码使用自定义实体类的对象填充列表框。 SetBinding 方法将编辑器的 SelectedItem 属性与检索相应实体对象的 ViewModel SelectedEntity 属性绑定。

    C#

    //View code
    mvvmContext.ViewModelType = typeof(ViewModel);
    var fluentApi = mvvmContext.OfType<ViewModel>();
    fluentApi.SetItemsSourceBinding(
    listBox,
    lb => lb.Items,
    x => x.Entities,
    (item, entity) => object.Equals(item.Value, entity),
    entity => new ImageListBoxItem(entity),
    null,
    (item, entity) => {
    ((ImageListBoxItem)item).Description = entity.Text;
    }
    );
    fluentApi.SetBinding(listBox, lb => lb.SelectedValue, x => x.SelectedEntity);
    
    //ViewModel code
    public class ViewModel {
    public virtual Entity SelectedEntity { get; set; }
    public virtual ObservableCollection<Entity> Entities { get; set;}
    protected void OnSelectedEntityChanged() {
    //"Remove" is a custom ViewModel method that deletes a selected entity
    this.RaiseCanExecuteChanged(x => x.Remove());
    }
    protected void OnEntitiesChanged() {
    SelectedEntity = Entities.FirstOrDefault();
    }
    }
    
    //Model code
    public class Entity {
    public Entity(int id) {
    this.ID = id;
    this.Text = "Entity " + id.ToString();
    }
    public int ID { get; private set; }
    public string Text { get; set; }
    }

    VB.NET

    'View code
    mvvmContext.ViewModelType = GetType(ViewModel)
    Dim fluentApi = mvvmContext.OfType(Of ViewModel)()
    fluentApi.SetItemsSourceBinding(
    listBox,
    Function(lb) lb.Items,
    Function(x) x.Entities,
    Function(item, entity) Object.Equals(item.Value, entity),
    Function(entity) New ImageListBoxItem(entity),
    Nothing,
    Function(item, entity) CType(item, ImageListBoxItem).Description = entity.Text
    )
    fluentApi.SetBinding(listBox, Function(lb) lb.SelectedValue, Function(x) x.SelectedEntity)
    
    'ViewModel code
    Public Class ViewModel
    Public Overridable Property SelectedEntity() As Entity
    Public Overridable Property Entities() As ObservableCollection(Of Entity)
    Protected Sub OnSelectedEntityChanged()
    '"Remove" is a custom ViewModel method that deletes a selected entity
    Me.RaiseCanExecuteChanged(Function(x) x.Remove())
    End Sub
    Protected Sub OnEntitiesChanged()
    SelectedEntity = Entities.FirstOrDefault()
    End Sub
    End Class
    
    'Model code
    Public Class Entity
    Public Sub New(ByVal id As Integer)
    Me.ID = id
    Me.Text = "Entity " & id.ToString()
    End Sub
    Private privateID As Integer
    Public Property ID() As Integer
    Get
    Return privateID
    End Get
    Private Set(ByVal value As Integer)
    privateID = value
    End Set
    End Property
    Public Property Text() As String
    End Class

    触发器

    触发器允许您在 ViewModel 属性更改时修改 UI(视图)。 在 DevExpress 演示中,复选框绑定到 ViewModel “IsActive”属性。 当此属性的值更改时,触发器会更改 UI 元素(标签)的背景颜色。

    C#

    //ViewModel code
    public class ViewModel {
    public virtual bool IsActive { get; set; }
    }
    
    //ViewModel code
    var fluent = mvvmContext.OfType<ViewModel>();
    fluent.SetBinding(checkEdit, c => c.Checked, x => x.IsActive);
    fluent.SetTrigger(x => x.IsActive, (active) => {
    if(active)
    label.Appearance.BackColor = Color.LightPink;
    else
    label.Appearance.BackColor = Color.Empty;
    });

    VB.NET

    'ViewModel code
    Public Class ViewModel
    Public Overridable Property IsActive() As Boolean
    End Class
    
    'ViewModel code
    Private fluent = mvvmContext.OfType(Of ViewModel)()
    fluent.SetBinding(checkEdit, Function(c) c.Checked, Function(x) x.IsActive)
    fluent.SetTrigger(Function(x) x.IsActive, Sub(active)
    If active Then
    label.Appearance.BackColor = Color.LightPink
    Else
    label.Appearance.BackColor = Color.Empty
    End If
    End Sub)

    DevExpress WinForm | 下载试用

    DevExpress WinForm拥有180+组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。DevExpress WinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!


    DevExpress技术交流群5:742234706      欢迎一起进群讨论

    更多DevExpress线上公开课、中文教程资讯请上中文网获取

  • 相关阅读:
    sql server 查看锁表SQL【转】
    在cxGrid表格中如何获得当前列的字段名
    获取cxgrid footer内容
    gulp学习总结
    前端入门应该掌握的html+css知识点
    前端知识回顾
    this、apply/call、bind、闭包、函数、变量复制
    三角形的实现方法(马)
    webpack学习总结(一)
    使用模板引擎artTemplate的几个问题总结
  • 原文地址:https://www.cnblogs.com/AABBbaby/p/15559567.html
Copyright © 2011-2022 走看看