简体   繁体   English

将ComboBox TwoWay绑定到属性

[英]Binding ComboBox TwoWay to Property

I'm trying to get my TwoWay-Binding to work. 我正在尝试使用双向绑定。

These ComboBoxes should bind themselve (TwoWay) to their property in the VM: 这些组合框应将它们自己(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: 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");
    }
}

Notice that the DataType of the ItemsSource is "CategoryLinkCollection" which Contains a "Category"-Property and an Obs.Collection of "CategoryLinkCollection". 请注意,ItemsSource的数据类型是“ CategoryLinkCollection”,其中包含“ Category”-属性和Obs.Collection“ CategoryLinkCollection”。 Through the SelectedValuePath the "Category" gets "saved" in the Property in the VM. 通过SelectedValuePath,“类别”在VM的属性中“保存”。

As long as I select an Item in the ComboBox everything just works fine but when I set the VM-Properties manually the ComboBoxes won't preselect the Item from the ItemsSource which contains the defined Category. 只要我在ComboBox中选择一个项目,一切就可以正常工作,但是当我手动设置VM属性时,ComboBox不会从包含定义类别的ItemsSource中预选该项目。 Normal string values just work finde (Textboxes) 普通的字符串值只能用于finde(文本框)

I assume it will never work because of the differen types (ComboBox = CategoryLinkCollection with ValuePath to Category, Property = Category) but maybe some of you could prove me wrong. 我认为由于类型不同(ComboBox = CategoryLinkCollection,ValuePath到Category,Property = Category),它将永远无法工作,但也许有些人可以证明我错了。 If you need more informations let me know. 如果您需要更多信息,请告诉我。

Update 1: 更新1:

I just remembered that the main reason should be somewhere else because the Model "Manufacturer" got no wrapper - so the ItemsSource contains a Collection of the same data type as the property is. 我只是记得主要的原因应该在其他地方,因为“制造商”模型没有包装器-因此ItemsSource包含与属性相同的数据类型的Collection。

XAML: XAML:

<ComboBox x:Name="_cmbManufacturer" 
          ItemsSource="{Binding MVM.ManufacturerCollection}" 
          DisplayMemberPath="Name" 
          SelectedItem="{Binding MVM.SelectedManufacturer, Mode=TwoWay}"/>

VM: see above. VM:见上文。

Update 2: 更新2:

At first please get away from that crappy Categorys and head over to the Manufacturer mentioned in Update 1 because it's the same issue but much easier to get in. 首先,请远离那些糟糕的类别,而转到Update 1中提到的制造商,因为这是相同的问题,但是更容易进入。

I now checked the SelectedManufacturer-Property after setting it manually just in case there would be some problems while setting it. 我现在在手动设置之后检查了SelectedManufacturer-Property,以防万一设置时出现问题。 The SelectedManufacturer-Property contains a Manufacturer (not null) but still the UI does not get updated. SelectedManufacturer-Property包含制造商(不为null),但UI仍未更新。

Update 3: 更新3:

I've got the following output out of the Output-Window after using the diagnostics NS: 使用诊断NS之后,我从“输出窗口”中获得了以下输出:

System.Windows.Data Warning: 60 : BindingExpression (hash=43478430): Default mode resolved to TwoWay System.Windows.Data警告:60:BindingExpression(哈希= 43478430):默认模式解析为TwoWay

System.Windows.Data Warning: 61 : BindingExpression (hash=43478430): Default update trigger resolved to PropertyChanged System.Windows.Data警告:61:BindingExpression(哈希= 43478430):默认更新触发器已解析为PropertyChanged

System.Windows.Data Warning: 62 : BindingExpression (hash=43478430): Attach to System.Windows.Controls.ComboBox.SelectedItem (hash=10372298) System.Windows.Data警告:62:BindingExpression(哈希= 43478430):附加到System.Windows.Controls.ComboBox.SelectedItem(哈希= 10372298)

System.Windows.Data Warning: 67 : BindingExpression (hash=43478430): Resolving source System.Windows.Data警告:67:BindingExpression(hash = 43478430):解析源

System.Windows.Data Warning: 70 : BindingExpression (hash=43478430): Found data context element: ComboBox (hash=10372298) (OK) System.Windows.Data警告:70:BindingExpression(哈希= 43478430):找到数据上下文元素:ComboBox(哈希= 10372298)(确定)

System.Windows.Data Warning: 78 : BindingExpression (hash=43478430): Activate with root item Manipulation (hash=64100268) System.Windows.Data警告:78:BindingExpression(哈希= 43478430):激活与根项操纵(哈希= 64100268)

System.Windows.Data Warning: 107 : BindingExpression (hash=43478430): At level 0 using cached accessor for Manipulation.MVM: RuntimePropertyInfo(MVM) System.Windows.Data警告:107:BindingExpression(hash = 43478430):在级别0使用缓存的访问器进行操作。MVM:RuntimePropertyInfo(MVM)

System.Windows.Data Warning: 104 : BindingExpression (hash=43478430): Replace item at level 0 with Manipulation (hash=64100268), using accessor RuntimePropertyInfo(MVM) System.Windows.Data警告:104:BindingExpression(hash = 43478430):使用访问器RuntimePropertyInfo(MVM)将级别0的项替换为Manipulation(hash = 64100268)

System.Windows.Data Warning: 101 : BindingExpression (hash=43478430): GetValue at level 0 from Manipulation (hash=64100268) using RuntimePropertyInfo(MVM): ManipulationViewModel (hash=11088040) System.Windows.Data警告:101:BindingExpression(hash = 43478430):使用RuntimePropertyInfo(MVM)从操作(hash = 64100268)在级别0上的GetValue:ManipulationViewModel(hash = 11088040)

