18

I have the following code which populates my user control in form of rows and column. The user control which is being populated contains Button, links, textbox etc. When a certain button is pressed on a particular User Control in a particular row/column, I need to know for which User Control that button was pressed. Here is the XAML that is populating the user controls in rows and columns

  <ItemsControl ItemsSource="{Binding Templates}" Width="{Binding GridWidth}">
        <ItemsControl.ItemsPanel>
              <ItemsPanelTemplate>
                    <UniformGrid Columns="{Binding NumColumns}" />
              </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
              <ItemsControl.ItemContainerStyle>
                 <Style>
                     <Setter Property="Grid.Column" Value="{Binding ColumnIndex}" />
                     <Setter Property="Grid.Row" Value="{Binding RowIndex}" />
                  </Style>
                 </ItemsControl.ItemContainerStyle>
                 <ItemsControl.ItemTemplate>
  </ItemsControl>

Templates is basically a collection of UserControls that are being populated in Rows/Columns. Preferably I want to do this in ViewModel but solution in code behind for now will work as well.

Cœur
  • 37,241
  • 25
  • 195
  • 267
WAQ
  • 2,556
  • 6
  • 45
  • 86
  • 4
    An `ItemsControl` does not track the selected item. If you want that behavior, use something like a `ListBox` and overwrite the template, like [this](http://stackoverflow.com/a/9069382/302677) – Rachel Aug 31 '13 at 01:30

3 Answers3

28

ItemsControl can't select items, only present collections. Only a Selector or one of it's descendants can select items.

For your scenario, I think a ListView with GridView would fit. When the user would click a control in the line, the event would bubble to the ListView and the item would get selected. You can override the default styles so it wouldn't display as selected line: WPF ListView turn off selection.

Community
  • 1
  • 1
CKII
  • 1,439
  • 14
  • 26
0

You can use ListView, and add a SelectionChanged event. Then you implement a function to verify ListView.SelectedItem just like a DataGrid

-1

I have a solution for you...a behavior:

   public static class SelectedItemBehavior
   {
      public static readonly DependencyProperty BindingProperty =
         DependencyProperty.RegisterAttached("Binding", typeof(object), typeof(SelectedItemBehavior),
            new FrameworkPropertyMetadata(new object(),
               FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
               SelectedItem_Changed));

      public static object GetBinding(FrameworkElement frameworkElement)
      {
         return (object)frameworkElement.GetValue(BindingProperty);
      }

      public static void SetBinding(FrameworkElement frameworkElement, object value)
      {
         frameworkElement.SetValue(BindingProperty, value);
      }

      private static void SelectedItem_Changed(Object sender, DependencyPropertyChangedEventArgs e)
      {
         ToggleButton toggleButton = (ToggleButton)sender;
         toggleButton.Checked -= ToggleButtonOnChecked;
         toggleButton.IsChecked = e.NewValue?.Equals(toggleButton.DataContext) ?? false;
         toggleButton.Checked += ToggleButtonOnChecked;
      }

      private static void ToggleButtonOnChecked(object sender, RoutedEventArgs e)
      {
         ToggleButton toggleButton = (ToggleButton)sender;
         SetBinding(toggleButton, toggleButton.DataContext);
      }
   }

Then bind as follows:

    <ItemsControl
        Name="ItemsControlList"
        Width="200"
        Height="100"
        ItemsSource="{Binding Values}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <RadioButton local:SelectedItemBehavior.Binding="{Binding ElementName=ItemsControlList, Path=DataContext.SelectedValue}" Content="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>