A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

106 lines
3.5 KiB

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Collections;
using Avalonia.Metadata;
namespace Avalonia.Controls
{
public partial class NativeMenu : AvaloniaObject,
IEnumerable<NativeMenuItemBase>,
INativeMenuExporterEventsImplBridge,
IAvaloniaListItemValidator<NativeMenuItemBase>
{
private readonly AvaloniaList<NativeMenuItemBase> _items =
new AvaloniaList<NativeMenuItemBase> { ResetBehavior = ResetBehavior.Remove };
private NativeMenuItem? _parent;
[Content]
public IList<NativeMenuItemBase> Items => _items;
/// <summary>
/// Raised when the menu requests an update.
/// </summary>
/// <remarks>
/// Use this event to add, remove or modify menu items before a menu is
/// shown or a hotkey is pressed.
/// </remarks>
public event EventHandler<EventArgs>? NeedsUpdate;
/// <summary>
/// Raised before the menu is opened.
/// </summary>
/// <remarks>
/// Do not update the menu in this event; use <see cref="NeedsUpdate"/>.
/// </remarks>
public event EventHandler<EventArgs>? Opening;
/// <summary>
/// Raised after the menu is closed.
/// </summary>
/// <remarks>
/// Do not update the menu in this event; use <see cref="NeedsUpdate"/>.
/// </remarks>
public event EventHandler<EventArgs>? Closed;
public NativeMenu()
{
_items.Validator = this;
_items.CollectionChanged += ItemsChanged;
}
void INativeMenuExporterEventsImplBridge.RaiseNeedsUpdate()
{
NeedsUpdate?.Invoke(this, EventArgs.Empty);
}
void INativeMenuExporterEventsImplBridge.RaiseOpening()
{
Opening?.Invoke(this, EventArgs.Empty);
}
void INativeMenuExporterEventsImplBridge.RaiseClosed()
{
Closed?.Invoke(this, EventArgs.Empty);
}
void IAvaloniaListItemValidator<NativeMenuItemBase>.Validate(NativeMenuItemBase item)
{
if (item.Parent is { } parent)
{
throw new InvalidOperationException(
$"The menu item {item.DebugDisplay} already has a parent {parent.DebugDisplay} " +
$"while trying to add it as a child of {DebugDisplay}.");
}
}
private void ItemsChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
foreach (NativeMenuItemBase i in e.OldItems)
i.Parent = null;
if (e.NewItems != null)
foreach (NativeMenuItemBase i in e.NewItems)
i.Parent = this;
}
public static readonly DirectProperty<NativeMenu, NativeMenuItem?> ParentProperty =
AvaloniaProperty.RegisterDirect<NativeMenu, NativeMenuItem?>(nameof(Parent), o => o.Parent);
public NativeMenuItem? Parent
{
get => _parent;
internal set => SetAndRaise(ParentProperty, ref _parent, value);
}
public void Add(NativeMenuItemBase item) => _items.Add(item);
public IEnumerator<NativeMenuItemBase> GetEnumerator() => _items.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}