WPF ComboBox SelectedItem - PullRequest
       20

WPF ComboBox SelectedItem

7 голосов
/ 28 января 2010

Хорошо, некоторое время работал с WPF, но мне нужна помощь.

У меня есть ComboBox, как показано ниже:

<TabControl>
    <TabItem Header="1">
        <ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/>
    </TabItem>
    <TabItem Header="2"/>
</TabControl>

Всякий раз, когда я отхожу от вкладки 1, а затем возвращаюсь к ней, выбор удаляется. Я думаю, что причина в том, что элементы управления разрушаются, когда они выходят из области видимости, а затем возвращаются обратно. Но в процессе этого SelectedItem становится нулевым, что на самом деле не то, что хотел пользователь, это событие из-за пользовательского интерфейса Жизненный цикл.

Так что мне интересно, какой маршрут лучше выбрать? Я создаю это приложение с MVVM, чтобы я мог игнорировать вызов set для свойства MyListSelection в моей ViewModel, но у меня есть ComboBox повсюду, и мне не нравится изменять мою ViewModel для того, что я считаю ошибкой WPF.

Я мог бы создать подкласс WPF ComboBox, но события SelectedItemChanging не существует, я могу добавить обработчик только при изменении SelectedItem.

Есть идеи?

UPDATE:

Хорошо, после того, как я ударился головой о стену, я понял, почему моя проблема не может быть воспроизведена. Если по какой-либо причине тип элемента списка является классом, то в WPF для SelectedItem устанавливается значение null, но если это тип значения, это не так.

вот мой тестовый класс (VMBase - это просто абстрактный класс, который реализует INotifyPropertyChanged):

public class TestListViewModel : VMBase
{
    public TestListViewModel()
    {
        TestList = new List<TestViewModel>();
        for (int i = 0; i < 10; i++)
        {
            TestList.Add(new TestViewModel(i.ToString()));
        }
    }

    public List<TestViewModel> TestList { get; set; }

    TestViewModel _SelectedTest;
    public TestViewModel SelectedTest
    {
        get { return _SelectedTest; }
        set
        {
            _SelectedTest = value;
            OnPropertyChanged("SelectedTest");
        }
    }
}

public class TestViewModel : VMBase
{
  public string Name {get;set;}
}

Поэтому, когда я изменяю TestList на тип int и перехожу между вкладками, SelectedItem остается неизменным. Но когда он имеет тип TestViewModel SelectedTest устанавливается в ноль, когда табайт выходит из фокуса.

Что происходит?

Ответы [ 7 ]

10 голосов
/ 07 мая 2010

У меня точно такая же проблема, и до сих пор я не мог понять, в чем проблема. Я тестировал на 4 разных машинах с одной и той же ОС, версией .Net и спецификациями оборудования и мог воспроизвести проблему на двух из них, на других работал просто отлично. Обходной путь, который я смог найти для меня, это определить привязку SelectedItem перед ItemsSource. Странно, если я следую этому шаблону, все работает как положено. Тем не менее, вы просто должны сделать следующее:

<Window x:Class="ComboBoxInTabItemSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TabControl>
            <TabItem Header="1">
                <ComboBox SelectedItem="{Binding MySelect}" ItemsSource="{Binding MyList}"/>
            </TabItem>
            <TabItem Header="2"/>
        </TabControl>
        <TextBlock Text="{Binding MySelect}"/>
    </StackPanel>
</Window>
0 голосов
/ 26 июля 2011

Это поведение с помощью комбинированного списка должно быть реализовано компилятором лучше, чем оно есть ... IE компилятор должен проверить и посмотреть, являются ли типы для ItemsSource и значение ссылки на тип свойства, которым SelectedItem является обязан будет когда-либо вернуть значение, которое сопоставимо

Следует предупредить, что вы можете рассмотреть возможность переопределения методов Equals () и GetHashCode () ...

