寻找将自身加载到菜单中的模块的 Prism 示例

发布于 2024-07-27 12:05:28 字数 1314 浏览 4 评论 0 原文

有谁知道使用 Prism 的 WPF 代码示例,其中每个模块将自己注册为另一个模块内菜单中的菜单项?

(我目前有一个应用程序尝试使用 EventAggregator 执行此操作,因此一个模块侦听来自其他模块的已发布事件,这些模块需要在菜单中将其标题作为菜单项,但我遇到了加载和线程等​​顺序的问题。我想找到一个使用经典 Prism 结构的示例这样做。)

我正在考虑这个:

Shell.xaml:

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

合同视图:

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

客户视图:

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

但据我所知'我们已经完成了非 Prism MVVM 应用程序结构,并且菜单总是很好地绑定到 ViewModel 中的 ObservableCollections,而上面的内容似乎打破了这种良好的模式。 以上是在 Prism 中执行此操作的惯用方法吗?

Does anyone know of WPF code examples using Prism in which modules each register themselves as a menuitem in a menu within another module?

(I've currently got an application which tries to do this with the EventAggregator, so one module listens for published events from other modules which need to have their title in the menu as a menu item, but I'm getting problems with the order of loading and threading etc. I want to find an example that uses classic Prism structure to do this.)

I'm thinking in terms of this:

Shell.xaml:

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

Contracts View:

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

Customers View:

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

But up to know I've done non-Prism MVVM application structure and Menus were always nicely bound to ObservableCollections in the ViewModel and the above seems to break this nice pattern. Is the above the customary way to do it in Prism?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

╰沐子 2024-08-03 12:05:28

更新:

我为您创建了一个示例。 它在这里:示例 (现已失效链接)

它有一些你可能还没有想到的东西,比如允许你的模块控制你的 shell 的合约(这样你就可以做像打开窗口之类的事情)。 它的设计考虑了 MVVM。 我不知道你是否使用它,但我会考虑它。

我尝试了几分钟来使选项卡标题正确,但最终我放弃了“A Tab”。 如果您使用选项卡式 UI,则可以将其作为练习。 我将其设计为外观简洁,因此您可以替换 Shell.xaml 中的 XAML,而不会破坏任何内容。 如果使用得当,这就是 RegionManager 的优点之一。

无论如何,祝你好运!


我从未见过这样的例子,但你必须自己实现。

您必须创建自己的界面,如下所示:

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

然后您的模块将声明对 IMenuRegistry 的依赖项并注册其视图。

您的 IMenuRegistry 实现(您可能会在托管 Bootstrapper 的同一项目中实现和注册)会将这些菜单项添加到您的菜单或树视图或您用于菜单的任何内容中。

当用户单击某个项目时,您必须使用 Bootstrapper.Container.Resolve(viewType) 方法创建视图的实例并将其填充到您想要显示它的任何占位符中。

Update:

I created a sample for you. It's here: Sample (now dead link)

It's got a few things you have probably not thought of yet, like a contract that will allow your modules to control your shell (so you can do stuff like Open Window, that kind of thing). It is designed with MVVM in mind. I don't know if you are using that, but I would consider it.

I tried for a few minutes to get the tab titles correct, but I ended up leaving off with "A Tab". It's left as an exercise for you if you go with a tabbed UI. I've designed it to be lookless, so you can replace the XAML in the Shell.xaml without breaking anything. That's one of the advantages to the RegionManager stuff if you use it right.

Anyway, good luck!


I've never seen an example of this, but you'd have to implement this yourself.

You'd have to create your own interface, something like this:

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

Your Modules then would declare a dependency on an IMenuRegistry and register their views.

Your implementation of IMenuRegistry (which you would likely implement and register in the same project that hosts your Bootstrapper) you would add those menu items to your menu or treeview or whatever you are using for your menu.

When a user clicks on an item you will have to use your Bootstrapper.Container.Resolve(viewType) method to create an instance of the view and stuff it in whatever placeholder you want to show it in.

氛圍 2024-08-03 12:05:28

