Хорошо работа с WPF некоторое время, но я нуждаюсь в некоторой помощи.
У меня есть a ComboBox
как ниже:
<TabControl>
<TabItem Header="1">
<ComboBox ItemsSource="{Binding MyList}" SelectedItem="{Binding MyListSelection}"/>
</TabItem>
<TabItem Header="2"/>
</TabControl>
Каждый раз, когда я переезжаю от вкладки 1 и затем возвращаюсь к ней, выбор удален. Я думаю, что причина этого состоит в том, что средства управления уничтожаются, когда они выходят из объема и затем обратно в. Но в процессе, из которого SelectedItem становится пустым, который не является действительно, что хотел пользователь, это - событие из-за жизненного цикла UI.
Таким образом, я задаюсь вопросом, что состоит в том, чтобы взять оптимальный маршрут? Я создаю это приложение с MVVM, таким образом, я мог проигнорировать вызов аппарата на Свойстве MyListSelection в моем ViewModel, но я имею ComboBoxes повсеместно и не люблю изменять свой ViewModel для того, что я рассматриваю ошибкой WPF.
Я мог разделить WPF ComboBox на подклассы, но нет никакого события SelectedItemChanging, я могу только добавить обработчик когда измененный SelectedItem.
Какие-либо идеи?
ОБНОВЛЕНИЕ:
Хорошо, после избиения моей головы против стены я узнал, почему моя проблема не могла быть воспроизведена. Если тип элемента списка является классом по некоторым причинам, SelectedItem установлен 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, чтобы ввести интервал и пойти назад и вперед между вкладками SelectedItem остается таким же. Но когда это имеет тип TestViewModel
SelectedTest устанавливается в NULL, когда tabitem идет не в фокусе.
Что продолжается?
У меня точно такая же проблема, и до сих пор я не мог понять, в чем проблема. Я тестировал на 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 на выставке. Когда вы связываете ваш класс ViewModel, который содержит MyList (связанные элементыSource) и MyLiSelection (BOND для вызова в вашем случае) всегда будет иметь эту информацию, даже если вы пошли на разные вкладки. Поэтому, когда вы вернетесь к этой вкладке, MyLiSelection будет связывать обратно в Comboboc.SelecedItem снова, и вы будете хорошими. Попробуйте это и дайте мне знать.
Я думаю, что это может быть решено простым нулевым чеком.
public TestViewModel SelectedTest
{
get { return _SelectedTest; }
set
{
if(value != null)
_SelectedTest = value;
OnPropertyChanged("SelectedTest");
}
}
Это связано с тем, что Combobox имеет тенденцию сбросить его выбранный индекс при переработании. Этот простой нулевой проверка заставит его перекоснуться к последнему действительному элементу.
Отредактировано после изменения в ОП. Привет, Хосе, я не могу воспроизвести ошибку, которую вы упоминаете. Таким образом, ваше предположение о разрушении контроля неправильно. 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;
}
}
}