RDV
RDV

Reputation: 1026

Add different controls in ItemsControl

I need to add different controls (TextBox/CheckBox/ComboBox, etc) in ItemsControl based on certain condition. Each Item in ItemsControl is a Name-Value pair. Name is always represented by TextBlock but Value can be any UI control. I am using horizontally aligned StackPanel to represent each Item. First control in StackPanel remains TextBlock but second control is dependent upon "ItemDataType" property set in ViewModel at runtime.

The problem I have is that I am not able to assign different controls in StackPanel's 2nd element using Style trigger with ItemDataType property.

Code Snippet:

<UserControl.Resources>

    <DataTemplate x:Key="TextBoxTemplate">
        <TextBox Text="{Binding Path=DataValue}"/>
    </DataTemplate>

    <DataTemplate x:Key="ComboBoxTemplate">
        <ComboBox ItemsSource="{Binding Path=SelectionList}" SelectedValue="{Binding Path=DataValue,Mode=TwoWay}"/>
    </DataTemplate>

    <DataTemplate x:Key="CheckBoxTemplate">
        <CheckBox IsChecked="{Binding Path=DataValue,Mode=TwoWay}" />
    </DataTemplate>

    <DataTemplate x:Key="ButtonTemplate">
        <Button Content="{Binding Path=DataValue}"/>
    </DataTemplate>

    <DataTemplate x:Key="dynamicTemplate">
        <StackPanel Orientation="Horizontal" Tag="{Binding ItemDataType}">
            <TextBlock Text="{Binding Path=DataName,Mode=TwoWay}"/>
            <ContentControl>
                <ContentControl.Style>
                    <Style TargetType="{x:Type ContentControl}">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding ItemDataType}" Value="TextBox">
                                <Setter Property="Template" Value="{StaticResource TextBoxTemplate}"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentControl.Style>
            </ContentControl>
        </StackPanel>
    </DataTemplate>

</UserControl.Resources>

<Grid>
    <!-- CONTROL LAYOUT -->
    <ItemsControl ItemsSource="{Binding Path=DataList,Mode=TwoWay}" ItemTemplate="{StaticResource dynamicTemplate}">

        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>
</Grid>

Error I get is DataTemplate invalid for ContentControl.Template property. I understand that what I am doing is wrong, but I want help to do it right way.

Thanks,

RDV

Upvotes: 0

Views: 2636

Answers (1)

RDV
RDV

Reputation: 1026

I wanted to have a XAML solution - took me sometime :-). Below is the working code:

    <Style x:Key="nvpTextBlockStyle" TargetType="{x:Type TextBlock}" BasedOn="{StaticResource {x:Type TextBlock}}">
        <Setter Property="HorizontalAlignment" Value="Left"/>
        <Setter Property="Width" Value="{Binding Path=LabelWidthStr, FallbackValue=50}"/>
        <Setter Property="Margin" Value="0,5,0,5"/>
        <Setter Property="Text" Value="{Binding Path=NameData,Mode=TwoWay}"/>
        <Setter Property="FontSize" Value="16"/>
    </Style>

    <DataTemplate x:Key="textBoxTemplate">
        <TextBox Margin="1,1" Text="{Binding Path=ValueData,UpdateSourceTrigger=PropertyChanged,
                    ValidatesOnExceptions=True,NotifyOnValidationError=True,ValidatesOnDataErrors=True}"/>
    </DataTemplate>

    <DataTemplate x:Key="comboBoxTemplate">
        <ComboBox HorizontalAlignment="Left" ItemsSource="{Binding Path=SelectionList}" 
                      SelectedValue="{Binding Path=ValueData,Mode=TwoWay}"
                      IsEnabled="{Binding IsDataItemEnabled}"/>
    </DataTemplate>

    <DataTemplate x:Key="checkBoxTemplate">
        <CheckBox HorizontalAlignment="Left" VerticalAlignment="Center"  
                      IsChecked="{Binding Path=ValueData,Mode=TwoWay}"/>
    </DataTemplate>

    <DataTemplate x:Key="buttonTemplate">
        <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.AddCommand}" 
                    CommandParameter="{Binding}" Width="30" Height="25">
            <TextBlock Text="&#x1F511;" FontFamily="Segoe UI Symbol" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Gray" />
        </Button>
    </DataTemplate>

    <DataTemplate x:Key="dynamicTemplate">
        <StackPanel Orientation="Horizontal" Margin ="5">
            <TextBlock Style="{StaticResource nvpTextBlockStyle}"/>
            <ContentPresenter Content="{Binding}" 
                Tag="{Binding Path=CustomDataType, FallbackValue={x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}}">
                <ContentPresenter.Resources>
                    <Style TargetType="{x:Type ContentPresenter}">
                        <Style.Triggers>
                            <Trigger Property="Tag" Value="{x:Static local:CustomViewModel.TEXTBOX_TEMPLATE}">
                                <Setter Property="ContentTemplate" Value="{StaticResource textBoxTemplate}"/>
                            </Trigger>
                            <Trigger Property="Tag" Value="{x:Static local:CustomViewModel.COMBOBOX_TEMPLATE}">
                                <Setter Property="ContentTemplate" Value="{StaticResource comboBoxTemplate}"/>
                            </Trigger>
                            <Trigger Property="Tag" Value="{x:Static local:CustomViewModel.CHECKBOX_TEMPLATE}">
                                <Setter Property="ContentTemplate" Value="{StaticResource checkBoxTemplate}"/>
                            </Trigger>
                            <Trigger Property="Tag" Value="{x:Static local:CustomViewModel.BUTTON_TEMPLATE}">
                                <Setter Property="ContentTemplate" Value="{StaticResource buttonTemplate}"/>
                            </Trigger>
                        </Style.Triggers>
                    </Style>
                </ContentPresenter.Resources>
            </ContentPresenter>
        </StackPanel>
    </DataTemplate>

    <Grid>       
    <ScrollViewer VerticalScrollBarVisibility="Auto">
        <ItemsControl  ItemsSource="{Binding Path=CustomDataList,Mode=TwoWay}" 
                       ItemTemplate="{StaticResource dynamicTemplate}";
                       KeyboardNavigation.IsTabStop="False">
            <ItemsPanelTemplate>
                <StackPanel></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl>
    </ScrollViewer>

</Grid>

Thanks,

RDV

Upvotes: 1

Related Questions