lls selecteditem binding through a behavior
Back in August I blogged about the ExtendedSelector, an extension of the LongListSelector that gave us a bindable SelectedItem property. A bit of a downside of this approach is that it’s basically a new control. Sure it inherits from the classic LLS underneath but it’s still another control in your XAML code.
Well, to fix this I’ve recreated the SelectedItem dependency property through a behavior.
The behavior
- public class SelectedItemBehavior : Behavior<LongListSelector>
- {
- public readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register(
- "SelectedItem", typeof(object), typeof(SelectedItemBehavior), new PropertyMetadata(default(object)));
- public object SelectedItem
- {
- get { return GetValue(SelectedItemProperty); }
- set { SetValue(SelectedItemProperty, value); }
- }
- protected override void OnAttached()
- {
- AssociatedObject.SelectionChanged += AssociatedObjectOnSelectionChanged;
- base.OnAttached();
- }
- protected override void OnDetaching()
- {
- AssociatedObject.SelectionChanged -= AssociatedObjectOnSelectionChanged;
- base.OnDetaching();
- }
- private void AssociatedObjectOnSelectionChanged(object sender, SelectionChangedEventArgs args)
- {
- SelectedItem = args.AddedItems[0];
- }
- }
It’s an easy one really. The behavior inherits from Behavior<LongListSelector> and has one dependency property. When the behavior gets attached to an LLS we attach the event handler to the SelectionChanged event. When detaching we cleanup by detaching the event handler.
When the SelectionChanged event fires we push the selected item into the dependency property.
Usage
Let’s throw together a quick little app to show the usage of the behavior. First the infamous Person class
- public class Person
- {
- public string Name { get; set; }
- public int Age { get; set; }
- }
Next is the MainViewModel
- public class MainViewModel : INotifyPropertyChanged
- {
- private ObservableCollection<Person> _persons;
- private Person _selectedPerson;
- public ObservableCollection<Person> Persons
- {
- get { return _persons; }
- set
- {
- if (_persons == value) return;
- _persons = value;
- OnPropertyChanged();
- }
- }
- public Person SelectedPerson
- {
- get { return _selectedPerson; }
- set
- {
- if (_selectedPerson == value) return;
- _selectedPerson = value;
- OnPropertyChanged();
- }
- }
- public MainViewModel()
- {
- Persons = new ObservableCollection<Person>();
- Random rnd = new Random();
- for (int i = 0; i < 20; i++)
- {
- var person = new Person {Name = "Person " + i, Age = rnd.Next(0, 80)};
- Persons.Add(person);
- }
- }
- public event PropertyChangedEventHandler PropertyChanged;
- protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
- {
- PropertyChangedEventHandler handler = PropertyChanged;
- if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
- }
- }
Two properties here, an observable collection that holds the persons and a SelectedPerson that will be bound to the dependency property on our behavior. The list of persons gets filled with some random data from the constructor.
Here’s the view
- <Grid x:Name="LayoutRoot" Background="Transparent">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="*" />
- </Grid.RowDefinitions>
- <!-- TitlePanel contains the name of the application and page title -->
- <StackPanel x:Name="TitlePanel"
- Grid.Row="0"
- Margin="12,17,0,28">
- <TextBlock Margin="12,0"
- Style="{StaticResource PhoneTextNormalStyle}"
- Text="MY APPLICATION" />
- <TextBlock Margin="9,-7,0,0"
- Style="{StaticResource PhoneTextTitle1Style}"
- Text="page name" />
- </StackPanel>
- <!-- ContentPanel - place additional content here -->
- <Grid x:Name="ContentPanel"
- Grid.Row="1"
- Margin="12,0,12,0">
- <Grid.RowDefinitions>
- <RowDefinition Height="Auto" />
- <RowDefinition Height="*" />
- </Grid.RowDefinitions>
- <TextBlock Grid.Row="0">
- <Run Text="Selected person is " />
- <Run Text="{Binding SelectedPerson.Age}" />
- <Run Text=" years old" />
- </TextBlock>
- <phone:LongListSelector Grid.Row="1"
- ItemsSource="{Binding Persons}">
- <phone:LongListSelector.ItemTemplate>
- <DataTemplate>
- <Grid Margin="0, 12, 0, 0">
- <TextBlock Text="{Binding Name}" />
- </Grid>
- </DataTemplate>
- </phone:LongListSelector.ItemTemplate>
- <i:Interaction.Behaviors>
- <vm:SelectedItemBehavior SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"/>
- </i:Interaction.Behaviors>
- </phone:LongListSelector>
- </Grid>
- </Grid>
Let’s extract the LongListSelector from that page as that’s the important piece
- <phone:LongListSelector Grid.Row="1"
- ItemsSource="{Binding Persons}">
- <phone:LongListSelector.ItemTemplate>
- <DataTemplate>
- <Grid Margin="0, 12, 0, 0">
- <TextBlock Text="{Binding Name}" />
- </Grid>
- </DataTemplate>
- </phone:LongListSelector.ItemTemplate>
- <i:Interaction.Behaviors>
- <vm:SelectedItemBehavior SelectedItem="{Binding SelectedPerson, Mode=TwoWay}"/>
- </i:Interaction.Behaviors>
- </phone:LongListSelector>
The ItemsSource is bound to the Persons ObservableCollection on the viewmodel. Underneath the ItemTemplate we attach the behavior and bind its property to the SelectedItem.
And that’s it, every time a person is selected from the LLS the SelectedPerson property gets updated on the viewmodel.
This is an imported post. It was imported from my old blog using an automated tool and may contain formatting errors and/or broken images.
Leave a Comment