System.Windows.Data Warning: 108 : BindingExpression (hash=43478430): At level 1 - for ManipulationViewModel.SelectedManufacturer found accessor RuntimePropertyInfo(SelectedManufacturer) System.Windows.Data警告:108:BindingExpression(哈希= 43478430):在级别1-对于ManipulationViewModel.SelectedManufacturer找到访问器RuntimePropertyInfo(SelectedManufacturer)

System.Windows.Data Warning: 104 : BindingExpression (hash=43478430): Replace item at level 1 with ManipulationViewModel (hash=11088040), using accessor RuntimePropertyInfo(SelectedManufacturer) System.Windows.Data警告:104:BindingExpression(hash = 43478430):使用访问器RuntimePropertyInfo(SelectedManufacturer)用ManipulationViewModel(hash = 11088040)替换级别1的项

System.Windows.Data Warning: 101 : BindingExpression (hash=43478430): GetValue at level 1 from ManipulationViewModel (hash=11088040) using RuntimePropertyInfo(SelectedManufacturer): Manufacturer (hash=14500136) System.Windows.Data警告:101:BindingExpression(hash = 43478430):使用RuntimePropertyInfo(SelectedManufacturer)从ManipulationViewModel(hash = 11088040)处于级别1的GetValue:制造商(hash = 14500136)

System.Windows.Data Warning: 80 : BindingExpression (hash=43478430): TransferValue - got raw value Manufacturer (hash=14500136) System.Windows.Data警告:80:BindingExpression(哈希= 43478430):TransferValue-获取原始值制造商(哈希= 14500136)

System.Windows.Data Warning: 84 : BindingExpression (hash=43478430): TransferValue - implicit converter produced Manufacturer (hash=14500136) System.Windows.Data警告:84:BindingExpression(哈希= 43478430):TransferValue-隐式转换器产生的制造商(哈希= 14500136)

System.Windows.Data Warning: 89 : BindingExpression (hash=43478430): TransferValue - using final value Manufacturer (hash=14500136) System.Windows.Data警告:89:BindingExpression(哈希= 43478430):TransferValue-使用最终值制造商(哈希= 14500136)

Update 4: 更新4:

Manufacturer Class: 制造商类别:

public class Manufacturer : Base.SqlBase {
    public Manufacturer(int id, string name) {
        this.SqlID = id;
        this.Name = name;
    }
}

SqlBase Class: 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;
}

Entity Class: 实体类别:

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

I get the SelectedItem of a GridView (Type: Entity) and hand it over to my Manipulation-View which instantiates it's ViewModel. 我得到GridView(类型:实体)的SelectedItem,并将其交给实例化ViewModel的Manipulation-View。 In this ViewModel the Entity gets divided into it's parts (eg. Manufacturer) and the properties (eg. SelectedManufacturer) get set. 在此ViewModel中,将实体划分为各个部分(例如,制造商),并设置属性(例如,SelectedManufacturer)。 All these steps get executed before the View gets built (before Initializecomponent). 所有这些步骤都构建View 之前 (在Initializecomponent之前)执行。 I thought in this way the View has to get the selected values when initialised - or am I wrong? 我认为以这种方式,视图必须在初始化时获取选定的值-还是我错了?

Update 5: 更新5:

I really don't know why but when setting a Manufacturer when the Window is initialising the PropertyChanged-Property of the Manufacturer object is null - when I set the Manufacturer through selecting an item the Property is not null. 我真的不知道为什么,但是在窗口初始化时设置制造商时,制造商对象的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, Do I understand correctly that the core issue is that you want the Combo boxes to reflect the changed selection when you update your viewModel? Howsit Chill-X,我是否正确理解核心问题是更新视图模型时希望组合框反映更改后的选择? If so, here's a watered down version of how you can do that. 如果是这样,这是您如何做到的精简版本。

Important things to note (Binding the selected item to another property called SelectedCategory . When you change SelectedCategory in the VM, the UI will change and if you select a new item in the combo box, the SelectedCategory property will be updated. 重要注意事项(将所选项目绑定到另一个名为SelectedCategory的属性。当您在VM中更改SelectedCategory时,UI将会更改,并且如果您在组合框中选择新项目,则SelectedCategory属性将被更新。

Here's the View Model: 这是视图模型:

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

Here's the xaml: 这是xaml:

<ComboBox ItemsSource="{Binding CategoryLinkCollection, Mode=TwoWay}" DisplayMemberPath="Name" SelectedItem="{Binding SelectedCategory, Mode=TwoWay}" />

I've simply used the code behind page to add dummy data to the collection (on window_loaded and the button click to show you can update the VM property and UI updates. 我只是使用了页面后面的代码将虚拟数据添加到集合中(在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];
    }
}

Now you've got a ComboBox which updates from VM and from UI. 现在,您有了一个从VM和UI更新的ComboBox。

Seems like I've solved the mystery. 似乎我已经解决了这个难题。

Explanation: 说明:

The "Manipulation"- View, which should pre-select the ComboBox-Value given by the Entity will receive it's own instance of the ObservableCollection - but the Manufacturer-Object gets passed to that form - so it's not contained in the Collection. 应该预先选择实体给定的ComboBox-Value的“ Manipulation”-视图将接收它自己的ObservableCollection实例-但是Manufacturer-Object被传递给该表单-因此它不包含在Collection中。

Solution: 解:

Overriding the Equals-Method to check the SQLID Property rather than the default method to determine equality solved the problem. 重写Equals-Method来检查SQLID属性,而不是通过默认方法来确定相等性可以解决此问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM