1

I have a WPF UserControl which is dynamically created at runtime. Depending on user interaction, from 1-5 of these controls is created and should be added to the UI.

I have an ObservableCollection<PlayerSpec> PlayerSpecViews in the xaml.cs code-behind.

Initially I tried using a Grid and dynamically adding RowDefinitions but that wasn't working. The control would be scaled down in size.

Then I tried using an ItemsControl but the binding was not adding the Control but instead the type name.

How can I use databinding to have the control added and placed in a vertical manner? Bonus info might include vertical scroll bar if needed.

My current XAML and binding are as follows:

<ItemsControl Name="PlayerSpecItems"
              HorizontalContentAlignment="Stretch"
              ItemsSource="{Binding Source=PlayerSpecViews}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel HorizontalAlignment="Stretch"
                        VerticalAlignment="Stretch" 
                        Height="95"
                        Width="175"
                        Margin="1">
                <local:PlayerSpec/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Classes XAML:

<!-- PlayerSpec -->
<Border Style="{StaticResource InnerBorder}"
        HorizontalAlignment="Stretch">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50"/>
            <ColumnDefinition Width="98"/>
            <ColumnDefinition Width="21"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Label Style="{StaticResource DefaultFont}"
               Grid.Column="0" 
               Grid.Row="0"
               VerticalAlignment="Stretch"
               VerticalContentAlignment="Center"
               HorizontalAlignment="Stretch"
               HorizontalContentAlignment="Right"
               Margin="1"
               Content="Name"/>
        <TextBox Style="{StaticResource DefaultFont}"
                 Name="PlayerName"
                 Background="Transparent"
                 Grid.Column="1"
                 Grid.Row="0"
                 Margin="1"/>
        <Grid Grid.Column="0"
              Grid.ColumnSpan="2"
              Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="25"/>
                <ColumnDefinition Width="25"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="25"/>
                <RowDefinition Height="25"/>
            </Grid.RowDefinitions>
            <Label Style="{StaticResource DefaultFont}"
                   Grid.Column="2"
                   Grid.Row="0"
                   VerticalAlignment="Stretch"
                   VerticalContentAlignment="Center"
                   HorizontalAlignment="Stretch"
                   HorizontalContentAlignment="Stretch"
                   Content="Automaton"/>
            <RadioButton GroupName="PlayerTypeGroup"
                     Name="PlayerAutomaton"
                     Grid.Column="1"
                     Grid.ColumnSpan="2"
                     Grid.Row="0"
                     Grid.IsSharedSizeScope="True"
                     VerticalAlignment="Center">
            </RadioButton>
            <Label Style="{StaticResource DefaultFont}"
               Grid.Column="2"
               Grid.Row="1"
               VerticalAlignment="Center"
               VerticalContentAlignment="Center"
               HorizontalAlignment="Stretch"
               HorizontalContentAlignment="Stretch"
               Content="Human"/>
            <RadioButton GroupName="PlayerType"
                     Name="PlayerHuman"
                     Grid.Column="1"
                     Grid.ColumnSpan="2"
                     Grid.Row="1"
                     Grid.IsSharedSizeScope="True"
                     VerticalAlignment="Center">
            </RadioButton>

        </Grid>
    </Grid>
</Border>
IAbstract
  • 19,551
  • 15
  • 98
  • 146
  • Unless I am misunderstanding you, you want to add new items to what is already show. Just make sure the collection you're binding to (PlayerSpecViews) is a bind-friendly list (i.e. ObservableCollection) then just add to the list in code behind and the ItemsControl will update the UI accordingly. – GEEF Jun 03 '14 at 23:11
  • I am using an ObservableCollection to bind to. The control is not getting added and/or rendering. – IAbstract Jun 03 '14 at 23:19
  • You don't do an `ObservableCollection` of UI elements. Instead, do an `ObservableCollection` of relevant **data** items that contain the **data** you want to show on screen. Post your full code (including the `PlayerSpec` class) – Federico Berasategui Jun 03 '14 at 23:19
  • So the issue with using the ItemsControl as you show here is that the type name is showing up? If that is the case you just need to edit your DataTemplate to display specific PlayerSpec fields you want, i.e. Bind a TextBlock to the PlayerSpec.FirstName, and another to PlayerSpec.LastName, etc. – GEEF Jun 03 '14 at 23:22
  • Also, remove the `StackPanel` from the ItemTemplate. It doesn't do what I guess you think it does. The `ItemTemplate` defines how to display `each item`. If you need to define how to `layout` items in the ItemsControl, use `ItemsControl.ItemsPanel` property. – Federico Berasategui Jun 03 '14 at 23:24
  • Changed `Source=` to `Path=`. Now the ItemsControl is adding the Control to it's collection. However, the control is not getting rendered. – IAbstract Jun 03 '14 at 23:50
  • @HighCore: so I should paste the XAML for PlayerSpec into the ItemsControl and bind the elements of PlayerSpec to the ViewModel? – IAbstract Jun 03 '14 at 23:57
  • @IAbstract yes, pretty much. The ItemTemplate of the ItemsControl will contain the Labels, TextBoxes, etc which are bound to the properties of the VM and so on. – Federico Berasategui Jun 04 '14 at 00:43

1 Answers1

4

Issues with your code

  • ItemsControl does not have its scrollbar so need to add an ScrollViewer
  • Binding source of ItemsControl's ItemsSource is set to PlayerSpecViews which does not look normal, I expect it to be from datacontext
  • Stack panel is not serving any purpose in data template

so your revised code is

<ScrollViewer>
    <ItemsControl Name="PlayerSpecItems" 
                  HorizontalContentAlignment="Stretch" 
                  ItemsSource="{Binding PlayerSpecViews}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <local:PlayerSpec Margin="1"/>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</ScrollViewer>

So this code should be rendering local:PlayerSpec for every item you have in your PlayerSpecViews collection subjected to correct binding

pushpraj
  • 13,458
  • 3
  • 33
  • 50
  • 2
    Just to add to this answer, PlayerSpecViews should be an ObservableCollection in your data context and each entry in this collection should serve as the data context for each PlayerSpec rendered in your ItemControl – ankhuri Jun 04 '14 at 04:10