Reputation: 213
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:
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:
Upvotes: 2
Views: 1166
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>
<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