Создать MenuItems из коллекции
Я пытался создать MenuItems элементов коллекции - и не удалось. Подробно: у меня есть простой класс ClassA, который определяет строковое свойство 'HeadText'. В моей MainViewModel я определил свойство ObservableCollection. Коллекция наполнена 3 предметами. Теперь в XAML я хочу создать MenuItems этих 3 элементов типа ClassA. Я сделал следующее:
<Window.Resources>
<CompositeCollection x:Key="CollA">
<ItemsControl ItemsSource="{Binding Path=MItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<MenuItem Header="{Binding HeadText}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</CompositeCollection>
</Window.Resources>
<Grid>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Source={StaticResource CollA}}"/>
</Grid>
Но все, что я получаю, это пустая строка меню. Любые идеи, как я могу это сделать?
Модель представления и класс ClassA:
public class MainVM
{
public MainVM() {
_mItems.Add(new ClassA() { HeadText = "A" });
_mItems.Add(new ClassA() { HeadText = "B" });
_mItems.Add(new ClassA() { HeadText = "C" });
}
private ObservableCollection<ClassA> _mItems = new ObservableCollection<ClassA>();
public ObservableCollection<ClassA> MItems{
get { return _mItems; }
}
}
public class ClassA
{
public ClassA() { }
public String HeadText { get; set; }
}
Заранее спасибо.
Редактировать:
Если я напишу это, это работает:
<Menu DockPanel.Dock="Top" ItemsSource="{Binding MItems}">
<Menu.ItemContainerStyle>
<Style TargetType="MenuItem" BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Header" Value="{Binding HeadText}"/>
</Style>
</Menu.ItemContainerStyle>
</Menu>
Но я хочу сделать это по-другому. И мне интересно, почему другой способ не работает.
1 ответ
Я нашел ответ здесь. Мой XAML сначала выглядел так:
<Window.DataContext>
<local:MainVM/>
</Window.DataContext>
<Window.Resources>
<CollectionViewSource Source="{Binding Path=MItems}" x:Key="source"/>
</Window.Resources>
<StackPanel>
<Menu DockPanel.Dock="Top">
<Menu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding HeadText}"/>
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemsSource>
<CompositeCollection>
<MenuItem Header="Static 1"/>
<MenuItem Header="Static 2"/>
<CollectionContainer Collection="{Binding Source={StaticResource source}}"/>
<MenuItem Header="Static 3"/>
</CompositeCollection>
</Menu.ItemsSource>
</Menu>
</StackPanel>
И MainVM.cs и ClassA:
public class MainVM
{
public MainVM() {
_mItems.Add(new ClassA() { HeadText = "Dyn1" });
_mItems.Add(new ClassA() { HeadText = "Dyn2" });
_mItems.Add(new ClassA() { HeadText = "Dyn3" });
}
private ObservableCollection<ClassA> _mItems = new ObservableCollection<ClassA>();
public ObservableCollection<ClassA> MItems{
get { return _mItems; }
}
}
public class ClassA
{
public ClassA() { }
private string _text = "";
public String HeadText {
get { return _text; }
set { _text = value; }
}
}
Это прекрасно работает, но вы должны заметить, что Visual Studio выдаст вам ошибки BindingExpression в случае, если вы действительно смешаете статические и динамические элементы меню.
Причина этого заключается в том, что синтаксический анализатор XAML применяет указанный ItemContainerStyle к динамическому элементу AND к статическим элементам меню: он создает новый MenuItem и связывает свойство HeadText со свойством Header вновь созданного MenuItem. Это делается как для динамических пунктов меню, так и для статических. Поскольку в классе MenuItem отсутствует свойство HeadText, отображается ошибка.
Приложение не сбоит, но это не очень хорошее решение. Обходной путь для этого состоит в том, чтобы разделить MenuBar как это:
<StackPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Menu Grid.Column="0">
<MenuItem Header="Static 1"/>
<MenuItem Header="Static 2"/>
</Menu>
<Menu Grid.Column="1">
<Menu.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding HeadText}"/>
</Style>
</Menu.ItemContainerStyle>
<Menu.ItemsSource>
<CompositeCollection>
<CollectionContainer Collection="{Binding Source={StaticResource source}}"/>
</CompositeCollection>
</Menu.ItemsSource>
</Menu>
<Menu Grid.Column="2">
<MenuItem Header="Static 3"/>
</Menu>
</Grid>
</StackPanel>
Может быть, есть более хорошее решение. Дайте мне знать, если это так.