【问题标题】:WPF ComboBox - binding to IsEditable in different thread is not consistentWPF ComboBox - 在不同线程中绑定到 IsEditable 不一致
【发布时间】:2014-07-29 02:10:16
【问题描述】:

我需要根据字典中作为ItemsSource传入的item的存在来设置ComboBox.IsEditable的值。

字典项设置在与 UI 线程不同的线程中。

我正在尝试使用以下 ComboBox 来实现:

<local:IsDictionaryNullOrEmptyConverter x:Key="isDictionaryNullOrEmptyConverter" />
...
<ComboBox IsEditable="{Binding MyItemsDictionary, Converter={StaticResource ResourceKey=isDictionaryNullOrEmptyConverter}, Mode=OneWay}"
    ItemsSource="{Binding MyItemsDictionary}">
<ComboBox>

还有以下转换器:

internal class IsDictionaryNullOrEmptyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        IDictionary dic = (IDictionary)value;
        if (dic == null || dic.Count == 0)
            return true;
        return false;
    }
}

问题是转换器中接收到的值有时是空字典,尽管它肯定有项目(ComboBox 中有项目)。

此外,还有两个具有相同行为的 ComboBox 控件。他们两个在同一个线程中接收不同的字典作为 ItemsSource,其中一个在转换器中获得一个空值,另一个获得一个完整的值。

【问题讨论】:

  • 每次字典中的项目数发生变化时,您是否使用全新的字典更新MyItemsDictionary 属性?如果不是,那么当这种情况发生时,UI 将不会收到通知。在这种情况下,您最好使用合适的转换器绑定到MyItemsDictionary.Count,并确保您的字典实现INotifyPropertyChanged
  • 我确实使用了 MyItemsDictionary.Add,我将其切换为更新属性,效果很好!
  • 您并不能真正控制进程绑定的顺序。它可以在有值之前评估 IsEditable,然后再次不命中。我不知道答案,这就是为什么这是评论。我会有一个布尔属性 IsEditable,你称之为 INPC。
  • Blam,我希望这种能力对于任何组合框的字典绑定都是通用的。因此,每个组合框的布尔值都不是一个好的解决方案。谢谢

标签: c# wpf binding combobox converter


【解决方案1】:

我创建了一个示例解决方案,它按预期工作。 IsEditable 属性总是在 ItemsSource属性更新时更新。

我的观点

<Window x:Class="MultipleDataGrid.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">
    <StackPanel>
        <ComboBox ItemsSource="{Binding SourceOne, Mode=OneWay}" IsEditable="{Binding SourceOne, Converter={StaticResource Converter}, UpdateSourceTrigger=PropertyChanged}"/>
        <ComboBox ItemsSource="{Binding SourceTwo, Mode=OneWay}" IsEditable="{Binding SourceOne, Converter={StaticResource Converter}, UpdateSourceTrigger=PropertyChanged}"/>
    </StackPanel>
</Window>

代码隐藏

using System.Windows;

namespace MultipleDataGrid
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new ViewModel();
        }
    }
}

我的视图模型

using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace MultipleDataGrid
{
    public class ViewModel : INotifyPropertyChanged
    {

        private static readonly object _lockOne = new object();
        private static readonly object _lockTwo = new object();

        private Dictionary<string, string> _sourceOne;

        public Dictionary<string, string> SourceOne
        {
            get { return _sourceOne; }
        }

        private Dictionary<string, string> _sourceTwo;

        public Dictionary<string, string> SourceTwo
        {
            get { return _sourceTwo; }
        }

        public ViewModel()
        {
            _sourceOne = new Dictionary<string, string>();
            _sourceTwo = new Dictionary<string, string>();
            BindingOperations.EnableCollectionSynchronization(_sourceOne, _lockOne); //Thread safety
            BindingOperations.EnableCollectionSynchronization(_sourceTwo, _lockTwo); //Thread safety

            //To delay the addition of the items to the dictionary and then raise a property changed at last after the task is executed
            Task.Run(async () => await LoadDictionary()).ContinueWith(t =>
                {
                    MessageBox.Show("Task Ran");
                    if (t.IsCompleted)
                    {
                        RaisePropertyChanged("SourceOne");
                        RaisePropertyChanged("SourceTwo");
                    }
                });
        }

        private async Task LoadDictionary()
        {
            Thread.Sleep(5000);
            await Task.Run(() =>
            {
                _sourceOne.Add("KeyOneOne", "ValueOne");
                _sourceOne.Add("KeyOneTwo", "ValueTwo");
                _sourceOne.Add("KeyOneThree", "ValueThree");
                _sourceOne.Add("KeyOneFour", "ValueFour");
                _sourceOne.Add("KeyOneFive", "ValueFive");
            });

            await Task.Run(() =>
            {
                _sourceTwo.Add("KeyTwoOne", "ValueOne");
                _sourceTwo.Add("KeyTwoTwo", "ValueTwo");
                _sourceTwo.Add("KeyTwoThree", "ValueThree");
                _sourceTwo.Add("KeyTwoFour", "ValueFour");
                _sourceTwo.Add("KeyTwoFive", "ValueFive");
            });


        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propName)
        {
            var pc = PropertyChanged;
            if (pc != null)
                pc(this, new PropertyChangedEventArgs(propName));
        }

    }
}

我按原样使用了您使用的转换器。我将资源定义移至App.xaml

<Application.Resources>
    <ResourceDictionary>
        <local:IsDictionaryNullOrEmptyConverter x:Key="Converter"/>
    </ResourceDictionary>
</Application.Resources>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 1970-01-01
    • 2010-10-12
    • 2010-10-24
    • 2013-04-18
    • 2015-11-16
    • 2013-01-23
    相关资源
    最近更新 更多