WPF, MVVM и цвет переднего плана меню - PullRequest
0 голосов
/ 18 июня 2009

Я новичок в WPF и MVVM. Я искал хороший способ динамически создавать меню в программе MVVM, и я не нашел ничего по своему вкусу, поэтому я нашел собственное решение. Это работает, но по какой-то причине цвет переднего плана (текста) меню иногда (просто иногда) не корректен.

Я добавил ссылку на изображение ниже.

http://img220.imageshack.us/img220/1912/badmenu.jpg (Dead Link)

Мое нижнее подменю отображается правильно с белым передним планом, но его родительское меню переднего плана стало черным и почти невозможно прочитать. Если бы я жестко закодировал меню, то цвет переднего плана родителя был бы белым. Если я наведу курсор мыши на родителя, его текст снова станет белым, а подменю станет черным.

Далее, когда я убираю свою мышь от родителя, все ее логические свойства 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.Resources

<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 (Мертвая ссылка)

Есть предложения, что я делаю неправильно и / или как исправить проблему с дисплеем?

Ответы [ 2 ]

1 голос
/ 18 июня 2009

Проблема заключается в том, что ваши виртуальные машины автоматически упаковываются в 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>

Я также вырезал некоторые привязки команд для простоты, но вы можете добавить их обратно при необходимости.

0 голосов
/ 18 июня 2009

По запросу, вот мои ViewModels.

ViewModelBase - это стандартная программа, созданная студией. 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;     }
}
...