Pergunta

Eu sou novo para WPF e MVVM. Eu tenho procurado uma boa maneira de criar dinamicamente menus no parttern MVVM e eu não estou achando nada para o meu gosto, então eu rolei a minha própria solução. Ele funciona, mas por alguma razão a cor de primeiro plano (texto) dos menus são, por vezes (só às vezes) não está correto.

Eu adicionei um link para a imagem abaixo.

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

As minhas submenu mais baixas exibe corretamente com um primeiro plano branco, mas a sua menus pai forground virou-se para preto e é quase impossível de ler. Se eu tivesse codificado os menus, em seguida, cor forground do pai seria branco. Se eu movo o mouse sobre o pai seu texto voltará ao branco e o submenu se tornará preto.

false Além disso, uma vez que eu movo o mouse para longe do pai, todas as suas propriedades boolean IsHighlighted, IsSubmenuOpen, etc... tornar-se, o que surpreendente para mim, porque eu acho que eles deveriam permanecer fiel. O resultado final é que eu não tenho sido capaz de resolver isso com um gatilho estilo.

Aqui está o meu 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 está mascarando minha tag end para Window.Resources

<DockPanel>
   <Menu DockPanel.Dock="Top" ItemsSource="{Binding Menus}" />

  <Grid>
       <!-- Add additional content here -->
  </Grid>
</DockPanel>

Ambos ParentMenu e herdar ChildMenu de uma classe comum que realmente detém todos os menus e expõe os sub-menus, através da recolha ChildMenuItems. ChildMenuItems é uma lista de objetos ChildMenu. Meu ViewModels expor uma lista de objetos ParentMenu.

Há provavelmente melhor maneiras de conseguir o que eu quero aqui. Aqui está um exemplo:

img132.imageshack.us/img132/4160/bettermenu.jpg (Dead Link)

Todas as sugestões sobre o que estou fazendo de errado e / ou como corrigir o problema de exibição?

Foi útil?

Solução

O problema é que o seu VMs automaticamente se envolver em MenuItems, então você tem basicamente MenuItems aninhados como o cabeçalho de MenuItems.

Você pode contornar isso definindo um estilo (e apontando para ele via ItemContainerStyle) que DataBinds para o seu VMs (nome de cabeçalho, DelegateCommands para comandar, etc.) usando MenuItem como o tipo de dados.

Um exemplo de uma maneira que você pode fazer isso é abaixo. Nota que eu deixei cair o HierarchicalDataTemplate em favor de uma ItemContainerStyle. Eu também tomei a liberdade de definir um DataTemplate para o seu MainViewModel como não foi muito claro como isso foi dados vinculados.

<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>

Eu também cortar algumas do Comando de ligação para fora para simplificar, mas você pode adicioná-lo novamente como necessário.

Outras dicas

Conforme solicitado, aqui estão as minhas ViewModels.

ViewModelBase é o padrão criado pelo estúdio. MainVieModel tem apenas o suficiente para nele para criar os menus de teste que eu estava usando para experimentar.

Basicamente, eu estou trabalhando no sentido de criar um pai / filho classes de menu que podem ser usados ??com uma série de aplicativos que vender para uma ampla coleção de clientes. Espero fazer isso onde cada cliente pode ter uma coleção personalizável de menus com base em suas necessidades e que moudles que tenha comprado licenças para.

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 classe pública: 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;     }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top