Pregunta

¿Alguien sabe de ejemplos de código WPF usando Prism en el que los módulos de registrar cada uno a sí mismos como un elemento de menú en un menú dentro de otro módulo?

(He Actualmente tengo una aplicación que intenta hacer esto con la EventAggregator, por lo que un módulo de escucha los eventos publicados de otros módulos que necesitan tener su título en el menú como un elemento de menú, pero estoy problemas para conseguir con el orden de carga y roscado, etc. Quiero encontrar un ejemplo que utiliza la estructura clásica de la prisma para hacer esto).

Estoy pensando en términos de lo siguiente:

Shell.xaml:

<DockPanel>
    <TextBlock Text="Menu:" DockPanel.Dock="Top"/>
    <Menu 
        Name="MenuRegion" 
        cal:RegionManager.RegionName="MenuRegion" 
        DockPanel.Dock="Top"/>
</DockPanel>

Los contratos Ver:

<UserControl x:Class="ContractModule.Views.AllContracts"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <MenuItem Header="Contracts">
    </MenuItem>
</UserControl>

Clientes Ver:

<UserControl x:Class="CustomerModule.Views.CustomerView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <MenuItem Header="Customers">
    </MenuItem>
</UserControl>

Sin embargo, hasta saber que he hecho estructura de la aplicación no Prisma MVVM y menús eran siempre muy bien obligado a ObservableCollections en el modelo de vista y lo anterior parece romper este patrón agradable. Se lo anterior, la forma habitual de hacerlo en Prisma?

¿Fue útil?

Solución

Actualización:

He creado una muestra para usted. Es aquí: ejemplo

Tiene algunas cosas que probablemente no ha pensado todavía, como un contrato que permitirá a sus módulos para el control de la shell (por lo que puede hacer cosas como ventana abierta, ese tipo de cosas). Está diseñado con MVVM en cuenta ... No sé si está utilizando, pero yo lo consideraría.

He intentado durante unos minutos para obtener los títulos de las fichas correcta, pero terminé dejando fuera con "A Tab". Se deja como ejercicio para usted si usted va con una interfaz de usuario con pestañas. He diseñado que sea lookless, para que pueda reemplazar el XAML en el Shell.xaml sin romper nada. Esa es una de las ventajas de la materia RegionManager si se utiliza bien.

De todos modos, buena suerte!


Nunca he visto un ejemplo de esto, pero que tendría que poner en práctica esto por sí mismo.

Usted tendría que crear su propia interfaz, algo como esto:

public interface IMenuRegistry
{
     void RegisterViewWithMenu(string MenuItemTitle, System.Type viewType);
}

Su Módulos entonces sería declarar una dependencia de una IMenuRegistry y registrar sus puntos de vista.

Su puesta en práctica de IMenuRegistry (que probablemente implementar y registrar en el mismo proyecto que aloja su programa previo) deberá añadir los elementos de menú al menú o vista de árbol o lo que usted está utilizando para su menú.

Cuando un usuario hace clic en un elemento que tendrá que utilizar el método de Bootstrapper.Container.Resolve(viewType) para crear una instancia de la vista y rellenarlo en cualquier marcador de posición que desea mostrar en.

Otros consejos

  

Estoy usando MEF junto con el prisma 6.0 y MVVM

1.Create una clase Menuviewmodel para Leafmenu y TopLevel MenuViewmodel clase para el menú de Nivel Superior. Menuviewmodel clase tendrá todas las propiedades que desea vincular a su menú con. Moduleui la aplicación de esta interafce debe tener un atributo como esto

