WPF - How can I create menu and submenus using binding

前端 未结 3 2044
鱼传尺愫
鱼传尺愫 2020-11-28 06:30

I am trying to create a dynamic menu using binding. I my viewmodel I have a list of objects which contains an header and a command. However, it is not working. I think the p

相关标签:
3条回答
  • 2020-11-28 07:21

    For me, it worked with this simple template:

    <Menu.ItemContainerStyle>
        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="Command" Value="{Binding Command}" />
        </Style>
    </Menu.ItemContainerStyle>
    <Menu.ItemTemplate>
        <HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Path=MenuItems}">
            <TextBlock Text="{Binding Header}"/>
        </HierarchicalDataTemplate>
    </Menu.ItemTemplate>
    

    Here is the complete example:

    MainWindow.xaml:

    <Window x:Class="WpfApplication14.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication14"
            Title="MainWindow" Height="350" Width="525">
        <DockPanel>
            <Menu DockPanel.Dock="Top" ItemsSource="{Binding MenuItems}">
                <Menu.ItemContainerStyle>
                    <Style TargetType="{x:Type MenuItem}">
                        <Setter Property="Command" Value="{Binding Command}" />
                    </Style>
                </Menu.ItemContainerStyle>
                <Menu.ItemTemplate>
                    <HierarchicalDataTemplate DataType="{x:Type local:MenuItemViewModel}" ItemsSource="{Binding Path=MenuItems}">
                        <TextBlock Text="{Binding Header}"/>
                    </HierarchicalDataTemplate>
                </Menu.ItemTemplate>
            </Menu>
            <Grid>
            </Grid>
        </DockPanel>
    </Window>
    

    MainWindow.xaml.cs:

    using System;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Windows.Input;
    
    namespace WpfApplication14
    {
        public partial class MainWindow : Window
        {
            public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
    
            public MainWindow()
            {
                InitializeComponent();
    
                MenuItems = new ObservableCollection<MenuItemViewModel>
                {
                    new MenuItemViewModel { Header = "Alpha" },
                    new MenuItemViewModel { Header = "Beta",
                        MenuItems = new ObservableCollection<MenuItemViewModel>
                            {
                                new MenuItemViewModel { Header = "Beta1" },
                                new MenuItemViewModel { Header = "Beta2",
                                    MenuItems = new ObservableCollection<MenuItemViewModel>
                                    {
                                        new MenuItemViewModel { Header = "Beta1a" },
                                        new MenuItemViewModel { Header = "Beta1b" },
                                        new MenuItemViewModel { Header = "Beta1c" }
                                    }
                                },
                                new MenuItemViewModel { Header = "Beta3" }
                            }
                    },
                    new MenuItemViewModel { Header = "Gamma" }
                };
    
                DataContext = this;
            }
        }
    
        public class MenuItemViewModel
        {
            private readonly ICommand _command;
    
            public MenuItemViewModel()
            {
                _command = new CommandViewModel(Execute);
            }
    
            public string Header { get; set; }
    
            public ObservableCollection<MenuItemViewModel> MenuItems { get; set; }
    
            public ICommand Command
            {
                get
                {
                    return _command;
                }
            }
    
            private void Execute()
            {
                // (NOTE: In a view model, you normally should not use MessageBox.Show()).
                MessageBox.Show("Clicked at " + Header);
            }
        }
    
        public class CommandViewModel : ICommand
        {
            private readonly Action _action;
    
            public CommandViewModel(Action action)
            {
                _action = action;
            }
    
            public void Execute(object o)
            {
                _action();
            }
    
            public bool CanExecute(object o)
            {
                return true;
            }
    
            public event EventHandler CanExecuteChanged
            {
                add { }
                remove { }
            }
        }
    }
    

    The resulting window looks like this:

    screen shot

    0 讨论(0)
  • 2020-11-28 07:25

    that is very easy,you can use this code for your nested menu

    ViewModel: TopMenuViewModel.cs

    public partial class TopMenuViewModel 
    {
        public TopMenuViewModel()
        {
            TopMenuItems = new ObservableCollection<MenuItem>
            {
                new MenuItem
                {
                    Title = "File",
                    PageName =typeof(OfficeListView).FullName,
                    ChildMenuItems= {
                        new MenuItem
                        {
                            Title = "New"
                        },
                         new MenuItem
                        {
                            Title = "Open"
                        },
                         new MenuItem
                        {
                            Title = "Save"
                        }
                    }
                },
                new MenuItem
                {
                    Title = "Edit"
                },
                new MenuItem
                {
                    Title = "Search"
                }
            };
        }
    

    View: TopMenuView.xaml

    <Menu IsMainMenu="True" ItemsSource="{Binding TopMenuItems}">
                <Menu.ItemContainerStyle>
                    <Style TargetType="{x:Type MenuItem}">
                        <Setter Property="Header" Value="{Binding Title}"/>
                        <Setter Property="ItemsSource" Value="{Binding Path=ChildMenuItems}"/>
                    </Style>
                </Menu.ItemContainerStyle>
    </Menu>   
    
    0 讨论(0)
  • 2020-11-28 07:28

    If like me you are keen to keep UI constructs in the XAML code, after some difficulty, I have worked a nice way of binding custom-typed collections to create menu items.

    In XAML:

    <Menu DockPanel.Dock="Top">
        <MenuItem Header="SomeHeaderName" ItemsSource="{Binding Path=MyCollection}">
            <MenuItem.ItemsContainerStyle>
                <Setter Property="Header" Value="{Binding Path=SomeRelevantTextProperty}"/>
                <EventSetter Event="Click" Handler="SomeMenuItemClickEventHandler"/>
            </MenuItem.ItemsContainerStyle>
        </MenuItem>
    </Menu>
    

    In code-behind:

    ObservableCollection<MyClass> MyCollection;
    
    private void SomeMenuItemClickEventHandler(object sender, RoutedEventArgs e)
    {
        MenuItem menuItem = sender as MenuItem;
        MyClass myClass = menuItem.DataContext as MyClass;
        // do something useful!
    }
    
    public class MyClass
    {
        public string SomeRelevantTextProperty { get; }
    }
    
    0 讨论(0)
提交回复
热议问题