【问题标题】:WPF - MVVM - ComboBox SelectedItemWPF - MVVM - ComboBox SelectedItem
【发布时间】:2012-06-19 05:02:03
【问题描述】:

我在后台有ViewModel(实现INotifyPropertyChanged) 和类Category,它只有一个string 类型的属性。我的 ComboBox SelectedItem 绑定到类别的实例。当我更改实例的值时,SelectedItem 没有被更新,Combobox 也没有被改变。

编辑:代码

组合框:

<ComboBox x:Name="categoryComboBox" Grid.Column="1"  Grid.Row="3" Grid.ColumnSpan="2" 
          Margin="10" ItemsSource="{Binding Categories}"
          DisplayMemberPath="Name" SelectedValue="{Binding NodeCategory, Mode=TwoWay}"/>

属性:

private Category _NodeCategory;
public Category NodeCategory
{
    get
    {
        return _NodeCategory;
    }
    set
    {
        _NodeCategory = value;
        OnPropertyChanged("NodeCategory");
    }
}

[Serializable]
public class Category : INotifyPropertyChanged
{
    private string _Name;
    [XmlAttribute("Name")]
    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            _Name = value;
            OnPropertyChanged("Name");
        }
    }

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    [field:NonSerialized]
    public event PropertyChangedEventHandler PropertyChanged;
}

而我正在尝试的是:当我设置时

NodeCategory = some_list_of_other_objects.Category;

使用适当的DisplayMemberPathCombobox 中选择该项目

【问题讨论】:

  • 你能贴一些代码吗,尤其是xaml
  • 是否绑定 SelectedItem 属性而不是选定值?
  • 尝试将更新源触发器添加到您的绑定 UpdateSourceTrigger=PropertyChanged
  • 我再次编辑了帖子,最后有解释。
  • 已经试过了:)没有成功:/因为我改变了后端的值

标签: c# .net wpf data-binding mvvm


【解决方案1】:

您的 XAML 需要进行一些修改,但我认为真正的问题在于您发布的代码,我认为这并不能说明全部情况。 对于初学者,您的组合框 ItemSource 绑定到名为 Categories 的属性,但您没有显示此属性是如何编码的,或者您的 NodeCategory 属性最初是如何与项目同步的。

尝试使用以下代码,您将看到所选项目在用户更改组合框中的值时保持同步。

XAML

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<StackPanel>
    <ComboBox x:Name="categoryComboBox"
              Grid.Column="1"
              Grid.Row="3"
              Grid.ColumnSpan="2"
              Margin="10"
              ItemsSource="{Binding Categories}"
              DisplayMemberPath="Name"
              SelectedItem="{Binding NodeCategory}" />
    <Label Content="{Binding NodeCategory.Name}" />
</StackPanel>

代码隐藏

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private ObservableCollection<Category> _categories = new ObservableCollection<Category>
    {
        new Category { Name = "Squares"},
        new Category { Name = "Triangles"},
        new Category { Name = "Circles"},
    };

    public MainWindow()
    {
        InitializeComponent();
        NodeCategory = _categories.First();
        this.DataContext = this;
    }

    public IEnumerable<Category> Categories
    {
        get { return _categories; }
    }

    private Category _NodeCategory;
    public Category NodeCategory
    {
        get
        {
            return _NodeCategory;
        }
        set
        {
            _NodeCategory = value;
            OnPropertyChanged("NodeCategory");
        }
    }

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

[Serializable]
public class Category : INotifyPropertyChanged
{
    private string _Name;
    [XmlAttribute("Name")]
    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            _Name = value;
            OnPropertyChanged("Name");
        }
    }

    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    [field: NonSerialized]
    public event PropertyChangedEventHandler PropertyChanged;
}

【讨论】:

  • 这个阶段的项目不可能给UI添加逻辑,抱歉。但是 tnx 的答案。投赞成票:)
  • 这个答案让我能够如此 +1。对于一个从头到尾的例子,我在这里写了一篇博客:technical-recipes.com/2017/…
【解决方案2】:

你在这一行设置的类别-

NodeCategory = some_list_of_other_objects.Category;

您的 Categories 集合中的一个 (ItemsSource="{Binding Categories}") 应该指的是同一个对象。如果不是,那么SelectedItem 将不起作用。

解决方案 1 -

你也可以尝试像这样使用SelectedValuePath -

<ComboBox x:Name="categoryComboBox" 
          ItemsSource="{Binding Categories}"
          DisplayMemberPath="Name" 
          SelectedValuePath="Name" 
          SelectedValue="{Binding NodeCategory, Mode=TwoWay}" />

在代码中你可以做这样的事情-

private string _NodeCategory;
public string NodeCategory
{
    get
    {
        return _NodeCategory;
    }
    set
    {
        _NodeCategory = value;
        OnPropertyChanged("NodeCategory");
    }
}

