Browse Source

Implemented managed menu bar presenter for native menus

pull/2978/head
Nikita Tsukanov 7 years ago
parent
commit
465273c883
  1. 2
      samples/ControlCatalog/MainWindow.xaml
  2. 2
      samples/ControlCatalog/MainWindow.xaml.cs
  3. 5
      samples/ControlCatalog/Pages/MenuPage.xaml
  4. 5
      src/Avalonia.Controls/NativeMenu.Export.cs
  5. 2
      src/Avalonia.Controls/NativeMenu.cs
  6. 36
      src/Avalonia.Controls/NativeMenuBar.cs
  7. 7
      src/Avalonia.Controls/NativeMenuItemSeperator.cs
  8. 1
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  9. 20
      src/Avalonia.Themes.Default/InverseBooleanValueConverter.cs
  10. 25
      src/Avalonia.Themes.Default/NativeMenuBar.xaml

2
samples/ControlCatalog/MainWindow.xaml

@ -15,11 +15,13 @@
<NativeMenuItem.Menu>
<NativeMenu>
<NativeMenuItem Header="Open" Clicked="OnOpenClicked"/>
<NativeMenuItemSeperator/>
<NativeMenuItem Header="Recent">
<NativeMenuItem.Menu>
<NativeMenu/>
</NativeMenuItem.Menu>
</NativeMenuItem>
<NativeMenuItemSeperator/>
<NativeMenuItem Header="Quit Avalonia" Clicked="OnCloseClicked" Gesture="CMD+Q"/>
</NativeMenu>
</NativeMenuItem.Menu>

2
samples/ControlCatalog/MainWindow.xaml.cs

@ -30,7 +30,7 @@ namespace ControlCatalog
};
DataContext = new MainWindowViewModel(_notificationArea);
_recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[1] as NativeMenuItem).Menu;
_recentMenu = ((NativeMenu.GetMenu(this).Items[0] as NativeMenuItem).Menu.Items[2] as NativeMenuItem).Menu;
}
public void OnOpenClicked(object sender, EventArgs args)

5
samples/ControlCatalog/Pages/MenuPage.xaml

@ -3,8 +3,11 @@
x:Class="ControlCatalog.Pages.MenuPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Menu</TextBlock>
<TextBlock Classes="h2">Exported menu fallback</TextBlock>
<TextBlock>(Should be only visible on platforms without desktop-global menu bar)</TextBlock>
<NativeMenuBar/>
<TextBlock Classes="h2">A window menu</TextBlock>
<StackPanel Orientation="Horizontal"
Margin="0,16,0,0"
HorizontalAlignment="Center"

5
src/Avalonia.Controls/NativeMenu.Export.cs

