WPF ComboBox SelectedItem
Ok работает с WPF некоторое время, но мне нужна помощь.
у меня есть ComboBox
, как показано ниже:
<TabControl>
<TabItem Header="1">
<ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/>
</TabItem>
<TabItem Header="2"/>
</TabControl>
всякий раз, когда я удаляюсь от вкладки 1, а затем возвращаюсь к ней, выбор удаляется. Я думаю, причина этого в том, что элементы управления разрушаются, когда они выходят из поля зрения, а затем возвращаются. Но в процессе этого SelectedItem становится null, что на самом деле не то, что хотел пользователь, это событие из-за жизненного цикла пользовательского интерфейса.
так что я интересно, какой маршрут лучше всего выбрать? Я создаю это приложение с MVVM, чтобы я мог игнорировать вызов set на свойстве MyListSelection в моей ViewModel, но у меня есть ComboBoxes повсюду и мне не нравится изменять мою ViewModel для того, что я считаю ошибкой WPF.
Я мог бы подкласс WPF ComboBox, но нет события SelectedItemChanging я могу добавить только обработчик при изменении SelectedItem.
какие идеи?
обновление:
ладно, после ударившись головой о стену, я понял, почему моя проблема не может быть воспроизведена. Если тип элемента списка по какой-то причине является классом, SelectedItem получает значение null от WPF, но если это тип значения, это не так.
вот мой тестовый класс(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 получает значение null, когда tabitem выходит из фокуса.
что происходит?
7 ответов
У меня точно такая же проблема, и до сих пор я не мог понять в чем проблема. Я тестировал на 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>
Я бы рекомендовал проверить привязки. Если что-то еще в вашем приложении изменяет выбранный элемент или источник элементов, ваша привязка будет нарушена. Вы также можете посмотреть в Visual Studio в окне вывода, чтобы увидеть, если есть какие-либо ошибки.
Я думаю, что вам может не хватать здесь TwoWay привязки к SelectedItem. Когда вы привязываете свой класс ViewModel, который содержит MyList(связанный ItemsSource) и MyListSelection (связь с SelectedItem в вашем случае), всегда будет иметь эту информацию, даже если вы перешли на другие вкладки. Поэтому, когда вы вернетесь на эту вкладку, MyListSelection будет привязываться к ComboBoc.SelectedItem снова, и вы будете хорошо. Попробуй и дай мне знать.
отредактировано после изменения в OP. Привет, Хосе, я не могу воспроизвести ошибку, которую вы упомянули. Таким образом, ваше предположение об уничтожении контроля неверно. 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;
}
}
}
Я думаю, что это можно решить с помощью простой проверки null.
public TestViewModel SelectedTest
{
get { return _SelectedTest; }
set
{
if(value != null)
_SelectedTest = value;
OnPropertyChanged("SelectedTest");
}
}
это потому, что ComboBox имеет тенденцию сбрасывать свой SelectedIndex при рециркуляции. Эта простая проверка null заставит его повторно привязаться к последнему допустимому элементу.
У меня была точно такая же проблема со ссылочным типом в моем списке. Решение состояло в том, чтобы переопределить Equals() в моем TestViewModel, чтобы WPF мог выполнить проверку равенства значений (вместо проверки ссылки) между объектами, чтобы определить, какой из них является SelectedItem. У моего было поле ID, которое действительно было идентифицирующей особенностью TestViewModel.
Это поведение с помощью combobox должно быть реализовано компилятором лучше, чем есть... Т. е. компилятор должен проверить и посмотреть, будут ли типы для ItemsSource и ссылочное значение типа свойства, к которому привязан SelectedItem, когда-либо возвращать сопоставимое значение
Он должен предупредить, что вы можете рассмотреть возможность переопределения методов Equals() и GetHashCode ()...
потратил много времени на это сегодня !!