corentinaltepe
corentinaltepe

Reputation: 213

WPF - How to add a textbox to the panel containing the Items of an ItemsControl

My ViewModel has properties of type MultipleSelectionInfo which looks like this (I've removed the PropertyChanged related code for clarity, but my binding works):

public abstract class MultipleSelectionInfo
{
    // A SelectableObject is made of a bool IsSelected and a string ObjectData
    public ObservableCollection<SelectableObject<string>> Items
    { get; set; }

    public string Others
    { get; set; }
}

I display these properties like that:

TextBox pushed to the bottom TextBox pushed to the right

My XAML looks like that:

<DataTemplate x:Key="PrepControl">
        <WrapPanel Orientation="Horizontal" HorizontalAlignment="Left">
            <ItemsControl ItemsSource="{Binding Items}">
                <ItemsControl.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <CheckBox Content="{Binding ObjectData}" IsChecked="{Binding IsSelected}" Margin="0,6,8,0"/>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>

            <TextBox MaxWidth="400" MinWidth="100"
                     MaxHeight="20" Text="{Binding Others}" IsEnabled="{Binding IsOthersSelected}"
                      HorizontalAlignment="Left"/>
        </WrapPanel>
    </DataTemplate>

To sumup, I'm displaying the items of MultipleSelectionInfo in an ItemsControl (horizontal WrapPanel), then I display the TextBox. Finally, I wrap the whole in an horizontal WrapPanel.

The issue with this is that the TextBox doesn't align nicely with the items, because of the WrapPanels. Ideally, if I could add the TextBox inside the WrapPanel of the ItemsControl, that would fix it. But I couldn't manage to do that.

Is it possible? How should I do? I would gladly avoid manipulating the controls/panels programmatically. If I really have to, I'm not very familiar with MVVM, would you care to explain?

Below is what I expect to achieve: Expected display 1 Expected display 2

Upvotes: 2

Views: 1166

Answers (1)

ASh
ASh

Reputation: 35646

universal approach is to create a DataTemplateSelector

Typically, you create a DataTemplateSelector when you have more than one DataTemplate for the same type of objects and you want to supply your own logic to choose a DataTemplate to apply based on the properties of each data object

in the given case I would try a Trigger, which modifies ContentTemplate for Others item:

<DataTemplate x:Key="PrepControl">
<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <CheckBox Content="{Binding ObjectData}" 
                            IsChecked="{Binding IsSelected}" 
                            Margin="0,6,8,0">
                    <CheckBox.Style>
                        <Style TargetType="CheckBox">
                            <Style.Triggers>
                                <Trigger Property="Content" Value="Others">
                                    <Setter Property="ContentTemplate">
                                        <Setter.Value>
                                            <DataTemplate>
                                                <StackPanel Orientation="Horizontal">
                                                    <TextBlock Text="{Binding}" VerticalAlignment="Center"/>
                                                    <TextBox Margin="5,0" VerticalAlignment="Center"
                                                                MinWidth="50"
                                                                IsEnabled="{Binding IsChecked, RelativeSource={RelativeSource AncestorType=CheckBox}}"
                                                                Text="{Binding Path=DataContext.Others, ElementName=Lst}"/>
                                                </StackPanel>
                                            </DataTemplate>
                                        </Setter.Value>
                                    </Setter>
                                </Trigger>
                            </Style.Triggers>
                        </Style>
                    </CheckBox.Style>
                </CheckBox>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>


variant with DataTemplate selection via Trigger

<ItemsControl ItemsSource="{Binding Items}" Grid.Column="1" Name="Lst">
    <ItemsControl.Resources>
        <DataTemplate x:Key="CheckItem">
            <CheckBox Content="{Binding ObjectData}" 
                    IsChecked="{Binding IsSelected}" 
                    Margin="0,6,8,0"/>
        </DataTemplate>

        <DataTemplate x:Key="OthersItem">
            <StackPanel Orientation="Horizontal">
                <CheckBox IsChecked="{Binding IsSelected}" 
                            Content="{Binding ObjectData}"
                            Margin="0,6,8,0"/>
                <TextBox Margin="5,0" VerticalAlignment="Center"
                        MinWidth="50"
                        IsEnabled="{Binding IsSelected}"
                        IsHitTestVisible="True"
                        Text="{Binding Path=DataContext.Others, ElementName=Lst}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.Resources>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <ContentPresenter Content="{Binding}">
                <ContentPresenter.Style>
                    <Style TargetType="ContentPresenter">
                        <Setter Property="ContentTemplate" Value="{StaticResource CheckItem}"/>
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding Path=ObjectData}" Value="Others">
                                <Setter Property="ContentTemplate" Value="{StaticResource OthersItem}"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </ContentPresenter.Style>
            </ContentPresenter>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

Upvotes: 1

Related Questions