Graeme_Grant
Вот решение MVVM, которое отключает элементы в другом Combobox, когда выбор сделан в одном...
Во первых привязка данных событие сантехника базовые классы:
public abstract class ObservableBase : INotifyPropertyChanged
{
public void Set<TValue>(ref TValue field, TValue newValue,
[CallerMemberName] string propertyName = "")
{
if (!EqualityComparer<TValue>.Default.Equals(field, default(TValue))
&& field.Equals(newValue)) return;
field = newValue;
RaisePropertyChanged(propertyName);
}
public void RaisePropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler PropertyChanged;
}
public abstract class ViewModelBase : ObservableBase
{
public bool IsInDesignMode
=> (bool)DesignerProperties.IsInDesignModeProperty
.GetMetadata(typeof(DependencyObject))
.DefaultValue;
}
Далее модель, представляющая данные:
public class PersonModel : ObservableBase, IDataModel
{
private string name;
public string Name
{
get => name;
set => Set(ref name, value);
}
}
Затем создается оболочка ViewModel для модели, представляющей состояние элемента. Это используется для включения/отключения элементов ComboBox.
public class ItemViewModel : ViewModelBase
{
public IDataModel Model { get; set; }
private bool isEnabled = true;
public bool IsEnabled
{
get => isEnabled;
set => Set(ref isEnabled, value);
}
}
Теперь MainViewModel для обработки данных и выбора/изменения состояния...
public class MainViewModel : ViewModelBase
{
public ObservableCollection<ItemViewModel> List1 { get; }
= new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> List2 { get; }
= new ObservableCollection<ItemViewModel>();
private ItemViewModel list1SelectedItem;
public ItemViewModel List1SelectedItem
{
get => list1SelectedItem;
set
{
Set(ref list1SelectedItem, value);
UpdateSelections(List1, value);
}
}
private ItemViewModel list2SelectedItem;
public ItemViewModel List2SelectedItem
{
get => list2SelectedItem;
set
{
Set(ref list2SelectedItem, value);
UpdateSelections(List2, value);
}
}
public MainViewModel() => InitData();
private void InitData()
{
for (int i = 0; i < 10; i++)
{
var model = new PersonModel()
{
Name = "Person " + i,
};
List1.Add(new ItemViewModel()
{
Model = model
});
List2.Add(new ItemViewModel()
{
Model = model
});
}
}
private void UpdateSelections(IList<ItemViewModel> list, ItemViewModel itemVM)
{
var dest = list.Equals(List1) ? List2 : List1;
if (itemVM == null)
{
foreach (var item in dest)
{
item.IsEnabled = true;
}
}
else
{
foreach (var item in dest)
{
item.IsEnabled = item.Model.Equals(itemVM.Model) != true;
}
}
}
}
Наконец, представление (интерфейс).
<Window x:Class="ComboBoxDisableItem.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:l="clr-namespace:ComboBoxDisableItem"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<l:MainViewModel/>
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="ComboBox">
<Setter Property="Width" Value="200"/>
<Setter Property="Margin" Value="10"/>
</Style>
</Grid.Resources>
<ComboBox ItemsSource="{Binding List1}"
SelectedItem="{Binding List1SelectedItem}">
<ComboBox.ItemContainerStyle>
<Style>
<Style.Triggers>
<DataTrigger Binding ="{Binding IsEnabled}" Value="False">
<Setter Property="ComboBoxItem.Focusable" Value="False"/>
<Setter Property="ComboBoxItem.IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.ItemContainerStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Model.Name }"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox ItemsSource="{Binding List2}"
SelectedItem="{Binding List2SelectedItem}"
Grid.Row="1">
<ComboBox.ItemContainerStyle>
<Style>
<Style.Triggers>
<DataTrigger Binding ="{Binding IsEnabled}" Value="False">
<Setter Property="ComboBoxItem.Focusable" Value="False"/>
<Setter Property="ComboBoxItem.IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.ItemContainerStyle>
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Model.Name }"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>
ОБНОВЛЕНИЕ: Было высказано предположение, что решение MVVM может быть немного сложным для OP. Поэтому ниже я адаптировал это решение как упрощенную версию кода.
Поскольку мы все еще используем привязку данных, разумно реализовать
INotifyPropertyChanged
интерфейс, необходимый для уведомления системы привязки данных об изменениях:
public abstract class ObservableBase : INotifyPropertyChanged
{
public void Set<TValue>(ref TValue field, TValue newValue,
[CallerMemberName] string propertyName = "")
{
if (!EqualityComparer<TValue>.Default.Equals(field, default(TValue))
&& field.Equals(newValue)) return;
field = newValue;
RaisePropertyChanged(propertyName);
}
public void RaisePropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this,
new PropertyChangedEventArgs(propertyName));
public event PropertyChangedEventHandler PropertyChanged;
}
Далее нам нужна модель данных для хранения Как данных, так и включенного состояния для каждого элемента в выпадающем списке:
public class PersonModel : ObservableBase
{
private string name;
public string Name
{
get => name;
set => Set(ref name, value);
}
private bool isEnabled = true;
public bool IsEnabled
{
get => isEnabled;
set => Set(ref isEnabled, value);
}
}
Теперь мы можем добавить код в code-behind для инициализации данных и обработки события SelectionChanged для каждого ComboBox:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitData();
DataContext = this;
ComboBoxA.SelectionChanged += OnComboBoxSelectionChanged;
ComboBoxB.SelectionChanged += OnComboBoxSelectionChanged;
}
public ObservableCollection<PersonModel> List1 { get; }
= new ObservableCollection<PersonModel>();
public ObservableCollection<PersonModel> List2 { get; }
= new ObservableCollection<PersonModel>();
private void InitData()
{
for (int i = 0; i < 10; i++)
{
var model = new PersonModel()
{
Name = "Person " + i,
};
List1.Add(model);
List2.Add(model);
}
}
private void OnComboBoxSelectionChanged(object sender,
SelectionChangedEventArgs e)
{
var src = sender as ComboBox;
var items = src.ItemsSource as IList<PersonModel>;
var selected = src.SelectedItem as PersonModel;
UpdateSelections(items, selected);
}
private void UpdateSelections(IList<PersonModel> list, PersonModel person)
{
var dest = list.Equals(List1) ? List2 : List1;
if (person == null)
{
foreach (var item in dest)
{
item.IsEnabled = true;
}
}
else
{
foreach (var item in dest)
{
item.IsEnabled = item.Equals(person) != true;
}
}
}
}
Наконец, XAML. Здесь я назвал ComboBoxes, как и в оригинальном посте, для подключения события SelectionChanged. Кроме того, XAML идентичен приве