views:

846

answers:

1

I'm trying to write a UserControl to display a list of items where each of these items is a title and a group of checkboxes. This whole will represent a form of data where the person filling it in is answering a list of questions with a 1 to 4 value. This all works and binds nicely to the window's ViewModel.

But I've currently got the answers hardcoded in the UserControl as follows:

<ListBox
  ItemsPanel="{StaticResource HorizontalScores}"
  Style="{StaticResource styleOuterListBox}"
  ItemContainerStyle="{StaticResource styleOuterListBoxItem}">
  <ListBoxItem>Never</ListBoxItem>
  <ListBoxItem>Sometimes</ListBoxItem>
  <ListBoxItem>Often</ListBoxItem>
  <ListBoxItem>Always</ListBoxItem>
</ListBox>

I would like to set these from the window's XAML or from the ViewModel as they will be different for other forms but can't see the correct incantation. How do I remove the ListBoxItems from the UserControl and use databinding instead?

BigEdit ...

Ok, this is the actual user control (it looks hideous but that's not the point):

<UserControl x:Class="BussPerry.Scorer" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:BussPerry.ViewModel" xmlns:local="clr-namespace:BussPerry">

  <UserControl.Resources>

    <SolidColorBrush x:Key="SelectedBackgroundBrush" Color="Gray" />
    <SolidColorBrush x:Key="SelectedForegroundBrush" Color="Red" />

    <ItemsPanelTemplate x:Key="HorizontalScores">
      <StackPanel Orientation="Horizontal" />
    </ItemsPanelTemplate>

    <Style x:Key="styleListBox" TargetType="{x:Type ListBox}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ListBox}">
            <ItemsPresenter Margin="2" />
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <Style x:Key="styleListBoxItem" TargetType="{x:Type ListBoxItem}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ListBoxItem}">
            <CheckBox Name="CheckBox" Padding="1" Width="60" 
           IsChecked="{Binding Path=IsSelected, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
              <ContentPresenter HorizontalAlignment="Center"/>
            </CheckBox>
            <ControlTemplate.Triggers>
              <Trigger Property="IsSelected" Value="True">
                <Setter TargetName="CheckBox" Property="Background" Value="{StaticResource SelectedBackgroundBrush}" />
                <Setter TargetName="CheckBox" Property="Foreground" Value="{StaticResource SelectedForegroundBrush}" />
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

  </UserControl.Resources>

  <ListBox ItemsPanel="{StaticResource HorizontalScores}" Style="{StaticResource styleListBox}" 
      ItemContainerStyle="{StaticResource styleListBoxItem}" SelectedIndex="{Binding Path=Score}">
    <ListBoxItem>Never</ListBoxItem>
    <ListBoxItem>Sometimes</ListBoxItem>
    <ListBoxItem>Often</ListBoxItem>
    <ListBoxItem>Always</ListBoxItem>
  </ListBox>

</UserControl>

And it's being called as follows:

<ListView
  Name="listviewScores"
  ItemsSource="{Binding Path=Scores}"

  Margin="5"
  BorderThickness="0"
  Background="Transparent"
  Focusable="False"
  Grid.Row="3">
  <ListView.View>
    <GridView
      ColumnHeaderContainerStyle="{StaticResource styleHiddenHeader}">
      <GridView.Columns>

        <GridViewColumn>
          <GridViewColumn.CellTemplate>
            <DataTemplate>
              <TextBlock
                Text="{Binding Path=Index}"
                HorizontalAlignment="Right" />
              </DataTemplate>
          </GridViewColumn.CellTemplate>
        </GridViewColumn>

        <GridViewColumn
          DisplayMemberBinding="{Binding Path=Title}" />

        <GridViewColumn >
          <GridViewColumn.CellTemplate>
            <DataTemplate>
              <local:Scorer >
              </local:Scorer>
            </DataTemplate>
          </GridViewColumn.CellTemplate>
        </GridViewColumn>
      </GridView.Columns>
    </GridView>
  </ListView.View>

</ListView>

What I want to do is to move the Never/Sometimes/Often/Always listboxitems from being hard coded in the user control to be databound.

(Suggestions of "you don't want to do it like that" are also welcome!)

A: 

Do you want to bind a collection to a listbox?

It's pretty simple...

<ListBox ItemsSource="{Binding Answers}" />

where Answers is your collection exposed in your ViewModel.

If you're having trouble creating a custom control that exposes an ItemsSource, then you just need to inherit from ItemsControl instead of just UserControl.

EDIT: Some assumptions:

  • the DataContext of the ListBox, custom control, or higher parent element is set to your ViewModel.
  • the ViewModel has a property called "Answers".
  • the Answers property implements IEnumerable<>.
SergioL
With this, just make sure you set the DataContext of your usercontrol. so in XAML:<YourUserControl ... DataContext="{StaticResource YourData}" />And YourData contains a property named Answers like SergioL was saying above.
Mark Synowiec
@Mark - Yeah, I just assumed that knowledge...should have been explicit.
SergioL
I really want to bind to two collections, one to the listbox showing the rows and the other to the listbox showing the columns.
amaca
@amaca - perhaps you can rephrase your question. ListBoxes don't have column headers. If you custom control contains headers, than you'd need to expose a dependency property to accept another IEnumerable...then you'd have to handle that data in your template.
SergioL