Scott
Scott

Reputation:

WPF RadioButton groups in Xaml

In the WPF app we are building, we have 3 groups of RadioButtons in individual StackPanels side by side. We are trying to program the following behavior. When tabbing through the form, we don't want to tab through each of the radiobuttons (standard behavior), instead we would like to tab to the "first" radiobutton in each group and have the ability to arrow up/down to the other radiobuttons (list) in each group once we tab to the group. We have set the IsTabStop=False for the radiobuttons below each of the first radiobutton in the list. This gives us the desired behavior for tabbing through each group, but this does not allow for the ability to arrow up/down the list. The arrow up/down behavior only works if the IsTabStop=True. We also tried setting the GroupName attribute of the radiobutton, but the behavior is the same as described above. In the old win forms, there was a radiobutton list control that had this behavior and we are just trying to recreate it. Does anyone have any idea as to how to recreate this behavior? Thanks in advance for your help...!

Upvotes: 7

Views: 14202

Answers (3)

Phil
Phil

Reputation: 43021

A solution is to use the technique of styling a list box to look like a radio button group. Then it's possible to tab between the styled list boxes, and use arrow keys to select individual 'radio button' list box items.

Here's a complete demo which can also be downloaded as a sample application

public class RadioButtonGroupsViewModel
{
    public RadioButtonGroupsViewModel()
    {
        Items1 = new List<string> {"One", "Two", "Three"};
        Selected1 = "One";

        Items2 = new List<string> {"Four", "Five", "Six"};
        Selected2 = "Five";

        Items3 = new List<string> {"Seven", "Eight", "Nine", "Ten"};
        Selected3 = "Ten";
    }

    public IEnumerable<string> Items1 { get; private set; }
    public string Selected1 { get; set; }

    public IEnumerable<string> Items2 { get; private set; }
    public string Selected2 { get; set; }

    public IEnumerable<string> Items3 { get; private set; }
    public string Selected3 { get; set; }
}

Xaml

xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" 

  <Page.Resources>  
    <Style x:Key="RadioButtonListBoxStyle" TargetType="ListBox">
      <Setter Property="BorderThickness" Value="0" />
      <Setter Property="ItemContainerStyle">
        <Setter.Value>
          <Style TargetType="ListBoxItem">
            <Setter Property="SnapsToDevicePixels" Value="true" />
            <Setter Property="OverridesDefaultStyle" Value="true" />
            <Setter Property="Template">
              <Setter.Value>
                <ControlTemplate TargetType="ListBoxItem">
                    <RadioButton 
                        IsTabStop="False"
                        GroupName=""
                        IsChecked="{Binding IsSelected, RelativeSource={RelativeSource TemplatedParent}}" >
                        <RadioButton.Content>
                            <Border VerticalAlignment=
                                    "{TemplateBinding Control.VerticalContentAlignment}" Padding="2">
                                <ContentPresenter 
                                    Margin="{TemplateBinding Control.Padding}"
                                    VerticalAlignment=
                                      "{TemplateBinding Control.VerticalContentAlignment}"
                                    HorizontalAlignment=
                                      "{TemplateBinding Control.HorizontalContentAlignment}" 
                                    RecognizesAccessKey="True" />
                            </Border>
                        </RadioButton.Content>
                    </RadioButton>
                </ControlTemplate>
              </Setter.Value>
            </Setter>
          </Style>
        </Setter.Value>
      </Setter>
    </Style>
  </Page.Resources>

  <Page.DataContext>
    <Samples:RadioButtonGroupsViewModel />
  </Page.DataContext>

  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="auto" />
      <RowDefinition Height="auto" />
      <RowDefinition Height="auto" />
      <RowDefinition />
    </Grid.RowDefinitions>

    <ListBox Style="{StaticResource RadioButtonListBoxStyle}" 
             ItemsSource="{Binding Items1}"
             SelectedItem="{Binding Selected1}">
      <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal" 
                      KeyboardNavigation.DirectionalNavigation="Cycle" />
        </ItemsPanelTemplate>
      </ListBox.ItemsPanel>
    </ListBox>

    <ListBox Grid.Row="1" 
             Style="{StaticResource RadioButtonListBoxStyle}" 
             ItemsSource="{Binding Items2}"
             SelectedItem="{Binding Selected2}">
      <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal" 
                      KeyboardNavigation.DirectionalNavigation="Cycle" />
        </ItemsPanelTemplate>
      </ListBox.ItemsPanel>
    </ListBox>

    <ListBox Grid.Row="2" 
             Style="{StaticResource RadioButtonListBoxStyle}" 
             ItemsSource="{Binding Items3}"
             SelectedItem="{Binding Selected3}">
      <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
          <StackPanel Orientation="Horizontal" 
                      KeyboardNavigation.DirectionalNavigation="Cycle" />
        </ItemsPanelTemplate>
      </ListBox.ItemsPanel>
    </ListBox>
  </Grid>

