Thursday, June 28, 2012

WPF Menu with Icons

Today I'll show how to build WPF Menu with Icons in XAML. In this example you'll see how to control IsEnabled state of MenuItem from your application. The application looks like this:
WPF Menu with Icons example
Ok, let's see the XAML (MainWindow.xaml):

<Menu Width="Auto" Height="21" DockPanel.Dock="Top">
    <!-- Action Menu -->
    <MenuItem Header="Actions">
        <MenuItem Name="menuItem_Enable_Disable"
                  Header="Disable Buttons" 
                  Margin="0"
                  Click="MenuItemEnableDisable_Click">
            <MenuItem.Icon>
                <Image Source="Icons/activate.ico" />
            </MenuItem.Icon>
        </MenuItem>
        <Separator/>
        <MenuItem Name="menuItem_Refresh"
                  Header="Refresh" 
                  Margin="0"
                  IsEnabled="{Binding MenuState, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <MenuItem.Icon>
                <Image Source="Icons/database-refresh.ico" />
            </MenuItem.Icon>
        </MenuItem>

        <MenuItem Header="Exit" 
                  Margin="0"
                  IsEnabled="{Binding MenuState, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                  Click="MenuItemExit_Click">
            <MenuItem.Icon>
                <Image Source="Icons/Exit.ico" />
            </MenuItem.Icon>
        </MenuItem>
    </MenuItem>
    <!-- Options Menu -->
    <MenuItem Header="Options">
        <MenuItem Name="menuItem_ServerSettings" 
                  Header="Server Settings" 
                  Margin="0"                          
                  IsEnabled="{Binding MenuState, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <MenuItem.Icon>
                <Image Source="Icons/server-settings.ico" />
            </MenuItem.Icon>
        </MenuItem>
        <MenuItem Name="menuItem_DatabaseSettings" 
                  Header="Database Settings" 
                  Margin="0"                          
                  IsEnabled="{Binding MenuState, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <MenuItem.Icon>
                <Image Source="Icons/database-settings.ico" />
            </MenuItem.Icon>
        </MenuItem>
    </MenuItem>
    <!-- About Menu -->
    <MenuItem Header="Help">
        <MenuItem Header="About" 
                  Margin="0"                          
                  IsEnabled="{Binding MenuState, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
            <MenuItem.Icon>
                <Image Source="Icons/Information.ico" />
            </MenuItem.Icon>
        </MenuItem>
    </MenuItem>
</Menu>
IsEnabled property of each MenuItem, except menuItem_Enable_Disable is bound to MenuStatus property of the ViewModel. This allows us to enable/disable menu items during application run. 
Let's see what we got in code behind (MainWindow.cs):


public partial class MainWindow : Window
{
    private ViewModel _vm = new ViewModel();
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = _vm;
    }

    private void MenuItemEnableDisable_Click(object sender, RoutedEventArgs e)
    {
        if (_vm.MenuState)
        {
            _vm.MenuState = false;
            this.menuItem_Enable_Disable.Header = "Enable Buttons";
        }
        else
        {
            _vm.MenuState = true;
            this.menuItem_Enable_Disable.Header = "Disable Buttons";
        }
    }

    private void MenuItemExit_Click(object sender, RoutedEventArgs e)
    {
        Application.Current.Shutdown();
    }
}
In the constructor we set ViewModel class as DataContext of the window.
In MenuItemEnableDisable_Click method we simply checking if menu items are enabled then we may disable them and vice versa. Now let's take a look on ViewModel.cs:
public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private bool _menuState = true;
    public bool MenuState
    {
        get { return _menuState; }
        set
        {
            if (_menuState != value)
            {
                _menuState = value;
                NotifyPropertyChanged("MenuState");
            }
        }
    }

    public void NotifyPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
Our ViewModel class has only one property MenuState and implements INotifyPropertyChanged interface. In this particular example there is no use of implementing INotifyPropertyChanged because I'm changing MenuState only from GUI, but if you want to add logic where MenuState will be changed from the code, then thanks to INotifyPropertyChanged, the GUI will be updated automatically.
Download the source code (Visual Studio 2010).

No comments:

Post a Comment