Allow user to select only one Checkbox at a time in LongListSelector Windows Phone 8 App

To allow user to select only one checkbox at a time in LongListselector or ListBox of windows phone follow the below given steps. To achieve this the key points are implementing INotifyPropertyChanged Interface and setting Binding Mode Mode=TwoWay, so that whenever change occurs either in data or in UI, both get reflected.

Credits: Scott Logic

binding

Step 1:

First create the UI for our LongListSelector.

  1. <phone:PhoneApplicationPage  
  2. x:Class="LongListSelector_With_Check_Boxes.MainPage"  
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  4.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  5.     xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"  
  6.     xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"  
  7.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"  
  8.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
  9. mc:Ignorable="d"  
  10. FontFamily="{StaticResource PhoneFontFamilyNormal}"  
  11. FontSize="{StaticResource PhoneFontSizeNormal}"  
  12. Foreground="{StaticResource PhoneForegroundBrush}"  
  13. SupportedOrientations="Portrait" Orientation="Portrait"  
  14. shell:SystemTray.IsVisible="False">  
  15.     <phone:PhoneApplicationPage.Resources>  
  16.         <Style x:Key="CheckBoxStyle" TargetType="CheckBox">  
  17.             <Setter Property="Template">  
  18.                 <Setter.Value>  
  19.                     <ControlTemplate TargetType="CheckBox">  
  20.                         <Grid Background="Transparent" HorizontalAlignment="Left">  
  21.                             <!--Margin input-->  
  22.                             <VisualStateManager.VisualStateGroups>  
  23.                                 <VisualStateGroup x:Name="CommonStates">  
  24.                                     <VisualState x:Name="Normal"/>  
  25.                                     <VisualState x:Name="MouseOver"/>  
  26.                                     <VisualState x:Name="Disabled">  
  27.                                         <Storyboard>  
  28.                                             <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="CheckBackground">  
  29.                                                 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>  
  30.                                             </ObjectAnimationUsingKeyFrames>  
  31.                                             <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="CheckMark">  
  32.                                                 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>  
  33.                                             </ObjectAnimationUsingKeyFrames>  
  34.                                             <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Fill" Storyboard.TargetName="IndeterminateMark">  
  35.                                                 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>  
  36.                                             </ObjectAnimationUsingKeyFrames>  
  37.                                             <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer">  
  38.                                                 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/>  
  39.                                             </ObjectAnimationUsingKeyFrames>  
  40.                                         </Storyboard>  
  41.                                     </VisualState>  
  42.                                 </VisualStateGroup>  
  43.                                 <VisualStateGroup x:Name="CheckStates">  
  44.                                     <VisualState x:Name="Checked">  
  45.                                         <Storyboard>  
  46.                                             <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="CheckMark">  
  47.                                                 <DiscreteObjectKeyFrame KeyTime="0">  
  48.                                                     <DiscreteObjectKeyFrame.Value>  
  49.                                                         <Visibility>Visible</Visibility>  
  50.                                                     </DiscreteObjectKeyFrame.Value>  
  51.                                                 </DiscreteObjectKeyFrame>  
  52.                                             </ObjectAnimationUsingKeyFrames>  
  53.                                         </Storyboard>  
  54.                                     </VisualState>  
  55.                                     <VisualState x:Name="Unchecked"/>  
  56.                                     <VisualState x:Name="Indeterminate">  
  57.                                         <Storyboard>  
  58.                                             <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="IndeterminateMark">  
  59.                                                 <DiscreteObjectKeyFrame KeyTime="0">  
  60.                                                     <DiscreteObjectKeyFrame.Value>  
  61.                                                         <Visibility>Visible</Visibility>  
  62.                                                     </DiscreteObjectKeyFrame.Value>  
  63.                                                 </DiscreteObjectKeyFrame>  
  64.                                             </ObjectAnimationUsingKeyFrames>  
  65.                                         </Storyboard>  
  66.                                     </VisualState>  
  67.                                 </VisualStateGroup>  
  68.                             </VisualStateManager.VisualStateGroups>  
  69.                             <Grid Margin="{StaticResource PhoneTouchTargetLargeOverhang}">  
  70.                                 <Grid.ColumnDefinitions>  
  71.                                     <ColumnDefinition Width="32"/>  
  72.                                     <ColumnDefinition Width="*"/>  
  73.                                 </Grid.ColumnDefinitions>  
  74.                                 <Grid Grid.Column="0" VerticalAlignment="Top">  
  75.                                     <Border x:Name="CheckBackground" BorderBrush="#9db0b5" BorderThickness="{StaticResource PhoneBorderThickness}" Background="{TemplateBinding Background}" HorizontalAlignment="Left" Height="32" IsHitTestVisible="False" VerticalAlignment="Center" Width="32"/>  
  76.                                     <Rectangle x:Name="IndeterminateMark" Fill="{StaticResource PhoneRadioCheckBoxCheckBrush}" HorizontalAlignment="Center" Height="16" IsHitTestVisible="False" Visibility="Collapsed" VerticalAlignment="Center" Width="16"/>  
  77.                                     <Path x:Name="CheckMark" Data="M0,123 L39,93 L124,164 L256,18 L295,49 L124,240 z" Fill="#9db0b5" FlowDirection="LeftToRight" HorizontalAlignment="Center" Height="21" IsHitTestVisible="False" Stretch="Fill" StrokeThickness="3" StrokeLineJoin="Round" Visibility="Collapsed" VerticalAlignment="Center" Width="23"/>  
  78.                                 </Grid>  
  79.                             </Grid>  
  80.                         </Grid>  
  81.                     </ControlTemplate>  
  82.                 </Setter.Value>  
  83.             </Setter>  
  84.         </Style>  
  85.         <DataTemplate x:Key="groupHeaderTemplate">  
  86.             <StackPanel Grid.Row="0" Background="White">  
  87.                 <TextBlock Text="{Binding Title}" Foreground="Red"></TextBlock>  
  88.             </StackPanel>  
  89.         </DataTemplate>  
  90.         <phone:JumpListItemBackgroundConverter x:Key="BackgroundConverter"/>  
  91.         <phone:JumpListItemForegroundConverter x:Key="ForegroundConverter"/>  
  92.         <Style x:Key="LLSJumpListStyle" TargetType="phone:LongListSelector">  
  93.             <Setter Property="GridCellSize" Value="113,113"/>  
  94.             <Setter Property="LayoutMode" Value="Grid" />  
  95.             <Setter Property="ItemTemplate">  
  96.                 <Setter.Value>  
  97.                     <DataTemplate>  
  98.                         <Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="113" Height="113" Margin="6" >  
  99.                             <TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6"   
  100. Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>  
  101.                         </Border>  
  102.                     </DataTemplate>  
  103.                 </Setter.Value>  
  104.             </Setter>  
  105.         </Style>  
  106.         <Style x:Name="DividerStyle" TargetType="Border">  
  107.             <Setter Property="BorderBrush" Value="Gray"></Setter>  
  108.             <Setter Property="BorderThickness" Value="0 0 0 1"></Setter>  
  109.             <Setter Property="Margin" Value="0 18 0 18"></Setter>  
  110.             <Setter Property="Width" Value="450"></Setter>  
  111.             <Setter Property="Opacity" Value="0.7"></Setter>  
  112.         </Style>  
  113.     </phone:PhoneApplicationPage.Resources>  
  114.     <!--LayoutRoot is the root grid where all page content is placed-->  
  115.     <Grid x:Name="LayoutRoot" Background="Transparent">  
  116.         <Grid.RowDefinitions>  
  117.             <RowDefinition Height="Auto"/>  
  118.             <RowDefinition Height="*"/>  
  119.         </Grid.RowDefinitions>  
  120.         <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">  
  121.             <TextBlock Text="Demo App" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>  
  122.         </StackPanel>  
  123.         <!--ContentPanel - place additional content here-->  
  124.         <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">  
  125.             <phone:LongListSelector x:Name="lbTags" Background="Transparent"  
  126. Margin="10,0"   
  127. LayoutMode="List"   
  128. SelectionChanged="llsPref_SelectionChanged">  
  129.                 <phone:LongListSelector.ItemTemplate>  
  130.                     <DataTemplate>  
  131.                         <Grid HorizontalAlignment="Stretch">  
  132.                             <Grid.RowDefinitions>  
  133.                                 <RowDefinition Height="*"/>  
  134.                                 <RowDefinition Height="*"/>  
  135.                             </Grid.RowDefinitions>  
  136.                             <Grid.ColumnDefinitions>  
  137.                                 <ColumnDefinition Width="0.5*"/>  
  138.                                 <ColumnDefinition Width="3*"/>  
  139.                             </Grid.ColumnDefinitions>  
  140.                             <CheckBox Grid.Column="0" IsChecked="{Binding CheckboxState, Mode=TwoWay}" Grid.Row="0" Grid.RowSpan="2" x:Name="chkDelete" Visibility="Visible" Margin="2,16,10,20" Grid.ColumnSpan="2" Click="CheckBox_Click" />  
  141.                             <TextBlock Text="{Binding NoteName}" FontSize="{StaticResource PhoneFontSizeLarge}" FontFamily="Segoe WP" Grid.Row="0" Foreground="Red" Grid.Column="1" Margin="12,24,0,0" />  
  142.                         </Grid>  
  143.                     </DataTemplate>  
  144.                 </phone:LongListSelector.ItemTemplate>  
  145.             </phone:LongListSelector>  
  146.         </Grid>  
  147.     </Grid>  
  148. </phone:PhoneApplicationPage>  