Upvotes: 3

John Love-Jensen
John Love-Jensen

Reputation: 53

I think the KeyboardNavigation attached properties will do the trick.

I mocked up a quick WPF example in XAML (sorry for the length), using ItemsControls to group the RadioButton elements:

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
  x:Class="Experiment.MainWindow"
  x:Name="Window"
  Title="MainWindow"
  Width="640" Height="480">

  <Grid x:Name="LayoutRoot">
    <Grid HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Margin="91,139,0,0">
      <ItemsControl KeyboardNavigation.IsTabStop="False" KeyboardNavigation.TabNavigation="Once" KeyboardNavigation.DirectionalNavigation="Contained">
        <RadioButton Content="Alpha" KeyboardNavigation.TabIndex="2"/>
        <RadioButton Content="Delta" KeyboardNavigation.TabIndex="2"/>
        <RadioButton Content="Gamma" IsChecked="True" KeyboardNavigation.TabIndex="1"/>
        <RadioButton Content="Beta" KeyboardNavigation.TabIndex="2"/>
      </ItemsControl>
    </Grid>
    <Grid HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Margin="244,139,0,0">
      <ItemsControl KeyboardNavigation.IsTabStop="False" KeyboardNavigation.TabNavigation="Once" KeyboardNavigation.DirectionalNavigation="Contained">
        <RadioButton x:Name="First" Content="Eenee" KeyboardNavigation.TabIndex="2"/>
        <RadioButton x:Name="Second" Content="Meenee" IsChecked="True" KeyboardNavigation.TabIndex="1"/>
        <RadioButton x:Name="Third" Content="Mynee" KeyboardNavigation.TabIndex="2"/>
        <RadioButton x:Name="Fourth" Content="Moe" KeyboardNavigation.TabIndex="2"/>
      </ItemsControl>
    </Grid>
    <Grid HorizontalAlignment="Left" Height="100" VerticalAlignment="Top" Width="100" Margin="391,139,0,0">
      <ItemsControl KeyboardNavigation.IsTabStop="False" KeyboardNavigation.TabNavigation="Once" KeyboardNavigation.DirectionalNavigation="Contained">
        <RadioButton Content="Extralarge" KeyboardNavigation.TabIndex="2"/>
        <RadioButton Content="Large" KeyboardNavigation.TabIndex="2"/>
        <RadioButton Content="Medium" KeyboardNavigation.TabIndex="2"/>
        <RadioButton Content="Small" IsChecked="True" KeyboardNavigation.TabIndex="1"/>
      </ItemsControl>
    </Grid>
  </Grid>
</Window>

Upvotes: 3

Reputation:

To change the orientation from left to right use the FlowDirection property to RightToLeft.

RadioButton is used in the group so that user can select only one option from the available options (No extra coding is required to uncheck others). Use same GroupName of the radiobuttons to mark in a group so that only one option can be selected as follows.

    <RadioButton Height="16" Margin="26,18,132,0" Name="RadioButton_Option1" VerticalAlignment="Top" Background="Snow" BorderBrush="Black"  GroupName="Visit_eggHeadcafe.com" Foreground="DarkBlue">ASP.net Articles </RadioButton>

    <RadioButton Height="16" Margin="26,18,132,0" Name="RadioButton_Option2" VerticalAlignment="Top" Background="Snow" BorderBrush="Black"  GroupName="Visit_eggHeadcafe.com" Foreground="DarkBlue">C# Articles</RadioButton>

    <RadioButton Height="16" Margin="26,18,132,0" Name="RadioButton_Option3" VerticalAlignment="Top" Background="Snow" BorderBrush="Black"  GroupName="Visit_eggHeadcafe.com" Foreground="DarkBlue">ADO.net Articles</RadioButton>

    <RadioButton Height="17" Margin="26,18,115,0" Name="RadioButton_Option4" VerticalAlignment="Top" Background="Snow" BorderBrush="Black"  GroupName="Visit_eggHeadcafe.com" Foreground="DarkBlue" Width="164">SQL Server 2005 Articles</RadioButton>

    <Button  Margin="26,18,132,0" Width="75" Height="20" Click="Button_Click">Open Articles</Button>

    </StackPanel > 

Upvotes: -2

Related Questions