如何在C#中改变一个ComboBox的itemsSource [英] How to change the itemsSource of a ComboBox in C#

查看:3753
本文介绍了如何在C#中改变一个ComboBox的itemsSource的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图在运行时更改 comboBox itemsSource 此问题中,我被告知要做, comboBox.itemssource ... 。如果所有我需要做的是创建一个新的 comboBox 然后调用命令就可以了。但是,我需要在我的用户控制通过xaml中已经存在的组合框上执行此操作。在这种情况下,我将如何引用它?我知道如何绑定到控件中的属性,但在这种情况下,我需要获得整个控制。我过度思考吗?



这是我目前正在切换 comboBox中的集合(这一切都在模型级别):

  //组合框列表的属性
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);
}
}
}

实现,但是 comboBox 中的 selectedItem 不会坚持。例如,当我点击一个不同的命令,然后切换回来,该框不再有 selectedItem



UPDATE



我有一个名为 selectedOperation 的属性绑定到我的 comboBox 。它包含一个简单的getter和setter,带有 NotifyPropertyChange 。这使得框中的 selectedItem 保持选中状态。但是,如果用户点击不同的命令并在 comboBox 中选择了一个不同的项目,那么该新项目就是它的地方。我需要能够为 comboBox 拥有的每个集合设置 selectedItem



例如:



我们假设 listBox 中有两个命令和B.每个在 comboBox 中创建不同的集合。 A创建一个数字集合,B创建一个名称集合。



对于命令A,用户选择5.当选择A时, 应显示5,因为它 selectedItem 。 A - > 5



对于命令B,用户选择Roger。当选择B时, comboBox 应显示Roger,因为它 selectedItem 。 B - > Roger



目前, comboBox 不记得它的 selectedItem

code>并更新该源,而不是手动更新 ComboBox.ItemsSource 属性。





这里是一个小例子:



当用户点击按钮,您只需更新您的数据,而不是显示它的控件。

 < Window x:Class =WpfApplication10.MainWindow
xmlns =http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http: /schemas.microsoft.com/winfx/2006/xaml
Title =MainWindowHeight =350Width =525x:Name =Window1>
< Grid DataContext ={Binding ElementName = Window1}>
< StackPanel>
< Button Click =Button_Click>一些数据1< / Button>
< Button Click =Button_Click_1>一些数据2< / Button>
< ListBox x:Name =ComboBox1ItemsSource ={Binding Collection}>< / ListBox>
< / StackPanel>
< / Grid>
< / Window>





 使用System.Collections .ObjectModel; 
使用System.Windows;

namespace WpfApplication10
{
///< summary>
/// MainWindow.xaml的交互逻辑
///< / summary>
public partial class MainWindow:Window
{
private readonly ObservableCollection< string> _collection = new ObservableCollection< string>();

public MainWindow()
{
InitializeComponent();
}

public ObservableCollection< string>集合
{
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);
}
}
}
}

strong>更新



如果要使用新集合而不是删除项目,则必须为集合实现INotifyPropertyChanged。

 使用System.Collections.ObjectModel; 
using System.ComponentModel;
using System.Runtime.CompilerServices;
使用System.Windows;

namespace WpfApplication10
{
///< summary>
/// MainWindow.xaml的交互逻辑
///< / summary>
public partial class MainWindow:Window,INotifyPropertyChanged
{
private ObservableCollection< string> _collection = new ObservableCollection< string>();

public MainWindow()
{
InitializeComponent();
}

public ObservableCollection< string>集合
{
get {return _collection; }
set
{
if(Equals(value,_collection))return;
_collection = value;
OnPropertyChanged();
}
}

公共事件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));
}
}
}

注意: [CallerMemberName] 保存您在每次调用invocator时添加属性名称,但只有在.NET 4.5中才能正确记录。



如果您不在.NET 4.5下,则必须改为 OnPropertyChanged(Collection)



参考: INotifyPropertyChanged



此外,更新集合使用新集合,而不是 _collection UI不会通知。



编辑2



您需要根据所使用的集合追踪所选项目。

 < Window x:Class =WpfApplication10.MainWindow
xmlns =http:// schemas。 microsoft.com/winfx/2006/xaml/presentation
xmlns:x =http://schemas.microsoft.com/winfx/2006/xaml
Title =MainWindowHeight =350 Width =525x:Name =Window1>
< Grid>
< StackPanel>
< Button Click =Button_Click>一些数据1< / Button>
< Button Click =Button_Click_1>一些数据2< / Button>
< ListBox x:Name =ComboBox1ItemsSource ={Binding}SelectedItem ={Binding MySelectedItem}/>
< / StackPanel>
< / Grid>
< / Window>

代码背后:

  using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.ComponentModel;
使用System.Windows;

命名空间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;组; }

public MyCustomCollection< string> MyCustomCollection2 {get;组; }

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


I am trying to change the itemsSource of a comboBox at run-time. In this question I was told to do, comboBox.itemssource.... That would be okay if all I needed to do was create a new comboBox and then call the command on it. However, I need to perform this operation on a comboBox that 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?

This how I am currently switching the Collections in the comboBox (This is all at the model level):

//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 selectedItem in the comboBox doesn't stick. For example, when I click on a different command and then switch back, the box no longer has a selectedItem.

UPDATE

I have a property called selectedOperation that is bound to my comboBox. It contains a simple getter and setter, with a NotifyPropertyChange. This makes it so that the selectedItem in 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 selectedItem for each collection that the comboBox holds.

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.

For command A the user selects 5. When A is selected the comboBox should display 5 as it's selectedItem. A -> 5

For command B the user selectes Roger. When B is selected the comboBox should display "Roger" as it's selectedItem. B -> Roger

Currently, the comboBox does not remember it's selectedItem when the user switches between commands.

解决方案

I would rather use a DataContext and update that source than manually updating a ComboBox.ItemsSourceproperty.

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.

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.

If you are not under .NET 4.5 then you'll have to put OnPropertyChanged("Collection") instead.

Reference : INotifyPropertyChanged

Also, update Collection with a new collection, not _collection otherwise your UI won't be notified.

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

这篇关于如何在C#中改变一个ComboBox的itemsSource的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