[英]Binding ComboBox TwoWay to Property
我正在嘗試使用雙向綁定。
這些組合框應將它們自己(TwoWay)綁定到VM中的屬性:
<ComboBox x:Name="_cmbCatT1" Margin="5,1,5,10"
ItemsSource="{Binding MVM.CategoryLinkCollection}"
DisplayMemberPath="Category.Name"
SelectedValue="{Binding MVM.SelectedTier1, Mode=TwoWay}"
SelectedValuePath="Category"/>
<ComboBox x:Name="_cmbCatT2" Margin="5,1,5,10"
DataContext="{Binding SelectedItem, ElementName=_cmbCatT1}"
ItemsSource="{Binding CategoryLinkCollection}"
DisplayMemberPath="Category.Name"
SelectedValue="{Binding MVM.SelectedTier2, ElementName=_vManipulation, Mode=TwoWay}"
SelectedValuePath="Category"/>
<ComboBox x:Name="_cmbCatT3" Margin="5,1,5,10"
DataContext="{Binding SelectedItem, ElementName=_cmbCatT2}"
ItemsSource="{Binding CategoryLinkCollection}"
DisplayMemberPath="Category.Name"
SelectedValue="{Binding MVM.SelectedTier3, ElementName=_vManipulation, Mode=TwoWay}"
SelectedValuePath="Category"/>
VM:
private string selectedName;
public string SelectedName {
get {
return this.selectedName;
}
set {
this.selectedName = value;
OnPropertyChanged("SelectedName");
}
}
private string selectedDescription;
public string SelectedDescription {
get {
return this.selectedDescription;
}
set {
this.selectedDescription = value;
OnPropertyChanged("SelectedDescription");
}
}
private string selectedRemark;
public string SelectedRemark {
get {
return this.selectedRemark;
}
set {
this.selectedRemark = value;
OnPropertyChanged("SelectedRemark");
}
}
private string selectedValue;
public string SelectedValue {
get {
return this.selectedValue;
}
set {
this.selectedValue = value;
OnPropertyChanged("SelectedValue");
}
}
private Model.Room selectedRoom;
public Model.Room SelectedRoom {
get {
return this.selectedRoom;
}
set {
this.selectedRoom = value;
OnPropertyChanged("SelectedRoom");
}
}
private Model.Locker selectedLocker;
public Model.Locker SelectedLocker {
get {
return this.selectedLocker;
}
set {
this.selectedLocker = value;
OnPropertyChanged("SelectedLocker");
}
}
private Model.Category selectedTier1;
public Model.Category SelectedTier1 {
get {
return this.selectedTier1;
}
set {
this.selectedTier1 = value;
OnPropertyChanged("SelectedTier1");
}
}
private Model.Category selectedTier2;
public Model.Category SelectedTier2 {
get {
return this.selectedTier2;
}
set {
this.selectedTier2 = value;
OnPropertyChanged("SelectedTier2");
}
}
private Model.Category selectedTier3;
public Model.Category SelectedTier3 {
get {
return this.selectedTier3;
}
set {
this.selectedTier3 = value;
OnPropertyChanged("SelectedTier3");
}
}
private Model.Manufacturer selectedManufacturer;
public Model.Manufacturer SelectedManufacturer {
get {
return this.selectedManufacturer;
}
set {
this.selectedManufacturer = value;
OnPropertyChanged("SelectedManufacturer");
}
}
請注意,ItemsSource的數據類型是“ CategoryLinkCollection”,其中包含“ Category”-屬性和Obs.Collection“ CategoryLinkCollection”。 通過SelectedValuePath,“類別”在VM的屬性中“保存”。
只要我在ComboBox中選擇一個項目,一切就可以正常工作,但是當我手動設置VM屬性時,ComboBox不會從包含定義類別的ItemsSource中預選該項目。 普通的字符串值只能用於finde(文本框)
我認為由於類型不同(ComboBox = CategoryLinkCollection,ValuePath到Category,Property = Category),它將永遠無法工作,但也許有些人可以證明我錯了。 如果您需要更多信息,請告訴我。
更新1:
我只是記得主要的原因應該在其他地方,因為“制造商”模型沒有包裝器-因此ItemsSource包含與屬性相同的數據類型的Collection。
XAML:
<ComboBox x:Name="_cmbManufacturer"
ItemsSource="{Binding MVM.ManufacturerCollection}"
DisplayMemberPath="Name"
SelectedItem="{Binding MVM.SelectedManufacturer, Mode=TwoWay}"/>
VM:見上文。
更新2:
首先,請遠離那些糟糕的類別,而轉到Update 1中提到的制造商,因為這是相同的問題,但是更容易進入。
我現在在手動設置之后檢查了SelectedManufacturer-Property,以防萬一設置時出現問題。 SelectedManufacturer-Property包含制造商(不為null),但UI仍未更新。
更新3:
使用診斷NS之后,我從“輸出窗口”中獲得了以下輸出:
System.Windows.Data警告:60:BindingExpression(哈希= 43478430):默認模式解析為TwoWay
System.Windows.Data警告:61:BindingExpression(哈希= 43478430):默認更新觸發器已解析為PropertyChanged
System.Windows.Data警告:62:BindingExpression(哈希= 43478430):附加到System.Windows.Controls.ComboBox.SelectedItem(哈希= 10372298)
System.Windows.Data警告:67:BindingExpression(hash = 43478430):解析源
System.Windows.Data警告:70:BindingExpression(哈希= 43478430):找到數據上下文元素:ComboBox(哈希= 10372298)(確定)
System.Windows.Data警告:78:BindingExpression(哈希= 43478430):激活與根項操縱(哈希= 64100268)
System.Windows.Data警告:107:BindingExpression(hash = 43478430):在級別0使用緩存的訪問器進行操作。MVM:RuntimePropertyInfo(MVM)
System.Windows.Data警告:104:BindingExpression(hash = 43478430):使用訪問器RuntimePropertyInfo(MVM)將級別0的項替換為Manipulation(hash = 64100268)
System.Windows.Data警告:101:BindingExpression(hash = 43478430):使用RuntimePropertyInfo(MVM)從操作(hash = 64100268)在級別0上的GetValue:ManipulationViewModel(hash = 11088040)
System.Windows.Data警告:108:BindingExpression(哈希= 43478430):在級別1-對於ManipulationViewModel.SelectedManufacturer找到訪問器RuntimePropertyInfo(SelectedManufacturer)
System.Windows.Data警告:104:BindingExpression(hash = 43478430):使用訪問器RuntimePropertyInfo(SelectedManufacturer)用ManipulationViewModel(hash = 11088040)替換級別1的項
System.Windows.Data警告:101:BindingExpression(hash = 43478430):使用RuntimePropertyInfo(SelectedManufacturer)從ManipulationViewModel(hash = 11088040)處於級別1的GetValue:制造商(hash = 14500136)
System.Windows.Data警告:80:BindingExpression(哈希= 43478430):TransferValue-獲取原始值制造商(哈希= 14500136)
System.Windows.Data警告:84:BindingExpression(哈希= 43478430):TransferValue-隱式轉換器產生的制造商(哈希= 14500136)
System.Windows.Data警告:89:BindingExpression(哈希= 43478430):TransferValue-使用最終值制造商(哈希= 14500136)
更新4:
制造商類別:
public class Manufacturer : Base.SqlBase {
public Manufacturer(int id, string name) {
this.SqlID = id;
this.Name = name;
}
}
SqlBase類:
public abstract class SqlBase : INotifyPropertyChanged {
public int SqlID { get; set; }
private string _name;
public string Name {
get {
return _name;
}
protected set {
this._name = value;
PropertyChangedHandler("Name");
}
}
public void SetId(int id) {
this.SqlID = id;
PropertyChangedHandler("SqlID");
}
private void PropertyChangedHandler(string propertyName) {
PropertyChangedEventHandler temp = PropertyChanged;
if (temp != null) {
temp(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
實體類別:
public class Entity : Base.SqlBase {
public string Description { get; private set; }
public string Remark { get; private set; }
public int Value { get; private set; }
public Model.CategoryWrapper Categories { get; private set; }
public Model.Manufacturer Manufacturer { get; private set; }
public Model.Locker Locker { get; private set; }
public Entity(string name, string desc, string remark, int value, Model.CategoryWrapper cat, Model.Manufacturer manuf, Model.Locker locker) {
this.Name = name;
this.Description = desc;
this.Remark = remark;
this.Value = value;
this.Categories = cat;
this.Manufacturer = manuf;
this.Locker = locker;
}
public Entity(int id, string name, string desc, string remark, int value, Model.CategoryWrapper cat, Model.Manufacturer manuf, Model.Locker locker) {
this.SqlID = id;
this.Name = name;
this.Description = desc;
this.Remark = remark;
this.Value = value;
this.Categories = cat;
this.Manufacturer = manuf;
this.Locker = locker;
}
}
我得到GridView(類型:實體)的SelectedItem,並將其交給實例化ViewModel的Manipulation-View。 在此ViewModel中,將實體划分為各個部分(例如,制造商),並設置屬性(例如,SelectedManufacturer)。 所有這些步驟都在構建View 之前 (在Initializecomponent之前)執行。 我認為以這種方式,視圖必須在初始化時獲取選定的值-還是我錯了?
更新5:
我真的不知道為什么,但是在窗口初始化時設置制造商時,制造商對象的PropertyChanged-Property為null-當我通過選擇一項設置制造商時,屬性不為null。
在綁定中使用更新源觸發器屬性,並將其設置為PropertyChanged:
<ComboBox x:Name="_cmbManufacturer" ItemsSource="{Binding MVM.ManufacturerCollection}" DisplayMemberPath="Name" SelectedItem="{Binding MVM.SelectedManufacturer, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
Howsit Chill-X,我是否正確理解核心問題是更新視圖模型時希望組合框反映更改后的選擇? 如果是這樣,這是您如何做到的精簡版本。
重要注意事項(將所選項目綁定到另一個名為SelectedCategory的屬性。當您在VM中更改SelectedCategory時,UI將會更改,並且如果您在組合框中選擇新項目,則SelectedCategory屬性將被更新。
這是視圖模型:
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<Category> _categoryLinkCollection;
public ObservableCollection<Category> CategoryLinkCollection
{
get
{
return this._categoryLinkCollection;
}
set
{
if (value != this._categoryLinkCollection)
{
this._categoryLinkCollection = value;
OnPropertyChanged("CategoryLinkCollection");
}
}
}
private Category _selectedCategory;
public Category SelectedCategory
{
get
{
return this._selectedCategory;
}
set
{
this._selectedCategory = value;
OnPropertyChanged("SelectedCategory");
}
}
}
這是xaml:
<ComboBox ItemsSource="{Binding CategoryLinkCollection, Mode=TwoWay}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" />
我只是使用了頁面后面的代碼將虛擬數據添加到集合中(在window_loaded上,單擊按鈕以顯示可以更新VM屬性和UI更新。
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Set the View's DataContext to our ViewModel
var vm = new ViewModel();
this.DataContext = new ViewModel();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Populate Category Collection with dummy data.
var vm = ((ViewModel)this.DataContext);
vm.CategoryLinkCollection = new ObservableCollection<Category>()
{
new Category("Cat 1"),
new Category("Cat 2"),
new Category("Cat 3"),
new Category("Cat 4"),
new Category("Cat 5"),
new Category("Cat 6"),
};
vm.SelectedCategory = vm.CategoryLinkCollection[0];
}
private void btn_Click(object sender, RoutedEventArgs e)
{
var vm = ((ViewModel)this.DataContext);
vm.SelectedCategory = vm.CategoryLinkCollection[3];
}
}
現在,您有了一個從VM和UI更新的ComboBox。
似乎我已經解決了這個難題。
說明:
應該預先選擇實體給定的ComboBox-Value的“ Manipulation”-視圖將接收它自己的ObservableCollection實例-但是Manufacturer-Object被傳遞給該表單-因此它不包含在Collection中。
解:
重寫Equals-Method來檢查SQLID屬性,而不是通過默認方法來確定相等性可以解決此問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.