并像这样设置所选项目 -

NodeCategory = some_list_of_other_objects.Category.Name;

并像这样使用选定的值 -

Category selectedCategory = 
   some_list_of_other_objects.FirstOrDefault(cat=> cat.Name == NodeCategory);

Category selectedCategory = 
   Categories.FirstOrDefault(cat=> cat.Name == NodeCategory);

解决方案 2 -

另一种可能的解决方案是 -

NodeCategory = 
  Categories.FirstOrDefault(cat=> cat.Name == some_list_of_other_objects.Category.Name);

这样,您的NodeCategory 属性将具有Categories 集合中对象的引用,并且SelectedItem 将起作用。

【讨论】:

  • 这正是我现在想发布的内容。
  • 让我再解释一下。我有类别列表。类别1,类别2...等。我在它附近有一个数据网格,我单击了数据网格行。好的。现在,当我点击它时,其他所有内容都填充了它的数据(我有几个文本框)但组合框选定的项目是空白的
  • @PredragPejic 以防您的 ComboBox 和 DataGrid 是两个不同的列表,拥有不同的对象然后使用 SelectedValuePath 将是一个不错的选择。
  • 是的,使用对象时DisplayMemberPath是必不可少的
  • “应该是指同一个对象”拯救我的一天!感谢您的信息。
【解决方案3】:

从我的小例子:

注意:这只是设置一个字符串(或另一个列表中的一个类别),但这里的基础应该是相同的:

基本上就是这样:

private void button1_Click(object sender, RoutedEventArgs e)
{
    (this.DataContext as ComboBoxSampleViewModel).SelectCategory("Categorie 4");
}

这是我的 XAML:

<Grid>
    <ComboBox Height="23" HorizontalAlignment="Left" Margin="76,59,0,0"   
              Name="comboBox1" VerticalAlignment="Top" Width="120" 
              ItemsSource="{Binding List.Categories}" 
              DisplayMemberPath="Name" 
              SelectedValue="{Binding NodeCategory, Mode=TwoWay}" />
    <Button Content="Button" Height="27" HorizontalAlignment="Left" 
            Margin="76,110,0,0" Name="button1" VerticalAlignment="Top" 
            Width="120" Click="button1_Click" />
</Grid>

在Window的ViewModel中

class ComboBoxSampleViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    public CategoryList List { get; set; }

    public ComboBoxSampleViewModel()
    {
        this.List = new CategoryList();
        NodeCategory = List.Selected;
    }

    private ComboBoxSampleItemViewModel nodeCategory;
    public ComboBoxSampleItemViewModel NodeCategory
    {
        get
        {
            return nodeCategory;
        }
        set
        {
            nodeCategory = value;
            NotifyPropertyChanged("NodeCategory");
        }
    }

    internal void SelectCategory(string p)
    {
        this.List.SelectByName(p);
        this.NodeCategory = this.List.Selected;
    }
}

在这个小课堂的帮助下:

public class CategoryList
{
    public ObservableCollection<ComboBoxSampleItemViewModel> Categories { get; set; }
    public ComboBoxSampleItemViewModel Selected { get; set; }
    public CategoryList()
    {
        Categories = new ObservableCollection<ComboBoxSampleItemViewModel>();

        var cat1 = new ComboBoxSampleItemViewModel() { Name = "Categorie 1" };
        var cat2 = new ComboBoxSampleItemViewModel() { Name = "Categorie 2" };
        var cat3 = new ComboBoxSampleItemViewModel() { Name = "Categorie 3" };
        var cat4 = new ComboBoxSampleItemViewModel() { Name = "Categorie 4" };

        Categories.Add(cat1);
        Categories.Add(cat2);
        Categories.Add(cat3);
        Categories.Add(cat4);

        this.Selected = cat3;
    }

    internal void SelectByName(string p)
    {
        this.Selected = this.Categories.Where(s => s.Name.Equals(p)).FirstOrDefault();
    }
}

还有这个 Item ViewModel

public class ComboBoxSampleItemViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged(string info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }

    private string name;

    public string Name 
    { 
        get
        {
            return name;
        }
        set
        {
            name = value;
            NotifyPropertyChanged("Name");
        }
    }
}

【讨论】:

  • 好的,没问题。据我所知,解决方案非常相似
【解决方案4】:

如果 Combobox 绑定到 View Model 的对象类,而发送者对象的 SelectionBoxItem(在后面代码中的 SelectionChanged 中)没有该类型,则表示它仍在加载。

ComboBox combo = sender as ComboBox;
if (combo.SelectionBoxItem.GetType() == typeof(BindedClass))
{
            // Not loading
}

【讨论】:

    猜你喜欢
    • 2017-02-20
    • 2014-03-18
    • 2010-10-14
    • 2011-01-10
    • 2016-09-25
    • 1970-01-01
    • 2015-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多