【问题标题】:WPF Combobox not updating when collection is changed更改集合时 WPF 组合框不更新
【发布时间】:2013-11-03 04:39:43
【问题描述】:

我是 WPF 新手。

我正在尝试将字符串集合绑定到组合框。

public ObservableCollection<string> ListString {get; set;}

Binding和datacontext设置如下

<Window 
        x:Class="Assignment2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:validators="clr-namespace:Assignment2"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525"
        DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}">
    <Grid>
        <ComboBox  Height="23" HorizontalAlignment="Left" Margin="109,103,0,0" Name="StringComboBox" VerticalAlignment="Top" Width="120" SelectionChanged="StringComboBox_SelectionChanged">
            <ComboBox.ItemsSource>
                <Binding Path="ListString" BindsDirectlyToSource="True" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"></Binding>
            </ComboBox.ItemsSource>
        </ComboBox>

我知道这是因为收藏正在更新。如果我写

public MainWindow()
        {

            InputString = "";
            ListString = new ObservableCollection<string>();
            ListString.Add("AAA");
            ListString.Add("BBB");
            ListString.Add("CCC");
          InitializeComponent();

        }

它确实有效,但如果我将InitializeComponent() 移动到第一行上方,如下所示,它不起作用。

  public MainWindow()
            {
               InitializeComponent();
                InputString = "";
                ListString = new ObservableCollection<string>();
                ListString.Add("AAA");
                ListString.Add("BBB");
                ListString.Add("CCC");                
            }

我该怎么办??

【问题讨论】:

  • 一个有效,另一个无效。我会选择可行的选项。
  • @Blam 我试图概括这个问题以解决我的另一个问题,其中列表来自 WCF 服务。您仍然建议使用可行的选项吗??

标签: c# wpf binding combobox observablecollection


【解决方案1】:

如果您将代码更改为会发生什么

<Window 
    x:Class="Assignment2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:validators="clr-namespace:Assignment2"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ComboBox  Height="23" HorizontalAlignment="Left" Margin="109,103,0,0" Name="StringComboBox" VerticalAlignment="Top" Width="120" SelectionChanged="StringComboBox_SelectionChanged"
               ItemsSource="{Binding ListString, Mode=OneWay}"/>

cs.

  public MainWindow()
        {
           InitializeComponent();
            InputString = "";
            ListString = new ObservableCollection<string>();
            ListString.Add("AAA");
            ListString.Add("BBB");
            ListString.Add("CCC"); 

           this.DataContext=this;    
      }           

顺便说一句:使用 mode=twoway 设置 ItemsSource 对我来说毫无意义。您的组合框永远不会为您的视图模型“创建新的项目源”。

编辑: 我认为您的第一个解决方案之所以有效,是因为在 xaml 中设置了 DataContext。我假设调用 InitializeComponent(); 时执行 DataContext="{Binding RelativeSource={RelativeSource Self}, Path=.}"并且因为您的 ListString 属性只是一个自动属性并且没有实现 INotifyPropertyChanged - 您的主窗口视图不会收到通知您的 ctor 创建了一个新的 ListString 属性。

  public ObservableCollection<string> ListString {get{return _list;}; set{_list=value; OnPropertyChanged("ListString");}}

应该使用您的两种方法,但您必须为您的 MainWindow 类实现 INotifyPropertyChanged。

【讨论】:

  • 我知道这是因为,当 InitializeComponent 被调用时,它会将该控件绑定到该特定对象引用,并且当引用本身发生更改时,它就不起作用了。
  • 如果你想设置 liststring=new OberservableCollection 不止一次,你必须为你的班级实现 INotifyPropertyChanged。 InitializeComponent() 的问题;分别 this.DataContext=this;看我的编辑
【解决方案2】:

您可以在后面的代码中设置组合框的项目源,或者在填充列表后再次设置数据上下文,或者您可以使用 inotifychanged 来引发属性更改。

public MainWindow()
        {
            InitializeComponent();
            InputString = "";
            ListString = new ObservableCollection<string>();
            ListString.Add("AAA");
            ListString.Add("BBB");
            ListString.Add("CCC");
            StringComboBox.ItemsSource = ListString;

        }

【讨论】:

  • 你确定你添加了 StringComboBox.ItemsSource = ListString;在你的代码中。它应该工作。我已经测试了我的结果和它的工作原理。
  • 对不起,它正在工作,但你不认为我应该通过 XAML 进行绑定
【解决方案3】:

解决了这个问题。实现 INotifyPropertyChanged 如下

public partial class MainWindow : Window, INotifyPropertyChanged

修改访问器如下

    private ObservableCollection<string> listString;
    public ObservableCollection<string> ListString 
    {
        get
        {
            return listString;
        }
        set
        {
            listString = value;
            NotifyPropertyChanged("ListString"); // method implemented below
        }
    }

并添加了以下事件和方法来引发事件

public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string name)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this,new PropertyChangedEventArgs(name));
    }
}

它有效 B)

【讨论】:

    【解决方案4】:

    在我看来,问题是“更新”ListString。使其成为属性(选定的答案)是解决此问题的一种方法。或者内联实例化,或者将它放在InitializeComponent 之前,我相信可以。

    如果预计会经常更新,将ObservableCollection 封装在管理器类中可能会有所帮助。在使用这种设置解决我自己的问题后,我发现了这个问题。我通过实现INotifyCollectionChanged 并像这样转发事件来让它工作

    /// <summary>
    /// Maintains an observable (i.e. good for binding) collection of resources that can be indexed by name or alias
    /// </summary>
    /// <typeparam name="RT">Resource Type: the type of resource associated with this collection</typeparam>
    public class ResourceCollection<RT> : IEnumerable, INotifyCollectionChanged
        where RT : class, IResource, new()
    {
        public event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add { Ports.CollectionChanged += value; }
            remove { Ports.CollectionChanged -= value; }
        }
    
        public IEnumerator GetEnumerator() { return Ports.GetEnumerator(); }
    
        private ObservableCollection<RT> Ports { get; set; }
        private Dictionary<string, RT> ByAlias { get; set; }
        private Dictionary<string, RT> ByName { get; set; }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-11-27
      • 1970-01-01
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 2011-11-08
      • 1970-01-01
      • 2015-01-11
      • 2011-03-30
      相关资源
      最近更新 更多