Pregunta

Soy nuevo en WPF y MVVM. He buscado una buena manera de crear dinámicamente menús en la parte MVVM y no encuentro nada de mi agrado, así que creé mi propia solución. Funciona, pero por alguna razón el color de primer plano (texto) de los menús a veces (solo a veces) no es correcto.

Agregué un enlace para la imagen a continuación.

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

Mi submenú más bajo se muestra correctamente con un primer plano blanco, pero sus menús principales para el fondo se volvieron negros y es casi imposible de leer. Si hubiera codificado los menús, el color de fondo de los padres sería blanco. Si muevo el mouse sobre el padre, el texto volverá a ser blanco y el submenú se volverá negro.

Además, una vez que muevo el mouse lejos del padre, todas sus propiedades booleanas IsHighlighted, IsSubmenuOpen, etc ... se vuelven falsas, lo que me sorprende porque creo que deberían permanecer verdaderas . El resultado final es que no he podido resolver esto con un activador de estilo.

Aquí está mi 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á enmascarando mi etiqueta final para Window.Resources

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

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

Tanto ParentMenu como ChildMenu heredan de una clase común que en realidad contiene todos los menús y expone los submenús a través de la colección ChildMenuItems . ChildMenuItems es una lista de objetos ChildMenu . Mis ViewModels exponen una lista de objetos ParentMenu .

Probablemente hay mejores formas de lograr lo que quiero aquí. Aquí hay un ejemplo:

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

¿Alguna sugerencia sobre lo que estoy haciendo mal y / o cómo solucionar el problema de visualización?

¿Fue útil?

Solución

El problema es que sus máquinas virtuales se envuelven automáticamente en MenuItems, por lo que esencialmente tiene MenuItems anidados como el encabezado de MenuItems.

Puede evitar esto definiendo un Estilo (y señalándolo a través de ItemContainerStyle) que DataBinds a sus VM (Nombre al encabezado, DelegateCommands a Command, etc.) usando MenuItem como DataType.

A continuación se muestra un ejemplo de cómo puede hacer esto. Tenga en cuenta que he descartado HierarchicalDataTemplate a favor de un ItemContainerStyle. También me tomé la libertad de definir un DataTemplate para su MainViewModel, ya que no estaba muy claro cómo estaban vinculados los datos.

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

También corté algunos de los enlaces de Comando para simplificarlos, pero puede volver a agregarlos según sea necesario.

Otros consejos

Según lo solicitado, aquí están mis ViewModels.

ViewModelBase es el estándar creado por studio. MainVieModel tiene lo suficiente para crear los menús de prueba que estaba usando para experimentar.

Básicamente, estoy trabajando para crear un menú para padres / hijos que pueda usar con una serie de aplicaciones que vendemos a una amplia colección de clientes. Espero llegar a un lugar donde cada cliente pueda tener una colección de menús personalizables en función de sus necesidades y para qué mudles compraron licencias.

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));
        }
    }
}   

clase pública 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;     }
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top