[Exportar (typeof (imenu))]

  public class MenuViewModel:ViewModelBase
        {
            public String Name { get; private set; }
            public UIMenuOptions ParentMenu { get; private set; }
            private bool _IsToolTipEnabled;
            public bool IsToolTipEnabled
            {
                get
                {
                    return _IsToolTipEnabled;
                }
                set
                {
                    SetField(ref _IsToolTipEnabled, value);
                }
            }

            private String _ToolTipMessage;

            public String ToolTipMessage
            {
                get
                {
                    return _ToolTipMessage;
                }
                set
                {
                    SetField(ref _ToolTipMessage, value);
                }
            }
            private IExtensionView extensionView;
            public MenuViewModel(String name, UIMenuOptions parentmenu,
             bool isMenuCheckable = false, 
             IExtensionView extensionView    =null)
            {
                if(name.Contains('_'))
                {
                  name= name.Replace('_', ' ');
                }
                name = "_" + name;
                this.Name = name;
                this.ParentMenu = parentmenu;
                this.IsMenuCheckable = isMenuCheckable;
                this.extensionView = extensionView ;
            }

            private RelayCommand<object> _OpenMenuCommand;

            public ObservableCollection<MenuViewModel> MenuItems { get; set; }
            public ICommand OpenMenuCommand
            {
                get
                {
                    if(_OpenMenuCommand==null)
                    {
                        _OpenMenuCommand = new RelayCommand<object>((args =>  
                          OpenMenu(null)));
                    }
                    return _OpenMenuCommand;
                }
            }

            private void OpenMenu(object p)
            {

                if (extensionView != null)
                {
                    extensionView .Show();
                }
            }

            private bool _IsMenuEnabled=true;
            public bool IsMenuEnabled
            {
                get
                {

                    return _IsMenuEnabled;
                }
                set
                {
                    SetField(ref _IsMenuEnabled, value);
                }
            }

            public bool IsMenuCheckable
            {
                get;
                private set;
            }
            private bool _IsMenuChecked;
            public bool IsMenuChecked
            {
                get
                {
                    return _IsMenuChecked;
                }
                set
                {
                    SetField(ref _IsMenuChecked, value);
                }
             }
        }

         public class ToplevelMenuViewModel:ViewModelBase
         {
            public ObservableCollection<MenuViewModel> ChildMenuViewModels { 
              get; private set; } 
            public  String Header { get; private set; }
            public  ToplevelMenuViewModel(String header,         
             IEnumerable<MenuViewModel> childs)
            {

                this.Header ="_"+ header;
                this.ChildMenuViewModels =new 
                ObservableCollection<MenuViewModel>(childs);
            }
        }
    }
  
      
  1. Crear una wich imenu interfaz tiene la propiedad MenuViewModel
  2.   
    public interface IMenu
     {
         MenuViewModel ExtensionMenuViewModel
        {
            get;

        }

     }
  

3.You necesidad de aplicar imenu interfaz en ModuleUi de todos los módulos que se cargan en un menú.

4.Implement MefBootstrapper
5.Override Configurar método de catálogo global 6.To el catálogo añadir catálogo diretory que contiene todos los archivos DLL de módulo, dll.Code interfaz imenu está por debajo

protected override void ConfigureAggregateCatalog()
{
    base.ConfigureAggregateCatalog();
    AggregateCatalog.Catalogs.Add(new  
     AssemblyCatalog(typeof(Bootstrapper).Assembly));
       AggregateCatalog.Catalogs.Add(new 
      AssemblyCatalog(typeof(IMenu).Assembly));
     //create a directorycatalog with path of a directory conatining  
      //your module dlls                
    DirectoryCatalog dc = new DirectoryCatalog(@".\Extensions");
    AggregateCatalog.Catalogs.Add(dc);
}
  
      
  1. en su proyecto principal añadir refence a imenu interafce DLL
  2.   
     

8.In mainwindow.xaml.cs clase declarar una propiedad

ClientMenuViewModels ObservableCollection pública          { obtener; conjunto privado; }

  

declarar un campo privado

     

