183 lines
5.7 KiB
C#
183 lines
5.7 KiB
C#
|
|
|
|
|
|
/* Based on Windows UI Library
|
|
Copyright(c) Microsoft Corporation.All rights reserved. */
|
|
|
|
|
|
using System.Collections.Specialized;
|
|
|
|
using System.Windows.Controls.Primitives;
|
|
using System.Windows.Input;
|
|
|
|
using WPFluent.Input;
|
|
|
|
|
|
// ReSharper disable once CheckNamespace
|
|
namespace WPFluent.Controls;
|
|
|
|
/// <summary>
|
|
/// The <see cref="BreadcrumbBar"/> control provides the direct path of pages or folders to the current location.
|
|
/// </summary>
|
|
/// <example>
|
|
/// <code lang="xml"> /// <ui:BreadcrumbBar x:Name="BreadcrumbBar" /> ///</code>
|
|
/// </example>
|
|
[StyleTypedProperty(Property = nameof(ItemContainerStyle), StyleTargetType = typeof(BreadcrumbBarItem))]
|
|
public class BreadcrumbBar : System.Windows.Controls.ItemsControl
|
|
{
|
|
/// <summary>
|
|
/// Identifies the <see cref="Command"/> dependency property.
|
|
/// </summary>
|
|
public static readonly DependencyProperty CommandProperty = DependencyProperty.Register(
|
|
nameof(Command),
|
|
typeof(ICommand),
|
|
typeof(BreadcrumbBar),
|
|
new PropertyMetadata(null));
|
|
|
|
/// <summary>
|
|
/// Identifies the <see cref="ItemClicked"/> routed event.
|
|
/// </summary>
|
|
public static readonly RoutedEvent ItemClickedEvent = EventManager.RegisterRoutedEvent(
|
|
nameof(ItemClicked),
|
|
RoutingStrategy.Bubble,
|
|
typeof(TypedEventHandler<BreadcrumbBar, BreadcrumbBarItemClickedEventArgs>),
|
|
typeof(BreadcrumbBar));
|
|
|
|
/// <summary>
|
|
/// Identifies the <see cref="TemplateButtonCommand"/> dependency property.
|
|
/// </summary>
|
|
public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register(
|
|
nameof(TemplateButtonCommand),
|
|
typeof(IRelayCommand),
|
|
typeof(BreadcrumbBar),
|
|
new PropertyMetadata(null));
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="BreadcrumbBar"/> class.
|
|
/// </summary>
|
|
public BreadcrumbBar()
|
|
{
|
|
SetValue(TemplateButtonCommandProperty, new RelayCommand<object>(OnTemplateButtonClick));
|
|
|
|
Loaded += OnLoaded;
|
|
Unloaded += OnUnloaded;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Occurs when an item is clicked in the <see cref="BreadcrumbBar"/>.
|
|
/// </summary>
|
|
public event TypedEventHandler<BreadcrumbBar, BreadcrumbBarItemClickedEventArgs> ItemClicked
|
|
{
|
|
add => AddHandler(ItemClickedEvent, value);
|
|
remove => RemoveHandler(ItemClickedEvent, value);
|
|
}
|
|
|
|
private void InteractWithItemContainer(int offsetFromEnd, Action<BreadcrumbBarItem> action)
|
|
{
|
|
if (ItemContainerGenerator.Items.Count <= 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var item = ItemContainerGenerator.Items[^offsetFromEnd];
|
|
var container = (BreadcrumbBarItem)ItemContainerGenerator.ContainerFromItem(item);
|
|
|
|
action.Invoke(container);
|
|
}
|
|
|
|
private void ItemContainerGeneratorOnItemsChanged(object sender, ItemsChangedEventArgs e)
|
|
{
|
|
if (e.Action != NotifyCollectionChangedAction.Remove)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UpdateLastContainer();
|
|
}
|
|
|
|
private void ItemContainerGeneratorOnStatusChanged(object sender, EventArgs e)
|
|
{
|
|
if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (ItemContainerGenerator.Items.Count <= 1)
|
|
{
|
|
UpdateLastContainer();
|
|
|
|
return;
|
|
}
|
|
|
|
InteractWithItemContainer(2, static item => item.SetCurrentValue(BreadcrumbBarItem.IsLastProperty, false));
|
|
UpdateLastContainer();
|
|
}
|
|
|
|
private void OnLoaded(object sender, RoutedEventArgs e)
|
|
{
|
|
ItemContainerGenerator.ItemsChanged += ItemContainerGeneratorOnItemsChanged;
|
|
ItemContainerGenerator.StatusChanged += ItemContainerGeneratorOnStatusChanged;
|
|
|
|
UpdateLastContainer();
|
|
}
|
|
|
|
private void OnTemplateButtonClick(object obj)
|
|
{
|
|
if (obj is null)
|
|
{
|
|
throw new ArgumentNullException("Item content is null");
|
|
}
|
|
|
|
var container = ItemContainerGenerator.ContainerFromItem(obj);
|
|
var index = ItemContainerGenerator.IndexFromContainer(container);
|
|
|
|
OnItemClicked(obj, index);
|
|
}
|
|
|
|
private void OnUnloaded(object sender, RoutedEventArgs e)
|
|
{
|
|
Loaded -= OnLoaded;
|
|
Unloaded -= OnUnloaded;
|
|
|
|
ItemContainerGenerator.ItemsChanged -= ItemContainerGeneratorOnItemsChanged;
|
|
ItemContainerGenerator.StatusChanged -= ItemContainerGeneratorOnStatusChanged;
|
|
}
|
|
|
|
private void UpdateLastContainer() => InteractWithItemContainer(
|
|
1,
|
|
static item => item.SetCurrentValue(BreadcrumbBarItem.IsLastProperty, true));
|
|
|
|
protected override DependencyObject GetContainerForItemOverride() { return new BreadcrumbBarItem(); }
|
|
|
|
protected override bool IsItemItsOwnContainerOverride(object item) { return item is BreadcrumbBarItem; }
|
|
|
|
protected virtual void OnItemClicked(object item, int index)
|
|
{
|
|
var args = new BreadcrumbBarItemClickedEventArgs(ItemClickedEvent, this, item, index);
|
|
RaiseEvent(args);
|
|
|
|
if (Command?.CanExecute(item) ?? false)
|
|
{
|
|
Command.Execute(item);
|
|
}
|
|
|
|
if (Command?.CanExecute(null) ?? false)
|
|
{
|
|
Command.Execute(null);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets or sets custom command executed after selecting the item.
|
|
/// </summary>
|
|
[Bindable(true)]
|
|
[Category("Action")]
|
|
[Localizability(LocalizationCategory.NeverLocalize)]
|
|
public ICommand Command { get => (ICommand)GetValue(CommandProperty); set => SetValue(CommandProperty, value); }
|
|
|
|
/// <summary>
|
|
/// Gets the <see cref="RelayCommand{T}"/> triggered after clicking
|
|
/// </summary>
|
|
public IRelayCommand TemplateButtonCommand => (IRelayCommand)GetValue(TemplateButtonCommandProperty);
|
|
}
|