Вопрос

Я новичок как в 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;     }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top