wpfxamllistviewexpander

Vertical Left Menu with User Control (Expander inside) must close others when you open one XAML


I'm implementing a Vertical Left Drop Down Menu with an User Control, this has inside an Expander. The UserControl has a DependencyProperty which expect a ListView (The Items of the Menu), also has a dependency property "IsSelected" which is bind with Expander property "IsExpanded". I like implement a function when the user click in the UserControlMenu, open this (if is Closed) and close the others. I attached my classes and UserControl, but, now I'm only get when you click on the UserControlMenu, this open and in that instant close.

The UserControl XAML

<UserControl x:Class="DropDownMenuExpander.UserControlMenuItem"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
             mc:Ignorable="d" >
    <Grid>
        <md:PackIcon Kind="{Binding Path=Icon}" Width="15" Height="15" Margin="10 16"/>
        <Expander x:Name="ExpanderMenu" Header="{Binding Path=Header}" IsExpanded="{Binding Path=IsSelected}" Width="210" HorizontalAlignment="Right" Background="{x:Null}">
            <ContentControl Content="{Binding ListView}"/>
        </Expander>
    </Grid>
</UserControl>

The UserControl .cs

    public partial class UserControlMenuItem : UserControl
    {
        public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register("Header", typeof(string), typeof(UserControlMenuItem));
        public string Header
        {
            get
            {
                return (string)GetValue(HeaderProperty);
            }
            set
            {
                SetValue(HeaderProperty, value);
            }
        }

        public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register("IsSelected", typeof(bool), typeof(UserControlMenuItem));
        public bool IsSelected
        {
            get
            {
                return (bool)GetValue(IsSelectedProperty);
            }
            set
            {
                SetValue(IsSelectedProperty, value);
            }
        }


        public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(PackIconKind), typeof(UserControlMenuItem));
        public PackIconKind Icon
        {
            get
            {
                return (PackIconKind)GetValue(IconProperty);
            }
            set
            {
                SetValue(IconProperty, value);
            }
        }
        public static readonly DependencyProperty ListViewProperty = DependencyProperty.Register("ListView", typeof(ListView), typeof(UserControlMenuItem), new UIPropertyMetadata(null));
        public ListView ListView
        {
            get
            {
                return (ListView)GetValue(ListViewProperty);
            }
            set
            {
                SetValue(ListViewProperty, value);
            }
        }
        public UserControlMenuItem()
        {
            InitializeComponent();
            DataContext = this;
        }
    }

Calling the UserControl in the MainWindow

<StackPanel x:Name="st_menu" Margin="10" Orientation="Vertical" ScrollViewer.CanContentScroll="True">
                    <local:UserControlMenuItem  x:Name="MenuItemHome" Header="Home" Icon="Home" PreviewMouseDown="MenuItemHome_PreviewMouseDown">
                        <local:UserControlMenuItem.ListView>
                            <ListView SelectionMode="Single" Margin="0 16 0 16">
                                <ListViewItem>
                                    <TextBlock Text="Item1"/>
                                </ListViewItem>
                                <ListViewItem>
                                    <TextBlock Text="Item2"/>
                                </ListViewItem>
                                <ListViewItem>
                                    <TextBlock Text="Item3"/>
                                </ListViewItem>
                            </ListView>
                        </local:UserControlMenuItem.ListView>
                    </local:UserControlMenuItem>
                    <local:UserControlMenuItem  x:Name="MenuItem2" Header="User" Icon="User" PreviewMouseDown="MenuItemHome_PreviewMouseDown">
                        <local:UserControlMenuItem.ListView>
                            <ListView SelectionMode="Single" Margin="0 16 0 16">
                                <ListViewItem>
                                    <TextBlock Text="User1"/>
                                </ListViewItem>
                                <ListViewItem>
                                    <TextBlock Text="User2"/>
                                </ListViewItem>
                                <ListViewItem>
                                    <TextBlock Text="User3"/>
                                </ListViewItem>
                            </ListView>
                        </local:UserControlMenuItem.ListView>
                    </local:UserControlMenuItem>
                    <local:UserControlMenuItem  x:Name="MenuMes2" Header="Messages" Icon="Chat" PreviewMouseDown="MenuItemHome_PreviewMouseDown">
                        <local:UserControlMenuItem.ListView>
                            <ListView SelectionMode="Single" Margin="0 16 0 16">
                                <ListViewItem>
                                    <TextBlock Text="Message1"/>
                                </ListViewItem>
                                <ListViewItem>
                                    <TextBlock Text="Message2"/>
                                </ListViewItem>
                                <ListViewItem>
                                    <TextBlock Text="Message3"/>
                                </ListViewItem>
                            </ListView>
                        </local:UserControlMenuItem.ListView>
                    </local:UserControlMenuItem>
                </StackPanel>

MainWindow.cs

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            MenuItemHome.IsSelected = true;
        }

        private void MenuItemHome_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            foreach (var item in st_menu.Children)
            {
                if (item is UserControlMenuItem menuItem)
                {
                    if (menuItem.Equals(sender as UserControlMenuItem))
                    {
                        menuItem.IsSelected = true;
                    }
                    else
                    {
                        menuItem.IsSelected = false;
                    }
                }
            }
        }
    }

Solution

  • You should set eventArgs.Handled = true;, it will stop the event bubbling, like:

    private void MenuItemHome_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        foreach (var item in st_menu.Children)
        {
            if (item is UserControlMenuItem menuItem && sender is UserControlMenuItem senderItem)
            {
                menuItem.IsSelected = menuItem.Equals(senderItem) && !senderItem.IsSelected;                
                e.Handled = true; //Tells to the visual tree that event was already handled
            }
        }
    }