private IEnumerable<IMenu> menuExtensions;

  1. En su MainWindow o shell constructor

    [ImportingConstructor]
       public MainWindow([ImportMany] IEnumerable<IMenu> menuExtensions)
        {
           this.menuExtensions = menuExtensions;
           this.DataContext=this;
    
        }
       private void InitalizeMenuAndOwners()
      {
       if (ClientMenuViewModels == null)
      {
        ClientMenuViewModels = new                                  
        ObservableCollection<ToplevelMenuViewModel>();
       }
       else
      {
        ClientMenuViewModels.Clear();
       }
      if (menuExtensions != null)
       {
         var groupings = menuExtensions.Select
          (mnuext =>   mnuext.ClientMenuViewModel).GroupBy(mvvm =>                                                                   
           mvvm.ParentMenu);
    
         foreach (IGrouping<UIMenuOptions, MenuViewModel> grouping in      
          groupings)         
          {
            UIMenuOptions parentMenuName = grouping.Key;
            ToplevelMenuViewModel parentMenuVM = new 
             ToplevelMenuViewModel(                                   
         parentMenuName.ToString(),
    
         grouping.Select(grp => { return (MenuViewModel)grp; }));
            ClientMenuViewModels.Add(parentMenuVM);
          }
    }}
    

}

  
      
  1. En su Shell.xaml o MainWindow.xaml definir una zona de menús y se unen a la propiedad ItemsSource ClientMenuViewModels
  2.   
       <Menu HorizontalAlignment="Left"
              Background="#FF0096D6"
              Foreground="{StaticResource menuItemForegroundBrush}"
              ItemsSource="{Binding ClientMenuViewModels}"
              TabIndex="3">
            <Menu.Resources>
                <Style x:Key="subMneuStyle" TargetType="{x:Type MenuItem}">
                    <Setter Property="Foreground" Value="#FF0096D6" />
                    <Setter Property="FontFamily" Value="HP Simplified" />
                    <Setter Property="FontSize" Value="12" />
                    <Setter Property="Background" Value="White" />
                    <Setter Property="Command" Value="{Binding   
                     OpenMenuCommand}" />                 
                    <Setter Property="IsCheckable" Value="{Binding

                     IsMenuCheckable}" />
                    <Setter Property="IsChecked" Value="{Binding 
                         IsMenuChecked, Mode=TwoWay}" />
                    <Setter Property="IsEnabled" Value="{Binding 
                   IsMenuEnabled, Mode=TwoWay}" />
                    <Setter Property="ToolTip" Value="{Binding  
                ToolTipMessage, Mode=OneWay}" />
                    <Setter Property="ToolTipService.ShowOnDisabled" Value=" 
            {Binding IsToolTipEnabled, Mode=OneWay}" />
                    <Setter Property="ToolTipService.IsEnabled" Value="
            {Binding IsToolTipEnabled, Mode=OneWay}" />
                    <Setter Property="ToolTipService.ShowDuration" 
         Value="3000" />
                    <Setter Property="ToolTipService.InitialShowDelay" 
                Value="10" />
                </Style>

                <my:MyStyleSelector x:Key="styleSelector" ChildMenuStyle="   
                     {StaticResource subMneuStyle}" />
                <HierarchicalDataTemplate DataType="{x:Type 
                  plugins:ToplevelMenuViewModel}"
                 ItemContainerStyleSelector="{StaticResource styleSelector}"
                  ItemsSource="{Binding ChildMenuViewModels}">
                    <Label Margin="0,-5,0,0"
                           Content="{Binding Header}"
                           FontFamily="HP Simplified"
                           FontSize="12"
                    Foreground="{StaticResource menuItemForegroundBrush}" />
                </HierarchicalDataTemplate>
                <DataTemplate DataType="{x:Type plugins:MenuViewModel}">
                    <Label VerticalContentAlignment="Center"
                           Content="{Binding Name}"
                           Foreground="#FF0096D6" />
                </DataTemplate>
            </Menu.Resources>
            <Menu.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </Menu.ItemsPanel>
              </Menu>









 public class MyStyleSelector : StyleSelector
      {
        public Style ChildMenuStyle { get; set; }
        public Style TopLevelMenuItemStyle { get; set; }
        public override Style SelectStyle(object item, DependencyObject             
         container)                    
        {
            if (item is MenuViewModel)
            {
                return ChildMenuStyle;
            }
            //if(item is ToplevelMenuViewModel)
            //{
            //    return TopLevelMenuItemStyle;
            //}
            return null;

        }
    }
  

aquí es la clase ViewModelBase

public class ViewModelBase:INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler =Volatile.Read(ref PropertyChanged);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        };
    }
    protected bool SetField<T>(ref T field, T value,[CallerMemberName] string propertyName="")
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }

}
  

clase RelayCommand está por debajo

 public class RelayCommand<T> : ICommand
    {
        #region Fields

        private readonly Action<T> _execute = null;
        private readonly Predicate<T> _canExecute = null;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action<T> execute)
            : this(execute, null)
        {
        }


        /// <summary>
        /// Creates a new command with conditional execution.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        /// <param name="canExecute">The execution status logic.</param>
        public RelayCommand(Action<T> execute, Predicate<T> canExecute)
        {
            if (execute == null)
                throw new ArgumentNullException("execute");

            _execute = execute;
            _canExecute = canExecute;
        }

        #endregion

        #region ICommand Members

        /// <summary>
        /// Defines the method that determines whether the command can execute in its current state.
        /// </summary>
        /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
        /// <returns>
        /// true if this command can be executed; otherwise, false.
        /// </returns>
        public bool CanExecute(object parameter)
        {
            return _canExecute == null ? true : _canExecute((T)parameter);
        }

        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (_canExecute != null)
                    CommandManager.RequerySuggested -= value;
            }
        }

        public void Execute(object parameter)
        {
            _execute((T)parameter);
        }

        #endregion
    }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top