У меня есть приложение, которое имеет ListBox ListBoxes. Я хотел бы сделать поля InnerList взаимоисключающими. My ViewModel имеет коллекцию Foos, в которой есть описание, свойство IsSelected и коллекции Bars, у которых есть имя и свойство IsSelected.WPF взаимно эксклюзивные списки
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<Foo> Foos { /* code removed for brevity */ }
}
public class Foo : INotifyPropertyChanged
{
public string Description { /* code removed for brevity */ }
public ObservableCollection<Bar> Bars { /* code removed for brevity */ }
public bool IsSelected { /* code removed for brevity */ }
}
public class Bar : INotifyPropertyChanged
{
public string Name { /* code removed for brevity */ }
public bool IsSelected { /* code removed for brevity */ }
}
Ниже приведена часть моего MainWindow, чей DataContext установлен в MyViewModel. Это свойство ItemsSource ListBox связано с использованием ItemsSource={Binding Path=Foos}
, а в шаблоне для этого списка ListBox используется внутренний список ListBox, связанный с использованием ItemsSource="{Binding Path=Bars}"
. A, B и C являются описаниями Foos. Элементы, содержащиеся в них, - это имена баров.
|--------------------------|
| A |--------------------| |
| | Item 1 | |
| | Item 2 | |
| | Item 3 | |
| |--------------------| |
| |
| B |--------------------| |
| | Item X | |
| | Item Y | |
| | Item Z | |
| |--------------------| |
| |
| C |--------------------| |
| | Item l | |
| | Item m | |
| |--------------------| |
|--------------------------|
Мне нужно сделать так, чтобы пользователь мог выбрать только один элемент из любой из баров. Итак, если пользователь выбирает пункт 1 из Foo A, тогда выбирает элемент X из Foo B, тогда элемент 1 следует отменить.
Мне также нужно привязать выбранный элемент к элементу управления TextBox в другом месте окна, но, по-моему, одно событие.
Выполнение этого изменения кода и выбора событий не является вариантом. Я бы предпочел сохранить это только с помощью XAML.
Заранее спасибо.
UPDATE
Следуя совету Moonshield, я придумал это, но он все еще не полностью работает.
public class MyViewModel
{
private Bar _selectedBar;
public ObservableCollection<Foo> Foos { /* code removed for brevity */ }
public Bar SelectedBar
{
get { return _selectedBar; }
set
{
_selectedBar = null;
NotifyPropertyChanged("SelectedBar");
_selectedBar = value;
NotifyPropertyChanged("SelectedBar");
}
}
}
<ListBox x:Name="lbFoos" ItemsSource="{Binding Path=Foos}" SelectedItem="{Binding Path=SelectedBar}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<StackPanel>
<TextBlock Text="Foo: " />
<TextBlock Text="{Binding Path=Description}" />
<ListBox ItemsSource="{Binding Path=Bars}" SelectedItem="{Binding Path=SelectedItem RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ListBox}}}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<TextBlock Text="{Binding Path=Name}" />
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=OneWayToSource}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Одно предостережение, с которым я столкнулся, заключается в том, что если свойство SelectedItem в окне списка привязано к свойству, а свойство принимает значение, отсутствующее в списке, это не приведет к визуальному отмене выбранного элемента. Я в конечном итоге взломал это, изменив настройщик свойства SelectedObject ViewModel, чтобы он исказил свойство уведомления, измененное «null» между обновлениями. Это приведет к тому, что блокировки списка будут отменены. – 2010-11-27 20:01:06