Now Implement the Class File
  1. public class sample_data: INotifyPropertyChanged   
  2. {  
  3.     // simple constructor  
  4.     public sample_data(string noteName, Boolean checkboxState)   
  5.     {  
  6.         this.NoteName = noteName;  
  7.         this.CheckboxState = checkboxState;  
  8.     }  
  9.   
  10.   
  11.     // implement the INotify  
  12.     public event PropertyChangedEventHandler PropertyChanged;  
  13.     private void NotifyPropertyChanged(String propertyName)   
  14.     {  
  15.         PropertyChangedEventHandler handler = PropertyChanged;  
  16.         if (null != handler)   
  17.         {  
  18.             handler(thisnew PropertyChangedEventArgs(propertyName));  
  19.         }  
  20.     }  
  21.   
  22.   
  23.     // {Binding Properties}  
  24.     Boolean checkbox_state;  
  25.     public Boolean CheckboxState   
  26.     {  
  27.         get   
  28.         {  
  29.             return checkbox_state;  
  30.         }  
  31.         set   
  32.         {  
  33.             checkbox_state = value;  
  34.             NotifyPropertyChanged("CheckboxState");  
  35.         }  
  36.     }  
  37.   
  38.   
  39.     string note_name;  
  40.     public string NoteName   
  41.     {  
  42.         get {  
  43.             return note_name;  
  44.         }  
  45.         set {  
  46.             note_name = value;  
  47.             NotifyPropertyChanged("NoteName");  
  48.         }  
  49.     }  
  50.   
  51.   
  52. }  
