數(shù)據(jù)和屬性綁定
根據(jù)您綁定的屬性,有三種可能的情況:
常規(guī)綁定——ViewModel屬性綁定到任何不可編輯的View元素的屬性。由于元素不可編輯,因此不需要將更新通知發(fā)送回綁定屬性(單向綁定)。
數(shù)據(jù)綁定——Model屬性(數(shù)據(jù)字段)綁定到編輯器屬性,如果用戶可以更改編輯器值,則需要更新綁定屬性(雙向綁定)。
屬性依賴性——綁定同一個ViewModel的兩個屬性。
常規(guī)綁定
如果需要將數(shù)據(jù)從一個屬性傳遞到另一個ViewModel的屬性,您可以使用標準的數(shù)據(jù)綁定API,或者推薦使用DevExpress MvvmContext.SetBinding方法。
例如,視圖有一個沒有文本的LabelControl,ViewModel有一個可綁定的字符串“LabelText”屬性,使用以下任何一種方法將屬性值傳遞給此Label。
C#:
//ViewModel code [POCOViewModel()] public class Form1ViewModel { public Form1ViewModel() { LabelText = "Value stored in ViewModel"; } public virtual string LabelText { get; set; } } //View code //option #1 (recommended): SetBinding method var fluent = mvvmContext1.OfType<Form1ViewModel>(); fluent.SetBinding(labelControl1, l => l.Text, x=>x.LabelText); //option #2: DataBindings Form1ViewModel viewModel = mvvmContext1.GetViewModel<Form1ViewModel>(); labelControl1.DataBindings.Add("Text", viewModel, "LabelText");
VB.NET:
'ViewModel code <POCOViewModel()> Public Class Form1ViewModel Public Sub New() LabelText = "Value stored in ViewModel" End Sub Public Overridable Property LabelText() As String End Class 'View code 'option #1 (recommended): SetBinding method Dim fluent = mvvmContext1.OfType(Of Form1ViewModel)() fluent.SetBinding(labelControl1, Function(l) l.Text, Function(x) x.LabelText) 'option #2: DataBindings Dim viewModel As Form1ViewModel = mvvmContext1.GetViewModel(Of Form1ViewModel)() labelControl1.DataBindings.Add("Text", viewModel, "LabelText")
提示:如果需要將編輯器綁定到屬性,并選擇特定的更新模式,請使用標準數(shù)據(jù)綁定而不是SetBinding方法(請參閱數(shù)據(jù)綁定部分)。
POCO視圖模型中的更新通知
如果綁定屬性的值可以更改,那么將此更改通知相關(guān)屬性非常重要,為此向相關(guān)屬性發(fā)送更新通知。如果使用的是POCO ViewModels那么 DevExpress框架可以發(fā)送這些通知。
在MVVM應(yīng)用程序中,每個視圖都有一個相關(guān)的ViewModel。當使用DevExpress MVVM框架時,您應(yīng)該為每個視圖添加一個MvvmContext組件,并將該組件指向與該視圖相關(guān)的ViewModel,我們建議在設(shè)計時通過組件的智能標簽菜單來完成這個操作。
您還可以在代碼中使用ViewModelType屬性來完成此操作。
C#:
mvvmContext.ViewModelType = typeof(ViewModel);
VB.NET:
mvvmContext.ViewModelType = GetType(ViewModel)
框架將分配給MvvmContext組件的每個ViewModel視為POCO (Plain Old CRL Object) ViewModel,POCO視圖模型有許多命名和語法約定,如果您遵循它們,框架就會預(yù)測您想要做什么并相應(yīng)地采取行動。例如,更新通知自動發(fā)送到(從)“正確”聲明的屬性。
創(chuàng)建一個 public virtual auto-implemented屬性,來允許框架向該屬性發(fā)送更新通知,還可以將屬性設(shè)置器聲明為protected。
C#:
public virtual string Name { get; set; } public virtual int ID { get; protected set; }
VB.NET:
Public Overridable Property Name() As String Public Overridable Property ID() As Integer Get Return _privateID End Get Protected Set(ByVal value As Integer) _privateID = value End Set End Property
提示:框架會忽略帶有支持字段的屬性,為了能夠綁定這些屬性,可以用DevExpress.Mvvm.DataAnnotations.BindableProperty屬性來修飾它們。
C#:
using DevExpress.Mvvm.DataAnnotations; //. . . string name; [BindableProperty] public virtual string Name { get { return name; } set { name = value; } }
VB.NET:
Imports DevExpress.Mvvm.DataAnnotations '. . . Private name_field As String <BindableProperty> Public Overridable Property Name() As String Get Return name_field End Get Set(ByVal value As String) name_field = value End Set End Property
如果希望在每次更新屬性時調(diào)用特定的方法,請在同一屬性中指定該方法的名稱。
C#:
[BindableProperty(OnPropertyChangedMethodName= "OnLookUpEdit1ValueChanged")] public virtual string Name { // ... }
VB.NET:
<BindableProperty(OnPropertyChangedMethodName:= "OnLookUpEdit1ValueChanged")> Public Overridable ReadOnly Property Name() As String ' ... End Property
在Bindable Properties演示中,一個Label顯示了TextEdit編輯器的值。TextEdit被綁定到自動實現(xiàn)的虛擬Text屬性(存儲原始編輯器值),Label被綁定到Title(存儲格式化的“Text”值)。
由于“Text”屬性遵循POCO命名約定,所以TextEdit-to-Text綁定是雙向的:當ViewModel屬性改變時,編輯器更新其值,當用戶修改編輯器文本時,ViewModel屬性更新其值。Label-to-Title綁定是單向的,因為“Title”屬性沒有公共集方法。在這個設(shè)置中,我們不需要對“Title”進行雙向綁定,因為用戶不能更改Label文本。
C#:
//View code var fluent = mvvmContext.OfType<ViewModel>(); fluent.SetBinding(editor, ed => ed.EditValue, x => x.Text); fluent.SetBinding(label, lbl => lbl.Text, x => x.Title); //ViewModel code public class ViewModel { public virtual string Text { get; set; } public string Title { get { if(Text == null) return "Title: (Null)"; if(Text.Length == 0) return "Title: (Empty)"; if(string.IsNullOrWhiteSpace(Text)) return "Title: (Whitespace)"; return "Title: " + Text; } } }
VB.NET:
'View code Dim fluent = mvvmContext.OfType(Of ViewModel)() fluent.SetBinding(editor, Function(ed) ed.EditValue, Function(x) x.Text) fluent.SetBinding(label, Function(lbl) lbl.Text, Function(x) x.Title) 'ViewModel code Public Class ViewModel Public Overridable Property Text() As String Public ReadOnly Property Title() As String Get If Text Is Nothing Then Return "Title: (Null)" End If If Text.Length = 0 Then Return "Title: (Empty)" End If If String.IsNullOrWhiteSpace(Text) Then Return "Title: (Whitespace)" End If Return "Title: " & Text End Get End Property End Class
注意:上面的代碼演示了“Title”和“Text”屬性之間的區(qū)別,但并不完整,demo模塊還使用屬性依賴來在“Text”發(fā)生變化時更新“Title”,運行演示可以查看完整的代碼。
綁定嵌套和非poco視圖模型的屬性
如果您需要綁定一個嵌套的ViewModel屬性,使用DevExpress.Mvvm.POCO.ViewModelSource.Create方法來創(chuàng)建這個嵌套ViewModel的實例,您可以通過 parent ViewModel訪問它,視圖綁定語法使用相同的SetBinding方法。
C#:
//Nested ViewModel public class NestedViewModel { public virtual string Text { get; set; } } //Parent ViewModel public class ViewModelWithChild { public ViewModelWithChild() { Child = ViewModelSource.Create<NestedViewModel>(); } public NestedViewModel Child { get; private set; } } //View code var fluent = mvvmContext.OfType<ViewModelWithChild>(); fluent.SetBinding(editor, ed => ed.EditValue, x => x.Child.Text);
VB.NET:
'Nested ViewModel Public Class NestedViewModel Public Overridable Property Text() As String End Class 'Parent ViewModel Public Class ViewModelWithChild Public Sub New() Child = ViewModelSource.Create(Of NestedViewModel)() End Sub Private privateChild As NestedViewModel Public Property Child() As NestedViewModel Get Return privateChild End Get Private Set(ByVal value As NestedViewModel) privateChild = value End Set End Property End Class 'View code Dim fluent = mvvmContext.OfType(Of ViewModelWithChild)() fluent.SetBinding(editor, Function(ed) ed.EditValue, Function(x) x.Child.Text)
如果不使用POCO模型,則框架不會自動發(fā)送更新通知。要在這種情況下發(fā)送通知,實現(xiàn)INotifyPropertyChanged 接口或創(chuàng)建-PropertyName-Changed事件,注意不能使用mvvmContext.ViewModelType屬性,您應(yīng)該調(diào)用mvvmContext.SetViewModel方法將ViewModel實例傳遞給組件。
C#:
//ViewModel code public class ObjectWithTextAndTitle { string textCore; public string Text { get { return textCore; } set { if(textCore == value) return; textCore = value; OnTextChanged(); } } protected virtual void OnTextChanged() { RaiseTextChanged(); } protected void RaiseTextChanged() { var handler = TextChanged; if(handler != null) handler(this, EventArgs.Empty); } public event EventHandler TextChanged; } //View code mvvmContext.SetViewModel(typeof(ObjectWithTextAndTitle), viewModelInstance); var fluent = mvvmContext.OfType<ObjectWithTextAndTitle>(); fluent.SetBinding(editor, ed => ed.EditValue, x => x.Text);
VB.NET:
'ViewModel code Public Class ObjectWithTextAndTitle Private textCore As String Public Property Text() As String Get Return textCore End Get Set(ByVal value As String) If textCore = value Then Return End If textCore = value OnTextChanged() End Set End Property Protected Overridable Sub OnTextChanged() RaiseTextChanged() End Sub Protected Sub RaiseTextChanged() Dim handler = TextChangedEvent If handler IsNot Nothing Then handler(Me, EventArgs.Empty) End If End Sub Public Event TextChanged As EventHandler End Class 'View code mvvmContext.SetViewModel(GetType(ObjectWithTextAndTitle), viewModelInstance) Dim fluent = mvvmContext.OfType(Of ObjectWithTextAndTitle)() fluent.SetBinding(editor, Function(ed) ed.EditValue, Function(x) x.Text)
數(shù)據(jù)綁定
要將編輯器綁定到Model屬性,請將 BindingSource 添加到View并使用標準的數(shù)據(jù)綁定API,可選的updatemode參數(shù)允許您指定屬性是否在編輯器值更改時更新其值,以及(如果是)是應(yīng)該立即發(fā)生還是在驗證編輯器時發(fā)生。
C#:
editor.DataBindings.Add(...);
VB.NET:
editor.DataBindings.Add(...)
實體屬性綁定演示定義了一個自定義Entity類,此類的實例用作數(shù)據(jù)記錄并具有ID和Text字段,兩個數(shù)據(jù)字段都綁定到編輯器,并且BindingSource組件存儲活動Entity對象。
C#:
//View mvvmContext.ViewModelType = typeof(ViewModel); var fluentApi = mvvmContext.OfType<ViewModel>(); // Create a BindingSource and populate it with a data object. //When a user modifies this object, the "Update" method is called BindingSource entityBindingSource = new BindingSource(); entityBindingSource.DataSource = typeof(Entity); fluentApi.SetObjectDataSourceBinding(entityBindingSource, x => x.Entity, x => x.Update()); // Data Bindings idEditor.DataBindings.Add( new Binding("EditValue", entityBindingSource, "ID")); textEditor.DataBindings.Add( new Binding("EditValue", entityBindingSource, "Text", true, DataSourceUpdateMode.OnPropertyChanged)); //ViewModel public class ViewModel { //... public virtual Entity Entity { get; set; } //... } //Model 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 mvvmContext.ViewModelType = GetType(ViewModel) Dim fluentApi = mvvmContext.OfType(Of ViewModel)() ' Create a BindingSource and populate it with a data object. 'When a user modifies this object, the "Update" method is called Dim entityBindingSource As New BindingSource() entityBindingSource.DataSource = GetType(Entity) fluentApi.SetObjectDataSourceBinding(entityBindingSource, Function(x) x.Entity, Function(x) x.Update()) ' Data Bindings idEditor.DataBindings.Add(New Binding("EditValue", entityBindingSource, "ID")) textEditor.DataBindings.Add(New Binding("EditValue", entityBindingSource, "Text", True, DataSourceUpdateMode.OnPropertyChanged)) 'ViewModel Public Class ViewModel '... Public Overridable Property Entity() As Entity '... End Class 'Model 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
您也可以使用SetBinding方法。
C#:
fluent.SetBinding(idEditor, l => l.EditValue, x => x.Entity.ID); fluent.SetBinding(textEditor, l => l.EditValue, x => x.Entity.Text);
VB.NET:
fluent.SetBinding(idEditor, Function(te) te.EditValue, Function(dl) dl.Entity.ID) fluent.SetBinding(textEditor, Function(te) te.EditValue, Function(dl) dl.Entity.Text)
但在這種情況下,就失去了設(shè)置必需的DataSourceUpdateMode的選項,該選項允許您防止過多的更新通知。
屬性依賴性
屬性依賴關(guān)系是來自同一ViewModel的兩個屬性之間的關(guān)系,當一個屬性改變時則另一個屬性會更新它的值。
在MVVM Best Practices演示中,多個模塊演示了以下設(shè)置:
- 將兩個 TextEdit 控件綁定到 ViewModel “Operand1”和“Operand 2”屬性。
- 當用戶更改 TextEdit 值時,操作數(shù)屬性會刷新其值。
- 當操作數(shù)屬性更改時,它們會更新數(shù)字“結(jié)果”屬性(依賴項#1)。
- “Result”屬性更新字符串“ResultText”屬性(依賴項#2)。
對于使用示例UI的每個演示模塊,將視圖元素綁定到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 ViewModel 中,您可以聲明OnXChanged其中 X 是屬性名稱的方法,當相關(guān)屬性的值發(fā)生變化時,框架會調(diào)用這些方法。
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
自定義更新方法
如果您的更新方法未調(diào)用“On…Changed”,請使用該DevExpress.Mvvm.DataAnnotations.BindableProperty屬性告訴框架,當屬性值更改時應(yīng)調(diào)用此方法。在下面的代碼示例中,DevExpress.Mvvm.POCO.RaisePropertyChanged是一個 DevExpress 擴展方法,它將更新通知發(fā)送到依賴屬性。
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
屬性依賴
使用 attribute 標記依賴屬性DevExpress.Mvvm.DataAnnotations.DependsOnProperties,請注意與前面的示例不同,下面的代碼僅使用一個依賴項:“ResultText”依賴于兩個“Operand”屬性,您無法使用此屬性創(chuàng)建鏈接依賴項。
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
元數(shù)據(jù)類
在此方法中,創(chuàng)建自定義更新方法并使用單獨的元數(shù)據(jù)類將屬性與這些方法鏈接起來。如果BindableProperty 屬性按名稱引用更新方法,則該OnPropertyChangedCall方法使用 lambda 表達式來檢索方法。當重命名自定義更新方法時,Metadata 類會顯示編譯錯誤。
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
集合綁定
要使用數(shù)據(jù)源記錄填充多項目控件,請使用方法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元素。
項目選擇器——一個表達式,用于檢索應(yīng)該從數(shù)據(jù)源填充的UI元素的項目集合。
源選擇器——一個表達式,用于定位數(shù)據(jù)源,其項應(yīng)用于填充目標。
匹配表達式——將數(shù)據(jù)源項與目標子項進行比較的表達式。當更改或刪除數(shù)據(jù)源記錄時,框架將運行此表達式來確定是否應(yīng)該更新相應(yīng)的Target集合項。
創(chuàng)建表達式——當出現(xiàn)新的數(shù)據(jù)源記錄時,用于創(chuàng)建新的Target集合項的表達式。
處理表達式——當Target集合項的相關(guān)數(shù)據(jù)源記錄被刪除時,該表達式將對其進行處理。
更改表達式——指定當匹配表達式得出的目標集合項與數(shù)據(jù)源記錄不同時,如何更新目標集合項。
在MVVM最佳實踐演示中,下面的代碼用自定義Entity類的對象填充一個列表框,SetBinding方法將編輯器的SelectedItem屬性與檢索相應(yīng)Entity對象的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
觸發(fā)器
觸發(fā)器允許您在 ViewModel 屬性更改時修改 UI(視圖)。在DevExpress 演示中,一個復(fù)選框綁定到 ViewModel“IsActive”屬性,當此屬性的值更改時,觸發(fā)器會更改 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)