我将 MEF 与 prism 6.0 和 MVVM 一起使用

1。为 Leafmenu 创建一个 Menuviewmodel 类,为顶级菜单创建一个 TopLevel MenuViewmodel 类。 Menuviewmodel 类将具有您想要绑定菜单的所有属性。 实现此接口的 Moduleui 必须具有这样的属性

[Export(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);
            }
        }
    }
  • 创建一个具有 MenuViewModel 属性的 IMenu 界面
  •     public interface IMenu
         {
             MenuViewModel ExtensionMenuViewModel
            {
                get;
    
            }
    
         }
    

    3.您需要在所有模块的 ModuleUi 中实现 IMenu 接口,该接口将被加载到菜单中。

    4.实现MefBootstrapper
    5.重写配置聚合目录方法
    6.在目录中添加包含所有模块dll、IMenu接口dll的目录目录。代码如下

    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);
    }
    
  • 在您的主项目中添加对 IMenu interafce dll 的引用
  • 8.在mainwindow.xaml.cs类中声明一个属性

    public ObservableCollection ClientMenuViewModels
    { 得到; 私人套装; }

    声明私有字段

    私有 IEnumerable; 菜单扩展;

    1. 在主窗口或 shell 构造函数中

      [导入构造函数] 
           公共 MainWindow([ImportMany] IEnumerable menuExtensions) 
            { 
               this.menuExtensions = menuExtensions; 
               this.DataContext=this; 
      
            } 
           私有无效 InitalizeMenuAndOwners() 
          { 
           if (ClientMenuViewModels == null) 
          { 
            ClientMenuViewModels = 新                                   
            ObservableCollection(); 
           } 
           别的 
          { 
            ClientMenuViewModels.Clear(); 
           } 
          if (菜单扩展!= null) 
           { 
             var 分组 = menuExtensions.Select 
              (mnuext => mnuext.ClientMenuViewModel).GroupBy(mvvm =>                                                                    
               mvvm.ParentMenu); 
      
             foreach (IGrouping 分组在       
              分组)          
              { 
                UIMenuOptionsparentMenuName = grouping.Key; 
                ToplevelMenuViewModelparentMenuVM = 新  
                 顶级菜单视图模型(                                    
             父菜单名称.ToString(), 
      
             grouping.Select(grp => { return (MenuViewModel)grp; })); 
                ClientMenuViewModels.Add(parentMenuVM); 
              } 
        }} 
        

    }

  • 在 Shell.xaml 或 Mainwindow.xaml 中定义菜单区域并将 itemssource 属性绑定到 ClientMenuViewModels
  •        <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;
    
            }
        }
    

    这是 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;
        }
    
    }
    

    RelayCommand 类如下

     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
        }
    

    I am using MEF along with prism 6.0 and MVVM

    1.Create a Menuviewmodel class for Leafmenu and TopLevel MenuViewmodel class for Toplevel menu. Menuviewmodel class will have all the properties you want to bind your menu with. Moduleui implementing this interafce must have an attribute like this

    [Export(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. Create an IMenu Interface wich has MenuViewModel property
        public interface IMenu
         {
             MenuViewModel ExtensionMenuViewModel
            {
                get;
    
            }
    
         }
    

    3.You need to implement IMenu Interface in ModuleUi of all your modules which will get loaded into a menu.

    4.Implement MefBootstrapper
    5.Override Configure aggregate catalog method
    6.To the catalog add diretory catalog containing all your module dlls, IMenu interface dll.Code is below

    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. in your main project add refence to IMenu interafce dll

    8.In mainwindow.xaml.cs class declare a property

    public ObservableCollection ClientMenuViewModels
    { get; private set; }

    declare a private field

    private IEnumerable<IMenu> menuExtensions;

    1. In your mainwindow or 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. In your Shell.xaml or Mainwindow.xaml define a menu region and bind the itemssource property to ClientMenuViewModels
           <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;
    
            }
        }
    

    here is ViewModelBase class

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

    RelayCommand class is below

     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
        }
    
    ~没有更多了~
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文