@ -8,8 +8,7 @@ namespace Avalonia.Controls
public partial class NativeMenu
{
public static readonly AttachedProperty<bool> IsNativeMenuExportedProperty =
AvaloniaProperty.RegisterAttached<NativeMenu, TopLevel, bool>("IsNativeMenuExported",
defaultBindingMode: BindingMode.OneWayToSource);
AvaloniaProperty.RegisterAttached<NativeMenu, TopLevel, bool>("IsNativeMenuExported");
public static bool GetIsNativeMenuExported(TopLevel tl) => tl.GetValue(IsNativeMenuExportedProperty);
@ -53,7 +52,7 @@ namespace Avalonia.Controls
}
public static readonly AttachedProperty<NativeMenu> MenuProperty
= AvaloniaProperty.RegisterAttached<NativeMenu, AvaloniaObject, NativeMenu>("NativeMenuItems", validate:
= AvaloniaProperty.RegisterAttached<NativeMenu, AvaloniaObject, NativeMenu>("Menu", validate:
(o, v) =>
{
if(!(o is Application || o is TopLevel))

2
src/Avalonia.Controls/NativeMenu.cs

@ -11,7 +11,7 @@ namespace Avalonia.Controls
{
public partial class NativeMenu : AvaloniaObject, IEnumerable<NativeMenuItemBase>
{
private AvaloniaList<NativeMenuItemBase> _items =
private readonly AvaloniaList<NativeMenuItemBase> _items =
new AvaloniaList<NativeMenuItemBase> { ResetBehavior = ResetBehavior.Remove };
private NativeMenuItem _parent;
[Content]

36
src/Avalonia.Controls/NativeMenuBar.cs

@ -0,0 +1,36 @@
using System;
using Avalonia.Controls.Primitives;
using Avalonia.Interactivity;
using Avalonia.Styling;
namespace Avalonia.Controls
{
public class NativeMenuBar : TemplatedControl
{
public static readonly AttachedProperty<bool> EnableMenuItemClickForwardingProperty =
AvaloniaProperty.RegisterAttached<NativeMenuBar, MenuItem, Boolean>(
"EnableMenuItemClickForwarding");
static NativeMenuBar()
{
EnableMenuItemClickForwardingProperty.Changed.Subscribe(args =>
{
var item = (MenuItem)args.Sender;
if (args.NewValue.Equals(true))
item.Click += OnMenuItemClick;
else
item.Click -= OnMenuItemClick;
});
}
public static void SetEnableMenuItemClickForwarding(MenuItem menuItem, bool enable)
{
menuItem.SetValue(EnableMenuItemClickForwardingProperty, enable);
}
private static void OnMenuItemClick(object sender, RoutedEventArgs e)
{
(((MenuItem)sender).DataContext as NativeMenuItem)?.RaiseClick();
}
}
}

7
src/Avalonia.Controls/NativeMenuItemSeperator.cs

@ -1,7 +1,10 @@
namespace Avalonia.Controls
using System;
namespace Avalonia.Controls
{
public class NativeMenuItemSeperator : NativeMenuItemBase
{
[Obsolete("This is a temporary hack to make our MenuItem recognize this as a separator, don't use", true)]
public string Header => "-";
}
}

1
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -51,4 +51,5 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.AutoCompleteBox.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.WindowNotificationManager.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.NotificationCard.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.NativeMenuBar.xaml?assembly=Avalonia.Themes.Default"/>
</Styles>

20
src/Avalonia.Themes.Default/InverseBooleanValueConverter.cs

@ -0,0 +1,20 @@
using System;
using System.Globalization;
using Avalonia.Data.Converters;
namespace Avalonia.Themes.Default
{
class InverseBooleanValueConverter : IValueConverter
{
public bool Default { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is bool b ? !b : Default;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is bool b ? !b : !Default;
}
}
}

25
src/Avalonia.Themes.Default/NativeMenuBar.xaml

@ -0,0 +1,25 @@
<Style xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Avalonia.Themes.Default"
Selector="NativeMenuBar">
<Style.Resources>
<local:InverseBooleanValueConverter x:Key="AvaloniaThemesDefaultNativeMenuBarInverseBooleanValueConverter" Default="True"/>
</Style.Resources>
<Setter Property="Template">
<ControlTemplate>
<Menu
IsVisible="{Binding $parent[TopLevel].(NativeMenu.IsNativeMenuExported), Converter={StaticResource AvaloniaThemesDefaultNativeMenuBarInverseBooleanValueConverter}}"
Items="{Binding $parent[TopLevel].(NativeMenu.Menu).Items}">
<Menu.Styles>
<Style Selector="MenuItem">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="Items" Value="{Binding Menu.Items}"/>
<Setter Property="Command" Value="{Binding Command}"/>
<Setter Property="CommandParameter" Value="{Binding CommandParameter}"/>
<Setter Property="(NativeMenuBar.EnableMenuItemClickForwarding)" Value="True"/>
</Style>
</Menu.Styles>
</Menu>
</ControlTemplate>
</Setter>
</Style>
Loading…
Cancel
Save