更新绑定源后,WPF组合框不显示正确的值

时间:2011-01-11 02:11:12

标签: wpf combobox binding

我正在使用WPF组合框,并且我注意到在更新绑定源之后组合框没有显示正确的绑定值的问题,而源本身正在从绑定更新过程中。

我已经汇总了一个简单的例子来证明这一点。在这个例子中,我有一个包含4个项目的组合框(字符串“A”,“B”,“C”和“D”)。组合框上的 SelectedItem 与datacontext上名为 ComboSelectedItem 的属性之间存在双向绑定。

预期的功能是如果用户从组合框中选择“A”,“B”或“C”,则datacontext中的逻辑将尝试将组合框上的选择重置为“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上是否有设置/属性或其他方法可以解决这个问题?感谢。

1 个答案:

答案 0 :(得分: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了解更多