NotifyPropertyChanged notifies that something is changed, Observable Collection always watches the collection for any changes.

Now go to MainPage.xaml.cs Page
  1. public partial class MainPage: PhoneApplicationPage   
  2. {  
  3.     // Constructor  
  4.     List < sample_data > currentList = new List < sample_data > ();  
  5.   
  6.   
  7.     public MainPage()   
  8.     {  
  9.         InitializeComponent();  
  10.         lbTags.ItemsSource = CreateData();  
  11.     }  
  12.     public ObservableCollection < sample_data > CreateData()   
  13.     {  
  14.         ObservableCollection < sample_data > my_list = new ObservableCollection < sample_data > ();  
  15.         my_list.Add(new sample_data("one"false));  
  16.         my_list.Add(new sample_data("two"true));  
  17.         my_list.Add(new sample_data("three"false));  
  18.         my_list.Add(new sample_data("four"true));  
  19.         my_list.Add(new sample_data("five"false));  
  20.         my_list.Add(new sample_data("six"true));  
  21.         my_list.Add(new sample_data("seven"false));  
  22.         my_list.Add(new sample_data("eight"true));  
  23.         return my_list;  
  24.     }  
  25.     public void CheckBox_Click(object sender, RoutedEventArgs e)   
  26.     {  
  27.         CheckBox chk = (CheckBox) sender;  
  28.         var checkBox = (CheckBox) sender;  
  29.         var data = (sample_data) chk.DataContext;  
  30.         var id = data.NoteName;  
  31.         foreach(sample_data sd in lbTags.ItemsSource)   
  32.         {  
  33.             if (id == sd.NoteName)   
  34.             {  
  35.                 sd.CheckboxState = data.CheckboxState;  
  36.                 //Setting Current Clicked CheckBox Property Value   
  37.             }   
  38.             else   
  39.             {  
  40.                 sd.CheckboxState = data.CheckboxState ? false : false;  
  41.                 //Setting Remaining all CheckBox Other Than Selected To Unchecked  
  42.             }  
  43.         }  
  44.   
  45.   
  46.     }  
  47.     public void llsPref_SelectionChanged(object sender, SelectionChangedEventArgs e) {}  
  48. }  
If you have any doubt please comment below and find the attached demo project for any reference.
Thank You!