Mysterio
Mysterio

Reputation: 139

WPF-C# StackPanel Visibility and ToggleButton

I am using C# and WPF to write a program which has a side menu like the one in the screenshot below.

enter image description here

The XAML Code for Menu Toggle Button 4 and 5 looks like this:

<ToggleButton x:Name="MenuBtn_4" Content="MENU TOGGLE BUTTON 4" />
<StackPanel x:Name="Submenu_4" Visibility="{Binding ElementName=MenuBtn_4, 
    Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, 
    FallbackValue=Visible}">
    <Button Content="SUBMENU BUTTON 1" />
    <Button Content="SUBMENU BUTTON 2" />
</StackPanel>

<ToggleButton x:Name="MenuBtn_5" Content="MENU TOGGLE BUTTON 5" />
<StackPanel x:Name="Submenu_5" Visibility="{Binding ElementName=MenuBtn_5, 
    Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, 
    FallbackValue=Visible}">
    <Button Content="SUBMENU BUTTON 1" />
    <Button Content="SUBMENU BUTTON 2" />
</StackPanel>

Right now if I click on the MenuToggleButton, the StackPanel with Submenu Buttons below becomes visible. If I click the ToggleButton again it collapses, which is what I want. But if the StackPanel of one Menu ToggleButton is visible and I click on another ToggleButton the first one stays visible. I would like it so that when another Menu ToggleButton is checked, the previously visible stack panels of the other Menu toggle buttons collapse. I tried solving this with MultiBinding but I cannot seem to make it work. Does anyone have any ideas how I could do this?

Upvotes: 0

Views: 1317

Answers (3)

Rekshino
Rekshino

Reputation: 7325

As "quick and dirty" you can solve it with XAML only if you put a hidden RadioButton and RadioButtons have a property GroupName, which provides that only one RadioButton is checked:

<StackPanel>
    <RadioButton x:Name="rb11" GroupName="G1" Visibility="Collapsed"/>
    <ToggleButton x:Name="tb11" IsChecked="{Binding IsChecked, ElementName=rb11}"  Content="111" />
    <StackPanel Visibility="{Binding IsChecked, ElementName=rb11, Converter={StaticResource Convert}}">
        <TextBlock Text="1111111111"/>
        <TextBlock Text="1111111111"/>
    </StackPanel>
    <RadioButton x:Name="rb22" GroupName="G1" Visibility="Collapsed"/>
    <ToggleButton x:Name="tb22" IsChecked="{Binding IsChecked, ElementName=rb22}" Content="222" />
    <StackPanel Visibility="{Binding IsChecked, ElementName=rb22, Converter={StaticResource Convert}}">
        <TextBlock Text="22222222222"/>
        <TextBlock Text="22222222222"/>
    </StackPanel>
</StackPanel>

Upvotes: 0

Corentin Pane
Corentin Pane

Reputation: 4943

You can use a MultiDataTrigger in a Style instead of a MultiBinding, causing each StackPanel to be visible only when the ToggleButton is checked and the other ToggleButton is not.

<Window.Resources>
    <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</Window.Resources>
<StackPanel>
    <ToggleButton x:Name="MenuBtn_4" Content="MENU TOGGLE BUTTON 4" Margin="0 5 0 5"/>
    <StackPanel x:Name="Submenu_4">
        <StackPanel.Style>
            <Style TargetType="StackPanel">
                <Setter Property="Visibility" Value="Collapsed"/>
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding ElementName=MenuBtn_4, Path=IsChecked}" Value="True"/>
                            <Condition Binding="{Binding ElementName=MenuBtn_5, Path=IsChecked}" Value="False"/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Control.Visibility" Value="Visible"/>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </StackPanel.Style>
        <StackPanel.Triggers>
        </StackPanel.Triggers>
        <Button Content="SUBMENU BUTTON 1" />
        <Button Content="SUBMENU BUTTON 2" />
    </StackPanel>

    <ToggleButton x:Name="MenuBtn_5" Content="MENU TOGGLE BUTTON 5" Margin="0 5 0 5"/>
    <StackPanel x:Name="Submenu_5">
        <StackPanel.Style>
            <Style TargetType="StackPanel">
                <Setter Property="Visibility" Value="Collapsed"/>
                <Style.Triggers>
                    <MultiDataTrigger>
                        <MultiDataTrigger.Conditions>
                            <Condition Binding="{Binding ElementName=MenuBtn_5, Path=IsChecked}" Value="True"/>
                            <Condition Binding="{Binding ElementName=MenuBtn_4, Path=IsChecked}" Value="False"/>
                        </MultiDataTrigger.Conditions>
                        <Setter Property="Control.Visibility" Value="Visible"/>
                    </MultiDataTrigger>
                </Style.Triggers>
            </Style>
        </StackPanel.Style>
        <Button Content="SUBMENU BUTTON 1" />
        <Button Content="SUBMENU BUTTON 2" />
    </StackPanel>
</StackPanel>

However, this won't force any ToggleButton to get unchecked when you check the other, and that's because it's not a correct use of the ToggleButton class. If you want truly exclusive behavior, you can use RadioButton as suggested in another answer or you could change the user experience by displaying sub menus when the mouse is over one of the header buttons instead of when a header is clicked.

Upvotes: 1

maulik kansara
maulik kansara

Reputation: 1107

You are facing such issue just because your window allows to check multiple ToggleButtons. Your issue can be resolved by implementing a logic which allows only one ToggleButton to be selected at a time.

And for this, you can use RadioButton which looks like ToggleButton in UI.

<RadioButton x:Name="MenuBtn_4" Content="MENU TOGGLE BUTTON 4" GroupName="grp1"
                              Style="{StaticResource {x:Type ToggleButton}}" cal:Message.Attach="MenuSelect"/>
                <StackPanel x:Name="Submenu_4" Visibility="{Binding ElementName=MenuBtn_4, 
                    Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, 
                    FallbackValue=Visible}">
                    <Button Style="{StaticResource MenuBtn}" Content="SUBMENU BUTTON 1"
                            cal:Message.Attach="SubmenuSelect"/>
                    <Button Style="{StaticResource MenuBtn}" Content="SUBMENU BUTTON 2"
                            cal:Message.Attach="SubmenuSelect"/>
                </StackPanel>

<RadioButton x:Name="MenuBtn_5" Content="MENU TOGGLE BUTTON 5" GroupName="grp1"
                              Style="{StaticResource {x:Type ToggleButton}}" cal:Message.Attach="MenuSelect"/>
                <StackPanel x:Name="Submenu_5" Visibility="{Binding ElementName=MenuBtn_5, 
                    Path=IsChecked, Converter={StaticResource BooleanToVisibilityConverter}, 
                    FallbackValue=Visible}">
                    <Button Style="{StaticResource MenuBtn}" Content="SUBMENU BUTTON 1"
                            cal:Message.Attach="SubmenuSelect"/>
                    <Button Style="{StaticResource MenuBtn}" Content="SUBMENU BUTTON 2"
                            cal:Message.Attach="SubmenuSelect"/>
                </StackPanel>

NOTE: if you can see, I have used style {StaticResource {x:Type ToggleButton}} but I think it should also work with your custom style {StaticResource ToggleMenuBtn}. But that you need to check.

Upvotes: 2

Related Questions