在 DropDownOpened 事件上设置的 WPF ComboBox 绑定列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18111670/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 09:23:14  来源:igfitidea点击:

WPF ComboBox Bound List set on DropDownOpened Event

c#wpfbindingcombobox

提问by Luke

My problem is that the ComboBoxis not displaying the value stored in its bound list.

我的问题是ComboBox没有显示存储在其绑定列表中的值。

Here is what I'm doing:

这是我在做什么:

WPF:

WPF:

<ComboBox ItemsSource="{Binding Devices}" 
  DropDownOpened="deviceSelector_DropDownOpened"/>

Note that my Window's DataContextis {Binding RelativeSource={RelativeSource Self}}.

请注意,我WindowDataContext{Binding RelativeSource={RelativeSource Self}}.

C# code-behind:

C# 代码隐藏:

public List<String> Devices { get; set; }

private void deviceSelector_DropDownOpened(object sender, EventArgs e)
{
  // the actual population of the list is occuring in another method 
  // as a result of a database query. I've confirmed that this query is
  // working properly and Devices is being populated.
  var dev = new List<String>();
  dev.Add("Device 1");
  dev.Add("Device 2");

  Devices = dev;
} 

I have tried doing this with an ObservableCollectioninstead of a List, and I've also tried using a PropertyChangedEventHandler. Neither of these approaches have worked for me.

我试过用 aObservableCollection代替 a来做这件事List,我也试过使用 a PropertyChangedEventHandler。这些方法都不适合我。

Any idea why my items aren't being displayed when I click the dropdown?

知道为什么单击下拉菜单时我的项目没有显示吗?

回答by Abe Heidebrecht

Since you're doing this in code behind anyway, why not set the ComboBox.ItemsSourcedirectly.

既然你在后面的代码中这样做,为什么不ComboBox.ItemsSource直接设置。

Now, I am not going to say this is the way it shouldbe done in WPF (I would prefer the view's data to be loaded in a ViewModel), but it will solve your issue.

现在,我不会说这是应该在 WPF 中完成的方式(我更喜欢将视图的数据加载到 ViewModel 中),但它会解决您的问题。

The reason why this isn't working is because your property doesn't inform the binding system when it changes. I know you said you tried it with PropertyChangedEventHandler, but that won't work unless your Viewlooks like this:

这不起作用的原因是因为您的属性在更改时不会通知绑定系统。我知道你说过你用 尝试过PropertyChangedEventHandler,但除非你View看起来像这样否则那是行不通的:

public class MyView : UserControl, INotifyPropertyChanged
{
    private List<String> devices;

    public event PropertyChangedEventHandler PropertyChanged;

    public List<String> Devices
    {
        get { return devices; }
        set 
        {
            devices = value;
            // add appropriate event raising pattern
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("Devices"));
        }
    }

    ...
}

Likewise, using an ObservableCollectionwould only work like this:

同样,使用 anObservableCollection只会像这样工作:

private readonly ObservableCollection<string> devices = new ObservableCollection<string>();

public IEnumerable<string> Devices { get { return devices; } }

private void deviceSelector_DropDownOpened(object sender, EventArgs e)
{
    devices.Clear();
    devices.Add("Device 1");
    devices.Add("Device 2");
} 

Either method should populate the ComboBox, and in a quick test I just ran, it worked.

任何一种方法都应该填充ComboBox,并且在我刚刚运行的快速测试中,它起作用了。

Edit to add DependencyPropertymethod

编辑添加DependencyProperty方法

One last way you can do this is with a DependencyProperty(as your Viewis a DependencyObject:

您可以执行此操作的最后一种方法是使用 a DependencyProperty(因为您View是 a DependencyObject

public class MyView : UserControl
{
    public static readonly DependencyProperty DevicesProperty = DependencyProperty.Register(
      "Devices",
      typeof(List<string>),
      typeof(MainWindow),
      new FrameworkPropertyMetadata(null));

    public List<string> Devices
    {
        get { return (List<string>)GetValue(DevicesProperty); }
        set { SetValue(DevicesProperty, value); }
    }

    ...
}

回答by Luke

The following change (suggested by Abe Heidebrecht) fixed the problem, but I don't know why. Anyone willing to lend an explanation?

以下更改(由 Abe Heidebrecht 建议)解决了该问题,但我不知道为什么。有愿意帮忙解释的吗?

WPF:

WPF:

<ComboBox DropDownOpened="deviceSelector_DropDownOpened"
  Name="deviceSelector"/>

C# code-behind:

C# 代码隐藏:

private void deviceSelector_DropDownOpened(object sender, EventArgs e)
{
  var dev = new List<String>();
  dev.Add("Device 1");
  dev.Add("Device 2");

  deviceSelector.ItemsSource = dev;
} 

回答by gmn

Unless I'm missing something here:

除非我在这里遗漏了什么:

Try firing OnPropertyChanged when devices gets updated for the devices property, this should fix this. I have occasionally also had to set the mode:

尝试在设备更新设备属性时触发 OnPropertyChanged,这应该可以解决此问题。我偶尔也不得不设置模式:

ItemsSource="{Binding Devices, Mode=TwoWay}"

On some controls.

在某些控件上。

Setting the itemssource on the control directly tells the control to use new items directly, without using the binding hooked up in the xaml. Updating the Devices property on the datacontext does not tell the combobox that the Devices property has changed so it won't update. The way to inform the combobox of the change is to fire OnPropertyChanged for the devices property when it gets changed.

在控件上设置 itemssource 直接告诉控件直接使用新项目,而不使用在 xaml 中挂钩的绑定。更新数据上下文上的 Devices 属性不会告诉组合框 Devices 属性已更改,因此不会更新。通知组合框更改的方法是在设备属性更改时触发 OnPropertyChanged。