Browse Source

Merge pull request #8547 from AvaloniaUI/tray-icon-fixes

Tray icon fixes
release/0.10.17
Dan Walmsley 4 years ago
parent
commit
0b525bfd5e
  1. 1
      samples/ControlCatalog/App.xaml
  2. 8
      src/Avalonia.Controls/TrayIcon.cs
  3. 1
      src/Avalonia.Themes.Default/NativeMenuBar.xaml
  4. 1
      src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml
  5. 20
      src/Windows/Avalonia.Win32/IconImpl.cs
  6. 4
      src/Windows/Avalonia.Win32/TrayIconImpl.cs
  7. 16
      src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs
  8. 8
      src/Windows/Avalonia.Win32/Win32Platform.cs

1
samples/ControlCatalog/App.xaml

@ -43,6 +43,7 @@
<NativeMenuItemSeparator />
<NativeMenuItem Header="Option 3" ToggleType="CheckBox" IsChecked="True" Command="{Binding ToggleCommand}" />
<NativeMenuItem Icon="/Assets/test_icon.ico" Header="Restore Defaults" Command="{Binding ToggleCommand}" />
<NativeMenuItem Header="Disabled option" IsEnabled="False" />
</NativeMenu>
</NativeMenuItem>
<NativeMenuItem Header="Exit" Command="{Binding ExitCommand}" />

8
src/Avalonia.Controls/TrayIcon.cs

@ -63,6 +63,10 @@ namespace Avalonia.Controls
args.NewValue.Value.CollectionChanged += Icons_CollectionChanged;
}
}
else
{
throw new InvalidOperationException("TrayIcon.Icons must be set on the Application.");
}
});
var app = Application.Current ?? throw new InvalidOperationException("Application not yet initialized.");
@ -125,9 +129,9 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> IsVisibleProperty =
Visual.IsVisibleProperty.AddOwner<TrayIcon>();
public static void SetIcons(AvaloniaObject o, TrayIcons trayIcons) => o.SetValue(IconsProperty, trayIcons);
public static void SetIcons(Application o, TrayIcons trayIcons) => o.SetValue(IconsProperty, trayIcons);
public static TrayIcons GetIcons(AvaloniaObject o) => o.GetValue(IconsProperty);
public static TrayIcons GetIcons(Application o) => o.GetValue(IconsProperty);
/// <summary>
/// Gets or sets the <see cref="Command"/> property of a TrayIcon.

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

@ -13,6 +13,7 @@
<Menu.Styles>
<Style Selector="MenuItem">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
<Setter Property="InputGesture" Value="{Binding Gesture}"/>
<Setter Property="Items" Value="{Binding Menu.Items}"/>
<Setter Property="Command" Value="{Binding Command}"/>

1
src/Avalonia.Themes.Fluent/Controls/NativeMenuBar.xaml

@ -14,6 +14,7 @@
<Menu.Styles>
<Style x:CompileBindings="False" Selector="MenuItem">
<Setter Property="Header" Value="{Binding Header}"/>
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
<Setter Property="InputGesture" Value="{Binding Gesture}"/>
<Setter Property="Items" Value="{Binding Menu.Items}"/>
<Setter Property="Command" Value="{Binding Command}"/>

20
src/Windows/Avalonia.Win32/IconImpl.cs

@ -1,6 +1,5 @@
using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using Avalonia.Platform;
@ -8,31 +7,18 @@ namespace Avalonia.Win32
{
class IconImpl : IWindowIconImpl
{
private Bitmap bitmap;
private Icon icon;
public IconImpl(Bitmap bitmap)
{
this.bitmap = bitmap;
}
private readonly Icon icon;
public IconImpl(Icon icon)
{
this.icon = icon;
}
public IntPtr HIcon => icon?.Handle ?? bitmap.GetHicon();
public IntPtr HIcon => icon.Handle;
public void Save(Stream outputStream)
{
if (icon != null)
{
icon.Save(outputStream);
}
else
{
bitmap.Save(outputStream, ImageFormat.Png);
}
icon.Save(outputStream);
}
}
}

4
src/Windows/Avalonia.Win32/TrayIconImpl.cs

@ -16,6 +16,8 @@ namespace Avalonia.Win32
{
public class TrayIconImpl : ITrayIconImpl
{
private static readonly IntPtr s_emptyIcon = new System.Drawing.Bitmap(32, 32).GetHicon();
private readonly int _uniqueId;
private static int s_nextUniqueId;
private bool _iconAdded;
@ -84,7 +86,7 @@ namespace Avalonia.Win32
uID = _uniqueId,
uFlags = NIF.TIP | NIF.MESSAGE,
uCallbackMessage = (int)CustomWindowsMessage.WM_TRAYMOUSE,
hIcon = _icon?.HIcon ?? new IconImpl(new System.Drawing.Bitmap(32, 32)).HIcon,
hIcon = _icon?.HIcon ?? s_emptyIcon,
szTip = _tooltipText ?? ""
};

16
src/Windows/Avalonia.Win32/Win32NativeToManagedMenuExporter.cs

@ -1,7 +1,10 @@
using System.Collections.Generic;
using System.Reactive.Linq;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Platform;
using Avalonia.Media.Imaging;
using Avalonia.Utilities;
#nullable enable
@ -28,7 +31,16 @@ namespace Avalonia.Win32
}
else if (menuItem is NativeMenuItem item)
{
var newItem = new MenuItem { Header = item.Header, Icon = item.Icon, Command = item.Command, CommandParameter = item.CommandParameter };
var newItem = new MenuItem
{
[!MenuItem.HeaderProperty] = item.GetObservable(NativeMenuItem.HeaderProperty).ToBinding(),
[!MenuItem.IconProperty] = item.GetObservable(NativeMenuItem.IconProperty)
.Select(i => i is {} bitmap ? new Image { Source = bitmap } : null).ToBinding(),
[!MenuItem.IsEnabledProperty] = item.GetObservable(NativeMenuItem.IsEnabledProperty).ToBinding(),
[!MenuItem.CommandProperty] = item.GetObservable(NativeMenuItem.CommandProperty).ToBinding(),
[!MenuItem.CommandParameterProperty] = item.GetObservable(NativeMenuItem.CommandParameterProperty).ToBinding(),
[!MenuItem.InputGestureProperty] = item.GetObservable(NativeMenuItem.GestureProperty).ToBinding()
};
if (item.Menu != null)
{
@ -36,7 +48,7 @@ namespace Avalonia.Win32
}
else if (item.HasClickHandlers && item is INativeMenuItemExporterEventsImplBridge bridge)
{
newItem.Click += (_, __) => bridge.RaiseClicked();
newItem.Click += (_, _) => bridge.RaiseClicked();
}
result.Add(newItem);

8
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -346,7 +346,7 @@ namespace Avalonia.Win32
using (var memoryStream = new MemoryStream())
{
bitmap.Save(memoryStream);
return new IconImpl(new System.Drawing.Bitmap(memoryStream));
return CreateIconImpl(memoryStream);
}
}
@ -354,11 +354,15 @@ namespace Avalonia.Win32
{
try
{
// new Icon() will work only if stream is an "ico" file.
return new IconImpl(new System.Drawing.Icon(stream));
}
catch (ArgumentException)
{
return new IconImpl(new System.Drawing.Bitmap(stream));
// Fallback to Bitmap creation and converting into a windows icon.
using var icon = new System.Drawing.Bitmap(stream);
var hIcon = icon.GetHicon();
return new IconImpl(System.Drawing.Icon.FromHandle(hIcon));
}
}

Loading…
Cancel
Save