wpf 如何在 C# 中更改 ComboBox 的 itemsSource
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19189623/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to change the itemsSource of a ComboBox in C#
提问by Eric after dark
I am trying to change the itemsSourceof a comboBoxat run-time. In this questionI was told to do, comboBox.itemssource.... That would be okay if all I needed to do was create a new comboBoxand then call the command on it. However, I need to perform this operation on a comboBoxthat already exists in my User Control through xaml. In that case, how would I reference it? I know how to bind to properties in the control, but in this case I would need to get the whole control. Am I over-thinking it? What is the best way to do what I'm thinking?
我正在尝试在运行时更改itemsSourcea 的comboBox。在这个问题中,我被告知要做,comboBox.itemssource...。如果我需要做的只是创建一个新的comboBox,然后在其上调用命令,那就没问题了。但是,我需要comboBox通过 xaml 对用户控件中已存在的一个执行此操作。在这种情况下,我将如何引用它?我知道如何绑定到控件中的属性,但在这种情况下,我需要获取整个控件。是我想多了?做我所想的最好方法是什么?
This how I am currently switching the Collections in the comboBox(This is all at the model level):
这是我目前如何切换集合中的comboBox(这都是在模型级别):
//Property for Combo Box List
public ObservableCollection<string> ComboBoxList
{
get { return _comboBoxList; }
set
{
if (Equals(value, _comboBoxList)) return;
_comboBoxList = value;
OnPropertyChanged("ComboBoxList");
}
}
public string SelectedCommand
{
get { return _selectedCommand; }
set
{
_selectedCommand = value;
NotifyPropertyChange(() => SelectedCommand);
if (SelectedCommand == "String Value")
{
ComboBoxList = new ObservableCollection<string>(newList);
}
}
}
The collections switch when using this implementation, but the selectedItemin the comboBoxdoesn't stick. For example, when I click on a different command and then switch back, the box no longer has a selectedItem.
使用此实现时集合切换,但selectedItemincomboBox不坚持。例如,当我单击不同的命令然后切换回来时,该框不再有selectedItem.
UPDATE
更新
I have a property called selectedOperationthat is bound to my comboBox. It contains a simple getter and setter, with a NotifyPropertyChange. This makes it so that the selectedItemin the box stays selected. BUT, if the user clicks on a different command and selects a different item in the comboBox, that new item takes it's place. I need to be able to have a selectedItemfor each collection that the comboBoxholds.
我有一个名为的属性selectedOperation绑定到我的comboBox. 它包含一个简单的 getter 和 setter,带有NotifyPropertyChange. 这使得selectedItem框中的 保持选中状态。但是,如果用户单击不同的命令并在 中选择不同的项目,则comboBox该新项目将取而代之。我需要能够selectedItem为每个集合comboBox拥有一个。
For example:
例如:
Let's say there are 2 commands in the listBox, A and B. Each create a different collection in the comboBox. A creates a collection of numbers, and B creates a collection of names.
假设有 2 个命令listBox,A 和 B。每个在comboBox. A 创建了一个数字集合,B 创建了一个名称集合。
For command A the user selects 5. When A is selected the comboBoxshould display 5 as it's selectedItem. A -> 5
For command A the user selects 5. When A is selected the comboBoxshould display 5 as it's selectedItem. A -> 5
For command B the user selectes Roger. When B is selected the comboBoxshould display "Roger" as it's selectedItem. B -> Roger
对于命令 B,用户选择 Roger。当 B 被选择时,comboBox应该显示“Roger”,因为它是selectedItem。B -> 罗杰
Currently, the comboBoxdoes not remember it's selectedItemwhen the user switches between commands.
目前,comboBox它不记得selectedItem用户在命令之间切换的时间。
回答by Aybe
I would rather use a DataContextand update that source than manually updating a ComboBox.ItemsSourceproperty.
我宁愿使用DataContext并更新该源而不是手动更新ComboBox.ItemsSource属性。
This way there would be no need to know about the controls at all.
这样就完全不需要了解控件了。
Here is a small example :
这是一个小例子:
When the user clicks the button, you just take care of updating your data, not the controls presenting it.
当用户单击按钮时,您只需负责更新数据,而不是呈现数据的控件。
<Window x:Class="WpfApplication10.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" x:Name="Window1">
<Grid DataContext="{Binding ElementName=Window1}">
<StackPanel>
<Button Click="Button_Click">Some data 1</Button>
<Button Click="Button_Click_1">Some data 2</Button>
<ListBox x:Name="ComboBox1" ItemsSource="{Binding Collection}"></ListBox>
</StackPanel>
</Grid>
</Window>
using System.Collections.ObjectModel;
using System.Windows;
namespace WpfApplication10
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private readonly ObservableCollection<string> _collection = new ObservableCollection<string>();
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<string> Collection
{
get { return _collection; }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
_collection.Clear();
for (int i = 0; i < 5; i++)
{
_collection.Add("method 1 item " + i);
}
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{ _collection.Clear();
for (int i = 0; i < 5; i++)
{
_collection.Add("method 2 item " + i);
}
}
}
}
Update
更新
If you want to use a new collection instead of removing items, you will have to implement INotifyPropertyChanged for the collection.
如果要使用新集合而不是删除项目,则必须为该集合实现 INotifyPropertyChanged。
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApplication10
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<string> _collection = new ObservableCollection<string>();
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<string> Collection
{
get { return _collection; }
set
{
if (Equals(value, _collection)) return;
_collection = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void Button_Click(object sender, RoutedEventArgs e)
{
Collection = new ObservableCollection<string>(new[] {"1", "2"});
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
Collection = new ObservableCollection<string>(new[] {"3", "4"});
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Note: the [CallerMemberName]saves you from adding the property name each time you invoke the invocator but it's only for .NET 4.5 if I remember correctly.
注意:[CallerMemberName]每次调用调用器时都可以避免添加属性名称,但如果我没记错的话,它仅适用于 .NET 4.5。
If you are not under .NET 4.5 then you'll have to put OnPropertyChanged("Collection")instead.
如果您不在 .NET 4.5 下,那么您必须OnPropertyChanged("Collection")改为使用。
Reference : INotifyPropertyChanged
Also, update Collectionwith a new collection, not _collectionotherwise your UI won't be notified.
此外,Collection使用新集合进行更新,_collection否则您的 UI 将不会收到通知。
EDIT 2
编辑 2
You need to track the selected item according the collection used.
您需要根据使用的集合跟踪所选项目。
<Window x:Class="WpfApplication10.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" x:Name="Window1">
<Grid>
<StackPanel>
<Button Click="Button_Click">Some data 1</Button>
<Button Click="Button_Click_1">Some data 2</Button>
<ListBox x:Name="ComboBox1" ItemsSource="{Binding}" SelectedItem="{Binding MySelectedItem}" />
</StackPanel>
</Grid>
</Window>
Code behind :
背后的代码:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace WpfApplication10
{
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
MyCustomCollection1 = new MyCustomCollection<string>(new[] {"a", "b"});
MyCustomCollection2 = new MyCustomCollection<string>(new[] {"c", "d"});
}
public MyCustomCollection<string> MyCustomCollection1 { get; set; }
public MyCustomCollection<string> MyCustomCollection2 { get; set; }
private void Button_Click(object sender, RoutedEventArgs e)
{
DataContext = MyCustomCollection1;
}
private void Button_Click_1(object sender, RoutedEventArgs e)
{
DataContext = MyCustomCollection2;
}
}
public class MyCustomCollection<T> : ObservableCollection<T>
{
private T _mySelectedItem;
public MyCustomCollection(IEnumerable<T> collection) : base(collection)
{
}
public T MySelectedItem
{
get { return _mySelectedItem; }
set
{
if (Equals(value, _mySelectedItem))return;
_mySelectedItem = value;
OnPropertyChanged(new PropertyChangedEventArgs("MySelectedItem"));
}
}
}
}
回答by makc
try changing the collection via style using some trigger (can be any trigger data/event) here is an example:
尝试使用一些触发器(可以是任何触发器数据/事件)通过样式更改集合,这是一个示例:
<Style x:Key="MySelectItemSourceStyle" TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Collection1}" />
<Style.Triggers>
<DataTrigger Binding="{Binding SomeValue}" Value="SecondCollection">
<Setter Property="ItemsSource" Value="{Binding Collection2}" />
</DataTrigger>
</Style.Triggers>
</Style>

