Skip to content

Commit bcdf8b6

Browse files
authored
HamburgerMenuItem Command improvements (#2921)
* Add feature for #2865 - Implement the interface ICommandSource - Handle Command binding change to hook or unhook command executable - Listen to the new command stuff to enable or disable the HamburgerMenuItem - New `MahApps.Metro.Styles.HamburgerMenu` key for the HamburgerMenu style * Update 1.5.0.md
1 parent 8a87a1b commit bcdf8b6

File tree

9 files changed

+324
-30
lines changed

9 files changed

+324
-30
lines changed

docs/release-notes/1.5.0.md

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
+ Add `HamburgerVisibility` property [UWPCommunityToolkit #1020](https://github.com/Microsoft/UWPCommunityToolkit/pull/1020)
1717
+ Set `Content` for `HamburgerMenu` only if one of the inner ListBox controls has a selected item.
1818
+ New `HamburgerMenuHeaderTemplate` property to set a header right of the HamburgerMenu button. [@SilverDragon135](https://github.com/SilverDragon135) [#2917](https://github.com/MahApps/MahApps.Metro/pull/2917)
19+
+ Implement the interface `ICommandSource` and handle Command binding change to hook or unhook command executable.
20+
+ Add `MahApps.Metro.Styles.HamburgerMenu` style key to the HamburgerMenu.
1921
- If `ShowInTaskbar = false`, when double click on the title bar of a minimized window, the window will be restored instead of maximized. [#2854](https://github.com/MahApps/MahApps.Metro/pull/2854) [@hausenism](https://github.com/hausenism)
2022
- Fix WindowCommands tab stop bug [#2858](https://github.com/MahApps/MahApps.Metro/pull/2858) [@neilt6](https://github.com/neilt6)
2123
- Don't overwrite cancellation for window close event [#2868](https://github.com/MahApps/MahApps.Metro/pull/2868) [@batzen](https://github.com/batzen)
@@ -92,3 +94,4 @@
9294
- [#2332](https://github.com/MahApps/MahApps.Metro/issues/2332) Calendar ignores IsTodayHighlighted property
9395
- [#2434](https://github.com/MahApps/MahApps.Metro/issues/2434) DataGridNumericUpDownColumn foreground color
9496
- [#2627](https://github.com/MahApps/MahApps.Metro/issues/2627) Inconsistent FloatingWatermark Alignment
97+
- [#2865](https://github.com/MahApps/MahApps.Metro/issues/2865) [Feature request]Enable/Disable of Hamburger Menu Item

src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/HamburgerMenuSample.xaml

+15-4
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,12 @@
55
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
66
xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
77
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
8+
xmlns:metroDemo="clr-namespace:MetroDemo"
9+
xmlns:exampleViews="clr-namespace:MetroDemo.ExampleViews"
810
d:DesignHeight="300"
911
d:DesignWidth="400"
10-
mc:Ignorable="d">
12+
mc:Ignorable="d"
13+
d:DataContext="{d:DesignInstance metroDemo:MainWindowViewModel}">
1114

1215
<UserControl.Resources>
1316
<DataTemplate x:Key="HamburgerMenuItem" DataType="{x:Type controls:HamburgerMenuItem}">
@@ -47,14 +50,21 @@
4750
</UserControl.Resources>
4851

4952
<Grid>
53+
<Grid.RowDefinitions>
54+
<RowDefinition Height="Auto" />
55+
<RowDefinition Height="*" />
56+
</Grid.RowDefinitions>
57+
<StackPanel Orientation="Horizontal" Grid.Row="0" Margin="20 5">
58+
<CheckBox VerticalAlignment="Center" Content="Allow About Hamburger MenuItem" IsChecked="{Binding CanShowHamburgerAboutCommand, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
59+
</StackPanel>
5060
<controls:HamburgerMenu x:Name="HamburgerMenuControl"
61+
Grid.Row="1"
5162
VerticalScrollBarOnLeftSide="False"
5263
SelectedIndex="1"
53-
Margin="20"
64+
Margin="20 0 20 20"
5465
HamburgerWidth="48"
5566
ItemClick="HamburgerMenu_OnItemClick"
5667
ItemTemplate="{StaticResource HamburgerMenuImageItem}"
57-
OptionsItemClick="HamburgerMenu_OnOptionsItemClick"
5868
OptionsItemTemplate="{StaticResource HamburgerMenuItem}">
5969
<!-- Header -->
6070
<controls:HamburgerMenu.HamburgerMenuHeaderTemplate>
@@ -80,7 +90,8 @@
8090
<!-- Options -->
8191
<controls:HamburgerMenu.OptionsItemsSource>
8292
<controls:HamburgerMenuItemCollection>
83-
<controls:HamburgerMenuGlyphItem Label="About">
93+
<controls:HamburgerMenuGlyphItem Label="About"
94+
Command="{x:Static exampleViews:ShowAboutCommand.Command}">
8495
<controls:HamburgerMenuGlyphItem.Tag>
8596
<iconPacks:PackIconMaterial Width="22"
8697
Height="22"

src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/ExampleViews/HamburgerMenuSample.xaml.cs

+47
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
namespace MetroDemo.ExampleViews
22
{
3+
using System.Windows;
34
using System.Windows.Controls;
5+
using System.Windows.Input;
6+
using JetBrains.Annotations;
47
using MahApps.Metro.Controls;
58
using MahApps.Metro.Controls.Dialogs;
69

@@ -24,10 +27,54 @@ private void HamburgerMenu_OnItemClick(object sender, ItemClickEventArgs e)
2427
}
2528
}
2629

30+
// Another option to handle the options menu item click
31+
[UsedImplicitly]
2732
private async void HamburgerMenu_OnOptionsItemClick(object sender, ItemClickEventArgs e)
2833
{
2934
var menuItem = e.ClickedItem as HamburgerMenuItem;
3035
await this.TryFindParent<MetroWindow>().ShowMessageAsync("", $"You clicked on {menuItem.Label} button");
3136
}
3237
}
38+
39+
// This class can be used to avoid the following error message
40+
// System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=
41+
// WPF doesn’t know which FrameworkElement to use to get the DataContext, because the HamburgerMenuItem doesn’t belong to the visual or logical tree of the HamburgerMenu.
42+
public class BindingProxy : Freezable
43+
{
44+
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
45+
public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
46+
47+
public object Data
48+
{
49+
get { return (object)GetValue(DataProperty); }
50+
set { SetValue(DataProperty, value); }
51+
}
52+
53+
protected override Freezable CreateInstanceCore()
54+
{
55+
return new BindingProxy();
56+
}
57+
}
58+
59+
public static class ShowAboutCommand
60+
{
61+
public static readonly RoutedCommand Command = new RoutedCommand();
62+
63+
static ShowAboutCommand()
64+
{
65+
Application.Current.MainWindow.CommandBindings.Add(new CommandBinding(Command, Execute, CanExecute));
66+
}
67+
68+
private static void CanExecute(object sender, CanExecuteRoutedEventArgs e)
69+
{
70+
var mainViewModel = ((MainWindow)sender).DataContext as MainWindowViewModel;
71+
e.CanExecute = mainViewModel != null && mainViewModel.CanShowHamburgerAboutCommand;
72+
}
73+
74+
private static async void Execute(object sender, ExecutedRoutedEventArgs e)
75+
{
76+
var menuItem = e.Parameter as HamburgerMenuItem;
77+
await ((MainWindow)sender).ShowMessageAsync("", $"You clicked on {menuItem.Label} button");
78+
}
79+
}
3380
}

src/MahApps.Metro.Samples/MahApps.Metro.Demo/MahApps.Metro.Demo.Shared/MainWindowViewModel.cs

+16
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,22 @@ public ICommand CloseCmd
214214
}
215215
}
216216

217+
private bool canShowHamburgerAboutCommand = true;
218+
219+
public bool CanShowHamburgerAboutCommand
220+
{
221+
get { return this.canShowHamburgerAboutCommand; }
222+
set
223+
{
224+
if (Equals(value, this.canShowHamburgerAboutCommand))
225+
{
226+
return;
227+
}
228+
this.canShowHamburgerAboutCommand = value;
229+
this.RaisePropertyChanged("CanShowHamburgerAboutCommand");
230+
}
231+
}
232+
217233
private ICommand textBoxButtonCmd;
218234

219235
public ICommand TextBoxButtonCmd
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#if NET4
2+
using System;
3+
#endif
4+
using System.Security;
5+
using System.Windows;
6+
using System.Windows.Input;
7+
8+
namespace MahApps.Metro.Controls
9+
{
10+
internal static class CommandHelpers
11+
{
12+
#if NET4
13+
internal static readonly DependencyProperty CanExecuteChangedHandlerProperty
14+
= DependencyProperty.RegisterAttached(
15+
"CanExecuteChangedHandler",
16+
typeof(EventHandler),
17+
typeof(CommandHelpers), new FrameworkPropertyMetadata(null));
18+
19+
internal static EventHandler GetCanExecuteChangedHandler(DependencyObject element)
20+
{
21+
return (EventHandler)element.GetValue(CanExecuteChangedHandlerProperty);
22+
}
23+
24+
internal static void SetCanExecuteChangedHandler(DependencyObject element, EventHandler value)
25+
{
26+
element.SetValue(CanExecuteChangedHandlerProperty, value);
27+
}
28+
#endif
29+
30+
internal static bool CanExecuteCommandSource(ICommandSource commandSource)
31+
{
32+
var command = commandSource.Command;
33+
if (command == null)
34+
{
35+
return false;
36+
}
37+
var commandParameter = commandSource.CommandParameter ?? commandSource;
38+
var routedCommand = command as RoutedCommand;
39+
if (routedCommand != null)
40+
{
41+
var target = commandSource.CommandTarget ?? commandSource as IInputElement;
42+
return routedCommand.CanExecute(commandParameter, target);
43+
}
44+
return command.CanExecute(commandParameter);
45+
}
46+
47+
[SecurityCritical]
48+
[SecuritySafeCritical]
49+
internal static void ExecuteCommandSource(ICommandSource commandSource)
50+
{
51+
CriticalExecuteCommandSource(commandSource);
52+
}
53+
54+
[SecurityCritical]
55+
internal static void CriticalExecuteCommandSource(ICommandSource commandSource)
56+
{
57+
var command = commandSource.Command;
58+
if (command == null)
59+
{
60+
return;
61+
}
62+
var commandParameter = commandSource.CommandParameter ?? commandSource;
63+
var routedCommand = command as RoutedCommand;
64+
if (routedCommand != null)
65+
{
66+
var target = commandSource.CommandTarget ?? commandSource as IInputElement;
67+
if (routedCommand.CanExecute(commandParameter, target))
68+
{
69+
routedCommand.Execute(commandParameter, target);
70+
}
71+
}
72+
else
73+
{
74+
if (command.CanExecute(commandParameter))
75+
{
76+
command.Execute(commandParameter);
77+
}
78+
}
79+
}
80+
}
81+
}

0 commit comments

Comments
 (0)