Vlad i Slav
Vlad i Slav

Reputation: 61

WPF Custom control with ContextMenu ItemCollection

I'm trying to create something like expandable button - button with context menu above, which will open by left mouse button click. Only thing I still can't finishing up is items property, which could be setting up in WPF XAML designer like for ContextMenu control. So, as far as I can understand, that means I need to use ItemCollection type for my property. Ok. Let's take a look on my component:

public partial class MenuButton : Button
{
    private readonly ContextMenu Menu;

    public static readonly DependencyProperty MenuItemsProperty =
        DependencyProperty.Register("MenuItems", typeof(ItemCollection), typeof(ContextMenu), new PropertyMetadata(default(ItemCollection), new PropertyChangedCallback(OnSomeMenuItemsPropertyChanged)));

    public ItemCollection MenuItems
    {
        get => (ItemCollection)GetValue(MenuItemsProperty);
        set => SetValue(MenuItemsProperty, value);
    }

    public MenuButton()
    {
        MenuItems = new DataGrid().Items; // I really need to do it - otherwise I'll get an error

        Menu = new ContextMenu
        {
            HasDropShadow = false,
            PlacementTarget = this,
            Placement = PlacementMode.Top,
        };

        InitializeComponent();
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);

        Menu.Width = ActualWidth;
        Menu.IsOpen = true;
    }

    private static void OnSomeMenuItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        if (target is ContextMenu menu)
        {
            menu.ItemsSource = (ItemCollection)e.NewValue;
        }
    }
}

But I can't 'catch' the OnSomeMenuItemsPropertyChanged - breakpoint does not work here. So, that means this mechanism is wrong. How can I fix that? Should I use OnItemsChanged and OnItemsCollectionChanged events instead (like for ObservableCollection) to handle the changes of the property? Or maybe something else?

Upvotes: -1

Views: 498

Answers (1)

Vlad i Slav
Vlad i Slav

Reputation: 61

So, finally I found the solution. I don't claim that this is the best practice, but maybe it will be useful for someone:

public partial class MenuButton : Button
{
    private readonly ContextMenu Menu;

    public static readonly DependencyProperty MenuItemsProperty =
        DependencyProperty.Register("MenuItems", typeof(ItemCollection), typeof(MenuButton), new PropertyMetadata(default(ItemCollection), new PropertyChangedCallback(OnSomeMenuItemsPropertyChanged)));

    public ItemCollection MenuItems
    {
        get => (ItemCollection)GetValue(MenuItemsProperty);
        set => SetValue(MenuItemsProperty, value);
    }

    public MenuButton()
    {
        Menu = new ContextMenu
        {
            HasDropShadow = false,
            PlacementTarget = this,
            Placement = PlacementMode.Top,
        };
        MenuItems = new DataGrid().Items;

        InitializeComponent();
    }

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
    {
        base.OnMouseLeftButtonDown(e);

        Menu.Width = ActualWidth;
        Menu.IsOpen = true;
    }

    private static void OnSomeMenuItemsPropertyChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
    {
        var menuButton = target as MenuButton;
        menuButton.Menu.ItemsSource = (ItemCollection)e.NewValue;
    }
}

Upvotes: 0

Related Questions