【问题标题】:WPF combobox not displaying correct value after updating binding source更新绑定源后 WPF 组合框未显示正确的值
【发布时间】:2011-06-06 21:55:09
【问题描述】:

我正在使用 WPF 组合框,我注意到一个问题,即在更新绑定源后组合框未显示正确的绑定值,而源本身正在从绑定中更新。

我已经整理了一个简单的示例来演示这一点。在此示例中,我有一个包含 4 个项目(字符串“A”、“B”、“C”和“D”)的组合框。组合框上的 SelectedItem 与数据上下文中名为 ComboSelectedItem 的属性之间存在双向绑定。

预期的功能是,如果用户从组合框中选择“A”、“B”或“C”,则数据上下文中的逻辑将尝试将组合框上的选择重置为“D”。 但是,如果用户从组合框中选择“A”,则选择仍然在“A”上。

下面是示例代码:

MainWindow.xaml:

<Window x:Class="Testing.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" DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>

    <Label Grid.Row="0" Grid.Column="0" Margin="10,10,10,10">Combobox test:</Label>
    <ComboBox Grid.Row="0" Grid.Column="1" Margin="10,10,10,10" x:Name="comboBox"
              ItemsSource="{Binding Path=ComboBoxItems}" Width="80"
              SelectedItem="{Binding Path=ComboSelectedItem, Mode=TwoWay}"/>

        </Grid>
</Window>

及其背后的代码:

using System;
using System.Windows;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading;
using System.Windows.Threading;

namespace Testing
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private ObservableCollection<String> items;
        public ObservableCollection<String> ComboBoxItems
        {
            get
            {
                if (items == null)
                {
                    items = new ObservableCollection<string>();
                    items.Add("A");
                    items.Add("B");
                    items.Add("C");
                    items.Add("D");
                }

                return items;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private string comboSelectedItem;
        public string ComboSelectedItem
        {
            get { return comboSelectedItem; }
            set
            {
                comboSelectedItem = value;

                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("ComboSelectedItem"));

                //if value != D, set to D
                if (ComboSelectedItem != "D")
                {
                     ComboSelectedItem = "D";
                }
            }
        }
    }
}

我发现如果我将 ComboSelectedItem 集排队以便它发生在 UI 线程上,那么这将起作用,例如

public string ComboSelectedItem
    {
        get { return comboSelectedItem; }
        set
        {
            comboSelectedItem = value;

            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs("ComboSelectedItem"));

            //if value != D, set to D
            if (ComboSelectedItem != "D")
            {
                ThreadPool.QueueUserWorkItem(delegate(Object theElement)
                {
                    UIElement elem = (UIElement)theElement;
                    elem.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)delegate()
                        {
                            ComboSelectedItem = "D";
                        });
                }, comboBox);
            }
        }
    }

但是,我不完全确定为什么会这样,而且无论如何我不希望对我的应用程序中可能发生这种情况的所有组合框都这样做。

相反,Combobox 上是否有设置/属性或其他可以为我解决此问题的方法?谢谢。

【问题讨论】:

    标签: wpf combobox binding


    【解决方案1】:

    这会有所帮助

     private string comboSelectedItem;
        public string ComboSelectedItem
        {
            get { return comboSelectedItem; }
            set
            {
                var origValue = "D";
    
                if (value == comboSelectedItem)
                    return;
    
                comboSelectedItem = value;
                //if value != D, set to D
                if (ComboSelectedItem != "D")
                {
                    // change the value back, but do so after the 
                    // UI has finished it's current context operation.
                    Application.Current.Dispatcher.BeginInvoke(
                            new Action(() =>
                            {
                                comboSelectedItem = origValue;
                                if (PropertyChanged != null)
                                    PropertyChanged(this, new PropertyChangedEventArgs("ComboSelectedItem"));
                            }), DispatcherPriority.ContextIdle, null);
                    // Exit early. 
                    return;
                }
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs("ComboSelectedItem"));
    
            }
        }
    

    查看here了解更多信息

    【讨论】:

    • 谢谢 biju。我希望避免做类似的事情,但这可能是目前唯一的解决方案。感谢您发布链接 - 它让我更好地了解它的工作原理/原因。
    猜你喜欢
    • 2023-03-28
    • 1970-01-01
    • 2012-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-21
    • 2011-11-27
    相关资源
    最近更新 更多