Цвет переднего плана WPF, MVVM и меню
-
06-07-2019 - |
Вопрос
Я новичок как в WPF, так и в MVVM.Я искал хороший способ динамического создания меню в MVVM parttern, но не нашел ничего по своему вкусу, поэтому я разработал свое собственное решение.Это работает, но по какой-то причине цвет переднего плана (текста) меню иногда (просто иногда) неправильный.
Я добавил ссылку на изображение ниже.
http://img220.imageshack.us/img220/1912/badmenu.jpg (Мертвая ссылка)
Мое нижнее подменю корректно отображается на белом переднем плане, но его родительское меню forground стало черным, и его практически невозможно прочитать.Если бы я жестко запрограммировал меню, то основной цвет родительского элемента был бы белым.Если я наведу курсор мыши на родительский элемент, его текст снова станет белым, а подменю - черным.
Кроме того, как только я отодвигаю курсор мыши от родительского элемента, все его логические свойства IsHighlighted, IsSubmenuOpen, etc...
становятся ложными, что меня удивляет, потому что я бы подумал, что они должны оставаться правдивыми.Конечный результат таков, что я не смог решить эту проблему с помощью триггера стиля.
Вот мой XAML .
<Window.Resources>
<DataTemplate DataType="{x:Type src:ParentMenu}" >
<Menu >
<MenuItem Header="{Binding MenuName}" ItemsSource="{Binding ChildMenuItems}" />
</Menu>
</DataTemplate>
<HierarchicalDataTemplate DataType="{x:Type src:ChildMenu}"
ItemsSource="{Binding ChildMenuItems}" >
<MenuItem Header="{Binding MenuName}" Command="{Binding Path=Command}" />
</HierarchicalDataTemplate>
' StackOverflow маскирует мой конечный тег для Window.Ресурсы
<DockPanel>
<Menu DockPanel.Dock="Top" ItemsSource="{Binding Menus}" />
<Grid>
<!-- Add additional content here -->
</Grid>
</DockPanel>
И то , и другое ParentMenu
и ChildMenu
наследуется от общего класса, который фактически содержит все меню и предоставляет доступ к подменю через ChildMenuItems
Коллекция. ChildMenuItems
это список ChildMenu
Объекты.Мой ViewModels
предоставьте список ParentMenu
Объекты.
Вероятно, есть лучшие способы добиться того, чего я здесь хочу.Вот такой пример:
img132.imageshack.us/img132/4160/bettermenu.jpg (Мертвая ссылка)
Любые предложения о том, что я делаю неправильно и / или как устранить проблему с отображением?
Решение
Проблема в том, что ваши виртуальные машины автоматически оборачиваются в MenuItems, поэтому вы, по сути, имеете MenuItems, вложенные в заголовок MenuItems.
Вы можете обойти это, определив стиль (и указав на него через ItemContainerStyle), который DataBinding для ваших виртуальных машин (имя для заголовка, DelegateCommands для команды и т. д.), используя MenuItem в качестве типа данных.
Пример того, как вы можете это сделать, приведен ниже. Обратите внимание, что я отбросил HierarchicalDataTemplate в пользу ItemContainerStyle. Я также взял на себя смелость определить DataTemplate для вашей MainViewModel, так как было не очень понятно, как это было связано с данными.
<Window.Resources>
<DataTemplate DataType="{x:Type src:MainViewModel}">
<ItemsControl ItemsSource="{Binding Menus}"></ItemsControl>
</DataTemplate>
<DataTemplate DataType="{x:Type src:ParentMenu}" >
<Menu>
<MenuItem Header="{Binding Name}"
ItemsSource="{Binding ChildMenuItems}" ItemContainerStyle="{DynamicResource ChildMenuItemStyle}" />
</Menu>
</DataTemplate>
<Style x:Key="ChildMenuItemStyle" TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Name}"></Setter>
<Setter Property="ItemsSource" Value="{Binding ChildMenuItems}"></Setter>
</Style>
</Window.Resources>
Я также вырезал некоторые привязки команд для простоты, но вы можете добавить их обратно при необходимости.
Другие советы
Как и было запрошено, вот мои ViewModels.
ViewModelBase - это стандартная база данных, созданная studio.В MainVieModel есть ровно столько, чтобы создать тестовые меню, с которыми я экспериментировал.
По сути, я работаю над созданием классов родительского / дочернего меню, которые я мог бы использовать с серией приложений, которые мы продаем широкому кругу клиентов.Я надеюсь сделать так, чтобы каждый клиент мог иметь настраиваемую коллекцию меню, основанную на его потребностях и на том, для каких продуктов он приобрел лицензии.
public abstract class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
открытый класс MainViewModel :База данных ViewModelBase
{
public MainViewModel() { MakeMenus(); }
private void MakeMenus()
{
// Makes some dummy menus to test with.
Menus = new ObservableCollection<MyMenuItem>();
ParentMenu parent;
ChildMenu child;
parent = new ParentMenu("First Level");
Menus.Add(parent);
child = new ChildMenu(parent, "second level");
parent.ChildMenuItems.Add(child);
ChildMenu child2 = new ChildMenu(child, "third level");
child2.MenuCommand = new DelegateCommand(CommandTest,
CommandCanExecute_First);
child.ChildMenuItems.Add(child2);
child = new ChildMenu(parent, "second level 2");
parent.ChildMenuItems.Add(child);
child2 = new ChildMenu(child, "third level 2");
child2.MenuCommand = new DelegateCommand(CommandTest,
CommandCanExecute_Second);
child.ChildMenuItems.Add(child2);
parent = new ParentMenu("Another First");
parent.ChildMenuItems.Add(new ChildMenu(parent, "Another Second"));
Menus.Add(parent);
OnPropertyChanged("Menus");
}
private bool ExecuteToggle { get; set; }
private void CommandTest() { ExecuteToggle = !ExecuteToggle; }
public ObservableCollection<MyMenuItem> Menus { get; private set;}
public bool CommandCanExecute_First() { return ExecuteToggle; }
public bool CommandCanExecute_Second() { return !ExecuteToggle; }
}