Сегодня потратил на это много времени !!

0 голосов
/ 11 ноября 2010

У меня была точно такая же проблема с типом ссылки в моем списке. Решением было переопределить Equals () в моем TestViewModel, чтобы WPF мог выполнять проверку на равенство значений (вместо проверки ссылок) между объектами, чтобы определить, какой из них является SelectedItem. У меня случилось, что в поле идентификатора действительно была функция идентификации TestViewModel.

0 голосов
/ 29 января 2010

Я думаю, что это можно решить с помощью простой нулевой проверки.

public TestViewModel SelectedTest
{
    get { return _SelectedTest; }
    set
    {
        if(value != null)
            _SelectedTest = value;
        OnPropertyChanged("SelectedTest");
    }
}

Это потому, что ComboBox имеет тенденцию сбрасывать свой SelectedIndex при переработке. Эта простая проверка на ноль заставит его выполнить повторную привязку к последнему действительному элементу.

0 голосов
/ 28 января 2010

Я думаю, что вам может не хватать здесь привязки TwoWay к SelectedItem. Когда вы связываете свой класс ViewModel, который содержит MyList (связанный ItemsSource) и MyListSelection (Bond to SelectedItem в вашем случае), всегда будет эта информация, даже если вы переходили на разные вкладки. Поэтому, когда вы вернетесь к этой вкладке, MyListSelection снова свяжется с ComboBoc.SelectedItem, и у вас все будет хорошо. Попробуйте и дайте мне знать.

0 голосов
/ 28 января 2010

Я бы порекомендовал проверить привязки. Если что-то еще в вашем приложении меняет выбранный элемент или источник элементов, то ваша привязка будет нарушена. Вы также можете посмотреть в окне вывода в окне вывода, чтобы увидеть, есть ли какие-либо ошибки.

0 голосов
/ 28 января 2010

ИЗМЕНЕНО после изменения в ОП. Привет, Хосе, я не могу воспроизвести ошибку, о которой ты упоминал. Таким образом, ваше предположение об уничтожении Контроля неверно. Combobox работает, как и ожидалось, с кодом ниже, даже теперь он использует ссылочный тип. Некоторые другие части вашего кода должны срабатывать при изменении TabItems.

<Window x:Class="ComboBoxInTabItemSpike.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TabControl>
            <TabItem Header="1">
                <ComboBox ItemsSource="{Binding MyList}"
                          SelectedItem="{Binding MySelect}"/>
            </TabItem>
            <TabItem Header="2"/>
        </TabControl>
        <TextBlock Text="{Binding MySelect}"/>
    </StackPanel>
</Window>

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

namespace ComboBoxInTabItemSpike
{
    public partial class Window1 : Window, INotifyPropertyChanged
    {
        public Window1()
        {
            InitializeComponent();
            MyList=new ObservableCollection<TestObject>(
                new[]{new TestObject("1"),new TestObject("2"),new TestObject("3") });
            DataContext = this;
        }

        public ObservableCollection<TestObject> MyList { get; set; }

        private TestObject mySelect;
        public TestObject MySelect
        {
            get { return mySelect; }
            set{ mySelect = value;
            if(PropertyChanged!=null)
                PropertyChanged(this,new PropertyChangedEventArgs("MySelect"));} 
        }

        public TestObject MySelectedItem
        {
            get { return (TestObject)GetValue(MySelectedItemProperty); }
            set { SetValue(MySelectedItemProperty, value); }
        }

        public static readonly DependencyProperty MySelectedItemProperty =
            DependencyProperty.Register("MySelectedItem",
                                typeof(TestObject),
                                typeof(Window1),
                                new UIPropertyMetadata(null));

        public event PropertyChangedEventHandler PropertyChanged;
    }

    public class TestObject
    {
        public string Name { get; set; }

        public TestObject(string name)
        {
            Name = name;
        }

        public override string ToString()
        {
            return Name;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...