Поле со списком WPF не отображает правильное значение после обновления источника привязки - PullRequest
3 голосов
/ 11 января 2011

Я использую комбинированный список 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 , чтобы это происходило в потоке пользовательского интерфейса, тогда это будет работать, например:

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 Ответ

1 голос
/ 11 января 2011

Это может помочь

 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"));

        }
    }

Проверьте здесь , чтобы узнать больше

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...