I have the following DataGrid in WPF with two groups.
First group is a bool flag which represents if a person is active/inactive.
The second group (or sub-group) is the ID of each person.
Each person can have multiple cities, therefore the grouping for the ID, because each person is shown multiple in the DataGrid.
Here is the XAML:
<DataGrid CanUserAddRows="False" AutoGenerateColumns="False" ItemsSource="{Binding DataSource}">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True">
<Expander.Style>
<Style TargetType="{x:Type Expander}">
<Style.Triggers>
<DataTrigger Binding="{Binding Name}" Value="True">
<Setter Property="Background" Value="{StaticResource ActiveBrush}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Name}" Value="False">
<Setter Property="Background" Value="{StaticResource InactiveBrush}"/>
<Setter Property="FontStyle" Value="Italic"/>
<Setter Property="Foreground" Value="Gray"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Expander.Style>
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name, Converter={StaticResource BoolToTextConverter}}" Margin="5 2 5 2"/>
<TextBlock Text=":" Margin="0 2 5 2"/>
<TextBlock Text="{Binding ItemCount}" Margin="0 2 0 2"/>
</StackPanel>
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="LightSteelBlue">
<TextBlock Text="{Binding Name}" Foreground="White" Margin="5 2 5 2"/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</DataGrid.GroupStyle>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<DockPanel>
<Button BorderThickness="0" Content="Edit" Margin="3"
Command="{Binding Commands.Edit}"
CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"/>
</DockPanel>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="ID" Binding="{Binding ID}" IsReadOnly="True"/>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" IsReadOnly="True"/>
<DataGridTextColumn Header="City" Binding="{Binding City}" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
It all works fine!
However, I don't like the blue row for each sub-group.
What I want to achieve is the grouping style in the following image:
For each sub-group I want the Edit button and the ID to appear only once per person.
How would I do this? Is it possible in XAML only or should I remove the reduntant content in code-behind?
Edit
Here some test data:
public class Person
{
public Person(bool active, int id, string name, string city)
{
Active = active;
ID = id;
Name = name;
City = city;
}
public bool Active { get; set; }
public int ID { get; set; }
public string Name { get; set; }
public string City { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
var data = new ObservableCollection<Person>
{
new Person(true, 233, "Max", "New York"),
new Person(true, 233, "Max", "Los Angeles"),
new Person(true, 314, "John", "Paris"),
new Person(true, 578, "Mary", "Vienna"),
new Person(true, 782, "Susan", "Rome"),
new Person(true, 782, "Susan", "Prague"),
new Person(true, 782, "Susan", "San Francisco"),
new Person(false, 151, "Henry", "Chicago")
};
DataSource = new ListCollectionView(data);
}
private ListCollectionView _dataSource;
public ListCollectionView DataSource
{
get { return _dataSource; }
set
{
_dataSource = value;
_dataSource.GroupDescriptions.Add(new PropertyGroupDescription("Active"));
_dataSource.GroupDescriptions.Add(new PropertyGroupDescription("ID"));
}
}
I would highly recommend changing the data structure to:
public class Person {
public bool Active { get; set; }
public int ID { get; set; }
public string Name { get; set; }
public Collection Cities { get; set; }
}
Otherwise you can change this GroupStyle
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Background="LightSteelBlue">
<TextBlock Text="{Binding Name}" Foreground="White" Margin="5 2 5 2"/>
</StackPanel>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
To
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="EditButtonColumn" />
<ColumnDefinition SharedSizeGroup="IDColumn" />
<ColumnDefinition SharedSizeGroup="NameColumn" />
<ColumnDefinition SharedSizeGroup="PresenterColumn" Width="*" />
</Grid.ColumnDefinitions>
<Button Grid.Column="0" BorderThickness="0" Content="Edit" Margin="3"
CommandParameter="{Binding Path=Items[0]}" />
<TextBlock Grid.Column="1" Text="{Binding Path=Items[0].ID}" />
<TextBlock Grid.Column="2" Text="{Binding Path=Items[0].Name}" />
<ItemsPresenter Grid.Column="3" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
Change the template to suit your needs
Related
I'm implementing a ListCollectionView so I can get groupings of objects within my datagrid. It seems to be working pretty well, but it doesn't feel like proper MVVM. I'm a little confused because a property can't directly be defined as a ListCollectionView. Instead, a separate collection has to be provided that implements IList.
The original ObservableCollection<EntityConcept> has too much information to display in the datagrid at once. The user selects one of the EntityConcept using a combobox, then a ListCollectionView<PropertyItem> is constructed to display all of the PropertyItem that belong to that EntityConcept.
I feel like it would make sense for the ObservableCollection<PropertyItem> to be defined as a ListCollectionView from the start. However, I don't think I can do that.
public class EntityConcept
{
private string _Name;
private ObservableCollection<PropertyItem> _propertyList;
public ObservableCollection<PropertyItem> propertyList
{
get
{
return _propertyList;
}
set
{
_propertyList = value;
}
}
public string Name
{
get
{
return _Name;
}
set
{
_Name = value;
}
}
}
Instead, a ListCollectionView is constructed based on what the user selects in the combobox:
<ComboBox x:Name="ifcCombo"
Grid.Column="2"
Grid.Row="1"
Margin="0,3,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="150"
DisplayMemberPath="ifcEntity"
SelectedItem="{Binding chosenConcept}"
ItemsSource="{Binding ConceptList}"/>
<!--Grid.Row 3-->
<DataGrid x:Name="propertiesTable"
ItemsSource="{Binding chosenConceptProperties}"
Grid.Column="1"
Grid.ColumnSpan="3"
Grid.Row="3"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
AutoGenerateColumns="False"
CanUserAddRows="False"
Margin="0,25,0,0" CellEditEnding="propertiesTable_CellEditEnding">
<DataGrid.Columns>
<DataGridCheckBoxColumn Width="75" MinWidth="50" Header="" IsReadOnly="False" Binding="{Binding On}"/>
<DataGridTextColumn Width="10*" MinWidth="250" Header="Property Name" Binding="{Binding PropertyName}" IsReadOnly="True" FontSize="10" />
<DataGridTextColumn Width="10*" MinWidth="250" Header="Mapping" Binding="{Binding Mapping}" IsReadOnly="False" FontSize="10" />
<!--<DataGridTemplateColumn Width="*" Header="" CellTemplateSelector="{StaticResource myDynamicTemplateSelector}"/>-->
</DataGrid.Columns>
<DataGrid.RowStyle>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="{Binding StringType, Converter={StaticResource stringToBrush}}"/>
</Style>
</DataGrid.RowStyle>
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black" BorderThickness="1,1,1,5">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<CheckBox x:Name="HeaderCheckBox" Grid.Column="2" Tag="{Binding Name}" Margin="5,0,0,0" Click="CheckAll"/>
<TextBlock Grid.Column="0" Text="{Binding Path=Name}" Foreground="#2a5fa4" FontWeight="Bold" Margin="10,0,0,0"/>
</StackPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter/>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
Instead, the ListCollectionView is manually constructed every time the chosenConcept is set. This doesn't feel correct to me, and I think there must be a cleaner way.
private ObservableCollection<EntityConcept> _ConceptList = new ObservableCollection<EntityConcept>();
private EntityConcept _chosenConcept = new EntityConcept();
private ListCollectionView _chosenConceptProperties;
public EntityConcept chosenConcept
{
get
{
return _chosenConcept;
}
set
{
_chosenConcept = value;
OnPropertyChanged(nameof(chosenConcept));
ConstructChosenConcept();
}
}
public ListCollectionView chosenConceptProperties
{
get
{
return _chosenConceptProperties;
}
set
{
_chosenConceptProperties = value;
OnPropertyChanged(nameof(chosenConceptProperties));
}
}
public void ConstructChosenConcept()
{
if(chosenConcept != null)
{
chosenConceptProperties = new ListCollectionView(chosenConcept.propertyList);
chosenConceptProperties.GroupDescriptions.Add(new PropertyGroupDescription("Pset"));
name = chosenConcept.Name;
description = chosenConcept.Description;
objectType = chosenConcept.ObjectType;
tag = chosenConcept.Tag;
}
}
I finish a ListView grouping and add a expander control.
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Expander IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}}">
<Expander.Header>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" FontWeight="Bold" Foreground="Gray" FontSize="16" VerticalAlignment="Bottom"/>
<TextBlock Text="{Binding ItemCount}" FontSize="22" Foreground="Green" FontWeight="Bold" FontStyle="Italic" Margin="10,0,0,0" VerticalAlignment="Bottom" />
<TextBlock Text=" item(s)" FontSize="22" Foreground="Silver" FontStyle="Italic" VerticalAlignment="Bottom" />
</StackPanel>
</Expander.Header>
<ItemsPresenter/>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
The IsExpanded like
<Expander IsExpanded="{Binding Mode=TwoWay, Path=IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem, Mode=FindAncestor}}">
and I set lv.SelectedIndex to change selection, but it don't work!
I have no idea.
Xaml Design:
<Window.Resources>
<Style x:Key="groupheaderstyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<TextBlock Text="{Binding Gropname}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DataGrid x:Name="dgdata" HorizontalAlignment="Left" Height="269" VerticalAlignment="Top" Width="292">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupheaderstyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
Xaml Design.cs
public class group
{
public string groupname { get; set; }
public string CLgroup { get; set; }
public string displayname { get; set; }
}
public Window4()
{
InitializeComponent();
ObservableCollection<group> samdata = new ObservableCollection<group>
{
new group{groupname="Group1",CLgroup="xxx",displayname="demo1"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
};
ListCollectionView collection = new ListCollectionView(samdata);
collection.GroupDescriptions.Add(new PropertyGroupDescription("groupname"));
dgdata.ItemsSource = collection;
}
I want to regroup my data with an expander that contains the group name and contains all ClassMate name inside.
This is my class Group :
public class Group{
public List<ClassMate> CLGroup { get; set; }
public string GroupName { get; set; }}
My classMate class :
public class ClassMate: INotifyPropertyChanged{
public string Name { get; set; }
public string DisplayName { get; set; }}
I tried to do this with this Xaml but I don't know why it's not working
<DataGrid x:Name="gridMates" ItemsSource="{Binding Groups }" >
<DataGrid.GroupStyle>
<!-- Style for groups at top level. -->
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel>
<TextBlock Text="{Binding Path=GroupName}" />
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsControl ItemsSource="{Binding Path=CLGroup}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=DisplayName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
What am I doing wrong?
Thanks
You need to bind the ItemsSource property to a grouped source collection. The easiest way to do this is to use a CollectionViewSource:
<Grid>
<Grid.Resources>
<CollectionViewSource x:Key="groups" Source="{Binding Groups}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="GroupName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Grid.Resources>
<DataGrid x:Name="gridMates" ItemsSource="{Binding Source={StaticResource groups}}" AutoGenerateColumns="False">
<DataGrid.GroupStyle>
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" >
<Expander.Header>
<DockPanel>
<TextBlock Text="{Binding Path=Name}" />
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsControl ItemsSource="{Binding Path=Items[0].CLGroup}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=DisplayName}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
</Grid>
XAML Design
<Window.Resources>
<Style x:Key="groupheaderstyle" TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander x:Name="exp" IsExpanded="True" Background="White" Foreground="Black">
<Expander.Header>
<TextBlock Text="{Binding Gropname}" />
</Expander.Header>
<ItemsPresenter />
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<DataGrid x:Name="dgdata" HorizontalAlignment="Left" Height="269" VerticalAlignment="Top" Width="292">
<DataGrid.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource groupheaderstyle}">
<GroupStyle.Panel>
<ItemsPanelTemplate>
<DataGridRowsPresenter />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</DataGrid.GroupStyle>
</DataGrid>
XAML Design.CS
public class group
{
public string groupname { get; set; }
public string CLgroup { get; set; }
public string displayname { get; set; }
}
public Window4()
{
InitializeComponent();
ObservableCollection<group> samdata = new ObservableCollection<group>
{
new group{groupname="Group1",CLgroup="xxx",displayname="demo1"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group1",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group2",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group3",CLgroup="zzz",displayname="demo3"},
new group{groupname="Group3",CLgroup="yyy",displayname="demo2"},
new group{groupname="Group3",CLgroup="yyy",displayname="demo2"},
};
ListCollectionView collection = new ListCollectionView(samdata);
collection.GroupDescriptions.Add(new PropertyGroupDescription("groupname"));
dgdata.ItemsSource = collection;
}
I was able to implement Tree View using the link
Now I have attached the below Data Grid to it for displaying the city details like Area, Population, TimeZone etc.I was able to receive the event IsSelected upon selecting the City name from the treeview using example. But how do I bind the data of City model (Area, Population, TimeZone ) to a datagrid in the .xaml ? I tried using the CityViewModel directly but it never populates the data.CityViewModel has an observableCollection of "CityTown"( with props like Area, Population, TimeZone etc) property called "CityTowns" which I am populating when IsSelected is fired.My Tree View only has Region -> State -> City hierarchy. City towns should be displayed in grid not in tree.
//DemoWindow.xaml content:
<TabControl>
<TabItem Header="Load Towns">
<StackPanel Orientation="Horizontal">
<advanced: LoadOnDemandControl/>
<DataGrid ItemsSource="{Binding Path=local.CityViewModel.CityTowns}"
AutoGenerateColumns="False" IsReadOnly="True"
>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Popluation}" Header="Popluation"/>
<DataGridTextColumn Binding="{Binding Path=Revenue}" Header="Revenue"/>
<DataGridTextColumn Binding="{Binding Path=TimeZone}" Header="TimeZone"/>
<DataGridTextColumn Binding="{Binding Path=Area}" Header="Area"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</TabItem>
</TabControl>
//LoadOnDemandCcontrol.xaml:
<TreeView ItemsSource="{Binding Regions}">
<TreeView.ItemContainerStyle>
<!--
This Style binds a TreeViewItem to a TreeViewItemViewModel.
-->
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Setter Property="FontWeight" Value="Normal" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.Resources>
<HierarchicalDataTemplate
DataType="{x:Type local:RegionViewModel}"
ItemsSource="{Binding Children}"
>
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0" Source="Images\Region.png" />
<TextBlock Text="{Binding RegionName}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
DataType="{x:Type local:StateViewModel}"
ItemsSource="{Binding Children}"
>
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0" Source="Images\State.png" />
<TextBlock Text="{Binding StateName}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:CityViewModel}">
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16" Margin="3,0" Source="Images\City.png" />
<TextBlock Text="{Binding CityName}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
//CityTown.cs content:
public class CityTown
{
public int Area { get; set; }
public int Population { get; set; }
public string TimeZone { get; set; }
public int Revenue { get; set; }
public virtual City City { get; set; }
}
//CityViewModel.cs cocntent
public class CityViewModel : TreeViewItemViewModel
{
readonly City _city;
public CityViewModel(City city, StateViewModel parentState)
: base(parentState, false)
{
_city = city;
}
public string CityName
{
get { return _city.CityName; }
}
private ObservableCollection<CityTown> _CityTowns;
public ObservableCollection<CityTown> CityTowns
{
get { return Database.GetTowns(CityName); }
set { _CityTowns = value; }
}
}
//LoadOnDemandDemoControl.xaml.cs content:
public partial class LoadOnDemandDemoControl : UserControl
{
public LoadOnDemandDemoControl()
{
InitializeComponent();
Region[] regions = Database.GetRegions();
CountryViewModel viewModel = new CountryViewModel(regions);
base.DataContext = viewModel;
}
}
I solved it by defining the SelectedValuePath property for TreeView xaml element class and used the same in DataGrid element -> ItemsSoruce property -> Path -> SelectedItem.ViewModelDataCollection.
I have a combobox which has 2 items. Each item is an objet deriving from a common interface. There is a DisplayText property on each object. Each object is templated so as to have a different visual. Everything works fine, except while selecting one of those objects, the visual is getting displayed in the combobox textbox. I want it to display the SelectedText property of the selected object in the textbox and the DisplayText inside the item template. How do I specify my binding for that please?
Here is my code:
public interface IMyDate
{
string DisplayText { get; }
string SelectedText { get; }
}
public class TodayMinus1 : IMyDate
{
public string DisplayText { get { return "Yesterday"; } }
public string SelectedText{get { return DateTime.Today.AddDays(-1).ToString(); }}
}
public class Today : IMyDate
{
public string DisplayText { get { return "TODAY"; } }
public string SelectedText { get { return DateTime.Today.ToString(); } }
}
public class MyMainViewModel
{
public MyMainViewModel()
{
MyDates = new List<IMyDate>() {new Today(), new TodayMinus1()};
}
public List<IMyDate> MyDates { get; set; }
public IMyDate SelectedDate { get; set; }
}
<ComboBox MaxHeight="26" VerticalAlignment="Center" x:Name="contextDropdown" ItemsSource="{Binding MyDates}" SelectedItem="{Binding SelectedDate}" Grid.Column="1" Width="150" Margin="5">
<ComboBox.Resources>
<DataTemplate DataType="{x:Type local:TodayMinus1}">
<TextBlock Text="{Binding DisplayText}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Today}">
<TextBlock Text="{Binding DisplayText}"/>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>
Please note that this is an oversimplified example and I have implemented INPC for all my objects.
Try this:
<ComboBox MaxHeight="26" VerticalAlignment="Center" x:Name="contextDropdown" ItemsSource="{Binding MyDates}"
SelectedItem="{Binding SelectedDate}" Grid.Column="1" Width="150" Margin="5">
<ComboBox.Resources>
<DataTemplate DataType="{x:Type local:TodayMinus1}">
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding DisplayText}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=ComboBoxItem}}" Value="{x:Null}">
<Setter Property="Text" Value="{Binding SelectedText}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Today}">
<TextBlock>
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="{Binding DisplayText}" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource AncestorType=ComboBoxItem}}" Value="{x:Null}">
<Setter Property="Text" Value="{Binding SelectedText}" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>
Added a DataTrigger inside the DataTemplate to achieve your requirement. Try this.
<ComboBox MaxHeight="26" VerticalAlignment="Center" x:Name="contextDropdown" ItemsSource="{Binding MyDates}" SelectedItem="{Binding SelectedDate}" Grid.Column="1" Width="150" Margin="5">
<ComboBox.Resources>
<DataTemplate DataType="{x:Type local:TodayMinus1}">
<TextBlock Text="{Binding DisplayText}" x:Name="DisplayBox"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}" Value="{x:Null}">
<Setter TargetName="DisplayBox" Property="Text" Value="{Binding SelectedText}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate DataType="{x:Type local:Today}">
<TextBlock Text="{Binding DisplayText}" x:Name="DisplayBox"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor,ComboBoxItem,1}}" Value="{x:Null}">
<Setter TargetName="DisplayBox" Property="Text" Value="{Binding SelectedText}"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ComboBox.Resources>
</ComboBox>