DataGrid Cell MultiSelect ComboBox with checkboxes - c#

I have a wpf MVVM application which shows a DataGrid. I have a few columns that are DataGridTextColumns and I want another column to be a MultiSelect Combobox in which shows a checkbox and textblock on each row. The dataSource for the datagrid is different than that of the multiselect combobox I am working towards. My Issue is that I cannot see data (list) in the multiselect combobox when its in the datagrid cell. When I move the code outside of the datagrid I am able to see data. This is my code below
ViewModel:
public class TripInfo : ViewModelBase
{
public TripInfo(bool isVisited, string cityName)
{
IsVisited = isVisited;
CityName = cityName;
}
public Boolean IsVisited { get; set; }
public String CityName { get; set; }
}
public class DataGridViewModel : ViewModelBase
{
ObservableCollection<RecordInfo> infos;
List<TripInfo> tripinfos;
ICommand _command;
public ObservableCollection<RecordInfo> PersonsInfo
{
get
{
return infos;
}
set
{
infos = value;
OnPropertyChanged("PersonsInfo");
}
}
public List<TripInfo> TripsInfo
{
get
{
return tripinfos;
}
set
{
tripinfos = value;
OnPropertyChanged("TripsInfo");
}
}
public DataGridViewModel()
{
PersonsInfo = new ObservableCollection<RecordInfo>();
TripsInfo = new List<TripInfo>();
TripsInfo.Add(new TripInfo(false, "Miami"));
TripsInfo.Add(new TripInfo(true, "Boston"));
TripsInfo.Add(new TripInfo(true, "Los Angeles"));
TripsInfo.Add(new TripInfo(true, "Houston"));
TripsInfo.Add(new TripInfo(false, "Dallas"));
TripsInfo.Add(new TripInfo(false, "Atlantic City"));
TripsInfo.Add(new TripInfo(true, "Chicago"));
GetPersonInfoData();
}
private void GetPersonInfoData()
{
PersonsInfo.Add(new RecordInfo
{
Name = "AA",
Age = 24,
DateOfBirth = new DateTime(1987, 4, 29),
Address = "XXX XXX XXXX"
});
PersonsInfo.Add(new RecordInfo
{
Name = "BB",
Age = 23,
DateOfBirth = new DateTime(1988, 3, 4),
Address = "XXX XXXXX XXX"
});
PersonsInfo.Add(new RecordInfo
{
Name = "CC",
Age = 26,
DateOfBirth = new DateTime(1985, 10, 2),
Address = "XXX XXX X"
});
View.Xaml
<Window.Resources>
<Style x:Key="NameCellStyle" TargetType="DataGridCell">
<Style.Setters>
<Setter Property="TextBlock.TextAlignment" Value="Center"/>
<Setter Property="Background" Value="Aqua"/>
</Style.Setters>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ComboBox Grid.Row="0" Name="cmb" Margin="5" Height="20" ItemsSource="{Binding TripsInfo}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Margin="5" IsChecked="{Binding IsVisited}"/>
<TextBlock Margin="5" Text="{Binding CityName}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<DataGrid Grid.Row="1" Name="DGVPersonInfo" ItemsSource="{Binding PersonsInfo}" AutoGenerateColumns="False" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Button Content="Remove..." Margin="3"
Command="{Binding Path=DataContext.RemoveCommand, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}"/>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Name" Binding="{Binding Name}">
<DataGridTextColumn.CellStyle>
<Style>
<Setter Property="FrameworkElement.HorizontalAlignment" Value="Center" />
<Setter Property="FrameworkElement.VerticalAlignment" Value="Center" />
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
<DataGridTextColumn Header="Age" Binding="{Binding Age}" CellStyle="{StaticResource NameCellStyle}"/>
<DataGridTemplateColumn Header="Date Of Birth">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding DateOfBirth}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateOfBirth}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Address" Binding="{Binding Address}" />
<DataGridTemplateColumn Header="Template">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding TripsInfo}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsVisited}" Width="20" />
<TextBlock Text="{Binding CityName}" Width="100" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>

ItemSource or any property of inside a Template is not directly accessible to the DataGrid's DataContext or any other Other Control or Window.
We need to explicitly provide the data Path.
As per your Xaml Code I am not sure where you have bind your View Model, but as per your Remove Button Command, below is how your Drop Down itemSource must be bind.
<ComboBox ItemsSource="{Binding Path=DataContext.TripsInfo, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}">

Related

DataGrid: replacing a DataGridTextColumn with DataGridTemplateColumn - how to make Binding work

I have a WPF Datagrid with a few DataGridTextColumns and I want to repace one with my own custom control. However I can't figure out how to bind.
<DataGrid ItemsSource="{Binding Path=Entries, Mode=OneWay}" IsSynchronizedWithCurrentItem="True">
<DataGrid.Columns>
<DataGridTextColumn Header="Comment" Binding="{Binding Path=Comment}" Width="Auto" />
</DataGrid.Columns>
</DataGrid>
I have replaced it with:
<DataGrid ItemsSource="{Binding Path=Entries, Mode=OneWay}" IsSynchronizedWithCurrentItem="True">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Comment" Width="Auto">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<x:customTextBox Text="{Binding Path=Comment}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Comment}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I also tried to set a RelativeSource without any success. Do you have any suggestions how to solve this?
This works for me using a textbox instead of whatever your control is.
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Path=Entries, Mode=OneWay}" IsSynchronizedWithCurrentItem="True"
AutoGenerateColumns="False"
>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Comment" Width="Auto">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel>
<TextBox Text="{Binding Path=Comment}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=Comment}" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
enter code here
MyItem is a viewmodel I happened to have in a scratch app.
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private ObservableCollection<MyItem> entries = new ObservableCollection<MyItem>
(
new List<MyItem>
{
new MyItem{ IsChosen = false},
new MyItem{ IsChosen = true },
new MyItem{ IsChosen = true }
}
);
}
Looks like
public partial class MyItem : ObservableObject
{
[ObservableProperty]
private bool? isChosen;
[ObservableProperty]
private string comment = "Some test string";
}

Add combobox for each rows of Datagrid

I have a datagrid with a list of my agents.
I display my agents, and I add two comboboxes to this datagrid, a "matrice" combobox (a matrice = a schedule over a number of weeks), and a combobox displaying the days of the week of the selected matrice.
My problem is that if I change a combobox, matrix for example, all the comboboxes change at the same time like this:
How can I "untie" the comboboxes so that they are independent of each other, so that I can, for each agent, or each row, choose a different matrice in its combobox?
Like agent A = Matrice A
agent B = Matrice Z...
Here is my code :
<!--Section datagrid-->
<DataGrid x:Name="DGagents" Grid.Row="1" Grid.Column="3" Grid.RowSpan="3" Margin="5" AlternationCount="2" ItemContainerStyle="{StaticResource alternatingStyle}" ItemsSource="{Binding Agents}" IsReadOnly="True" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox IsChecked="{Binding Path=DataContext.SelectAllAgents,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" PresentationTraceSources.TraceLevel="High"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Matricule" Width="100" HeaderStyle="{StaticResource CenterGridHeaderStyle}" Binding="{Binding Matricule}" />
<DataGridTextColumn Header="Nom" Width="120" HeaderStyle="{StaticResource CenterGridHeaderStyle}" Binding="{Binding Nom}"/>
<DataGridTextColumn Header="Prénom" Width="120" HeaderStyle="{StaticResource CenterGridHeaderStyle}" Binding="{Binding Prenom}"/>
<DataGridTemplateColumn Header="Matrice" Width="150" HeaderStyle="{StaticResource CenterGridHeaderStyle}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.MatricesEtablissement,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" SelectedItem="{Binding Path=DataContext.selectedMatrice,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="A"/>
<ColumnDefinition SharedSizeGroup="B"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding IDMatrice}"
Margin="4,0,0,0"/>
<TextBlock Grid.Column="1"
Text="{Binding Nom}"
Margin="4,0,0,0"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Semaine" Width="60" HeaderStyle="{StaticResource CenterGridHeaderStyle}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.MatriceWeeks,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" SelectedItem="{Binding Path=DataContext.selectedWeeks,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Num_jour_sem}"
Margin="4,0,0,0"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Date début" Width="150" HeaderStyle="{StaticResource CenterGridHeaderStyle}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateDebut}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Date fin" Width="150" HeaderStyle="{StaticResource CenterGridHeaderStyle}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding DateFin}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
And C#
private ObservableCollection<Matrix> _MatricesEtablissement;
public ObservableCollection<Matrix> MatricesEtablissement
{
get
{
return _MatricesEtablissement;
}
set
{
if (value != _MatricesEtablissement)
{
_MatricesEtablissement = value;
RaisePropertyChanged("MatricesEtablissement");
}
}
}
private Matrix _selectedMatrice;
public Matrix selectedMatrice
{
get
{
return _selectedMatrice;
}
set
{
if (value != _selectedMatrice)
{
_selectedMatrice = value;
UpdateMatriceWeek(value);
RaisePropertyChanged("selectedMatrice");
}
}
}
private ObservableCollection<Matrix> _MatriceWeeks;
public ObservableCollection<Matrix> MatriceWeeks
{
get
{
return _MatriceWeeks;
}
set
{
if (value != _MatriceWeeks)
{
_MatriceWeeks = value;
RaisePropertyChanged("MatriceWeeks");
}
}
}
private Matrix _selectedWeeks;
public Matrix selectedWeeks
{
get
{
return _selectedWeeks;
}
set
{
if (value != _selectedWeeks)
{
_selectedWeeks = value;
RaisePropertyChanged("selectedWeeks");
}
}
}
private void UpdateListeMatrice()
{
MatricesEtablissement = new ObservableCollection<Matrix>();
foreach(Matrix m in Matrices)
{
if (MatricesEtablissement.Any(p => p.IDMatrice == m.IDMatrice) == false)
MatricesEtablissement.Add(m);
}
}
private void UpdateMatriceWeek(Matrix selectedValue)
{
MatriceWeeks = new ObservableCollection<Matrix>();
if(selectedValue != null)
{
foreach (Matrix m in Matrices)
{
if (m.IDMatrice == selectedMatrice.IDMatrice)
{
MatriceWeeks.Add(m);
}
}
}
}
my goal being to retrieve the data from every row at the end.

Bind data into multicolum datagrid-combobox wpf

I found this tutorial online which is exactly what I am trying to do, but the tutorial does not explain how to load data from code behind into the combobox. any idea how I can acheive this?
Basically I want a multicolumn combobox in a datagrid, and when the user selects an item, it displays only one of the values and not both.
<DataGrid x:Name="DGOrders" Margin="30" AutoGenerateColumns="False" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding OrderID}" Header="Order ID" />
<DataGridTemplateColumn Header="User" Width="200">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding UserID}" SelectedValuePath="UserID" DisplayMemberPath="CompanyName" HorizontalContentAlignment="Stretch" ItemsSource="{Binding}" >
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Margin="5" Grid.Column="0" Text="{Binding UserID}"/>
<TextBlock Margin="5" Grid.Column="1" Text="{Binding CompanyName}"/>
<TextBlock Margin="5" Grid.Column="2" Text="{Binding UserName}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
I am not sure about what you meant by displaying only one of the values and not both, but i hope that explain it self once i show you how to properly bind the properties in the DataGrid, first of all you need to make sure that your model looks something like this :
public class Order
{
public string OrderId { get; set; }
public string SelectedUserId { get; set; }
}
public class User
{
public string UserId { get; set; }
public string CompanyName { get; set; }
public string UserName { get; set; }
}
then in the code behind create two collectionw to hold the users list and the orders list which represent the DataContext for the ComboBox and the DataGrid:
private ObservableCollection<Order> _ordersCollection = new ObservableCollection<Order>()
{
new Order()
{
OrderId = "1",
SelectedUserId = "2"
} ,new Order()
{
OrderId = "2",
SelectedUserId = "3"
}
};
public ObservableCollection<Order> OrdersCollection
{
get
{
return _ordersCollection;
}
set
{
if (_ordersCollection == value)
{
return;
}
_ordersCollection = value;
OnPropertyChanged();
}
}
private ObservableCollection<User> _usersCollection = new ObservableCollection<User>()
{
new User()
{
UserId = "1",
UserName = "Name1",
CompanyName = "Company1"
} ,new User()
{
UserId = "2",
UserName = "Name2",
CompanyName = "Company2"
} ,new User()
{
UserId = "3",
UserName = "Name3",
CompanyName = "Company3"
}
};
public ObservableCollection<User> UsersCollection
{
get
{
return _usersCollection;
}
set
{
if (_usersCollection == value)
{
return;
}
_usersCollection = value;
OnPropertyChanged();
}
}
you may consider implementing the INotifyPropertyChanged interface so that the UI will be notified each time the collection is updated.
Now in the UI, make sure your main window's DataContext is set to the codebehind using this
DataContext="{Binding RelativeSource={RelativeSource Self}}"
then properly bind the Properties:
<Grid>
<DataGrid x:Name="DGOrders" Margin="30" AutoGenerateColumns="False" ItemsSource="{Binding OrdersCollection}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding OrderId}" Header="Order ID" />
<DataGridTemplateColumn Header="User" Width="200" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedValue="{Binding SelectedUserId}" SelectedValuePath="UserId" DisplayMemberPath="CompanyName" HorizontalContentAlignment="Stretch" ItemsSource="{Binding DataContext.UsersCollection,ElementName=DGOrders}" >
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Margin="5" Grid.Column="0" Text="{Binding UserId}"/>
<TextBlock Margin="5" Grid.Column="1" Text="{Binding CompanyName}"/>
<TextBlock Margin="5" Grid.Column="2" Text="{Binding UserName}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
you will end up with something like this

WPF DataGrid Row Style with MVVM

I have a DataGrid where I'd like to change the row border color or background if a certain property of my ViewModel class is set to true. I'm having problems getting the DataTrigger to bind to the row source item (ViewModel) property. In this case, I'd like to bind to the ViewModel Property IsExpired. Unfortunately, it won't let me and throws and exception at runtime. Any help would be appreciated.
public class ViewModel
{
public uint Id { get; private set;}
public string Symbol { get; private set;}
public bool IsExpired { get; private set;}
}
public class WindowViewModel : PropertyChangedNotifier
{
public ObservableCollection<ViewModel> ViewModels { get; private set;}
private DateTime _timestamp;
public DateTime TimeStamp
{
get { return _timestamp; }
set
{
_timestamp = value;
OnPropertyChanged("TimeStamp");
}
}
}
<Grid x:Name="Layout" d:DataContext="{StaticResource DesignerViewModel}" DataContext="{Binding}">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Text="Accounts" VerticalAlignment="Center" Margin="5"/>
<ComboBox x:Name="AccountsComboBox" ItemsSource="{Binding Accounts}" DisplayMemberPath="ClearingNumber" Width="125"
HorizontalAlignment="Left" Margin="5" IsEditable="False" IsReadOnly="True" Style="{StaticResource AccountComboBoxStyle}"/>
<Button x:Name="LoadPositionsButton" Content="Load" Margin="5" VerticalAlignment="Center" HorizontalAlignment="Center" Width="50" Click="LoadPositionsButtonOnClick"/>
<TextBlock x:Name="TimeStampTextBlock" HorizontalAlignment="Right" Margin="5" Width="150" Text="{Binding LastUpdate, Converter={StaticResource TimeStampConverter}}"/>
</StackPanel>
<DataGrid Grid.Row="1" ItemsSource="{Binding ViewModels}" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False"
CanUserResizeRows="False" CanUserSortColumns="False" AutoGenerateColumns="False" HeadersVisibility="Column">
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpired}" Value="True">
<Setter Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.RowStyle>
<!-- ... -->
<DataGrid.Columns>
<DataGridTemplateColumn Header="Account">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:ViewModel">
<TextBlock Text="{Binding Account}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--<DataGridTemplateColumn Header="Exch">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:ViewModel">
<TextBlock Text="{Binding ExchangeCode}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>-->
<DataGridTemplateColumn Header="Symbol">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:ViewModel">
<TextBlock Text="{Binding Symbol}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Description">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:ViewModel">
<TextBlock Text="{Binding Description}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Maturity">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="vm:ViewModel">
<TextBlock Text="{Binding MaturityMonthYear}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGrid.Columns>
</DataGrid>
</Grid>
First you should implement INotifyPropertyChanged interface for ViewModel class. This is similar to what how you wrote in your WindowViewModel class. And then change the auto-property IsExpired to:
public bool IsExpired
{
get { return _isExpired; }
set
{
_isExpired = value;
OnPropertyChanged("IsExpired");
}
}
Second if you want to change style of certain column you should change the CellStyle property of column:
<DataGrid Grid.Row="1" ItemsSource="{Binding ViewModels}" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False"
CanUserResizeRows="False" CanUserSortColumns="False" AutoGenerateColumns="False" HeadersVisibility="Column">
<DataGrid.Columns>
<DataGridTemplateColumn Header="HeaderName" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Symbol}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsExpired}" Value="True">
<Setter Property="BorderBrush" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
<!-- ... -->
</DataGrid>
If you want to change style of data grid rows you should use the Template property, for example:
<DataGrid Grid.Row="1" ItemsSource="{Binding ViewModels}" CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserResizeColumns="False"
CanUserResizeRows="False" CanUserSortColumns="False" AutoGenerateColumns="False" HeadersVisibility="Column">
<DataGrid.RowStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRow}">
<Border x:Name="DataGridRowBorder"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<!-- Row template -->
<Grid>
<TextBlock Text="{Binding Path=Symbol}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsExpired}" Value="True">
<Setter TargetName="DataGridRowBorder" Property="BorderBrush" Value="Red"/>
<Setter TargetName="DataGridRowBorder" Property="BorderThickness" Value="1"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.RowStyle>
<!-- ... -->
</DataGrid>

List Under ListView Item

I have listview that binding with observable Collection, this listview show the invoice items, any item in invoice maybe has a sub detail (Options), (for example item color),
what i want to ask about is: how to make list view show the item options as list under the main item in listview, i hope my question is clear .. for more clarity look at the image :
What i want is in a yellow color, how to make listview look like the image ?
here's my invoice listview code :
<ListView x:Name="temsReceipt" ItemsSource="{Binding ocItemsReceipt}">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="40" Width="50"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Name" Width="230" DisplayMemberBinding="{Binding ItemName}"/>
<GridViewColumn Header="Item Price" Width="100" DisplayMemberBinding="{Binding ItemPrice}"/>
</GridView>
</ListView.View>
The same think if i used the datagrid
Let's say that you have following classes:
class InvoiceItem
{
public string ItemName { get; set; }
public List<InvoiceOption> Options { get; set; }
}
class InvoiceOption
{
public string OptionName { get; set; }
}
ListView solution:
<ListView x:Name="temsReceipt" ItemsSource="{Binding}">
<ListView.Resources>
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBlock Height="40" Width="50"></TextBlock>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Name" Width="230" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding ItemName}" VerticalAlignment="Center"
FontWeight="Bold" FontSize="18"/>
<ListBox ItemsSource="{Binding Options}" Grid.Row="1" Background="Yellow"
HorizontalAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding OptionName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Item Price" Width="100" DisplayMemberBinding="{Binding ItemPrice}"/>
</GridView>
</ListView.View>
</ListView>
If you want to use DataGrid you can use RowDetailsTemplate:
<DataGrid ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding ItemName}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel Margin="2" Background="Yellow">
<TextBlock Text="Options:" />
<ListBox ItemsSource="{Binding Options}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding OptionName}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
Sample data:
...
public MainWindow()
{
InitializeComponent();
List<InvoiceItem> _source = new List<InvoiceItem>
{
new InvoiceItem
{
ItemName = "Item1",
Options = new List<InvoiceOption>
{
new InvoiceOption { OptionName = "Option1" },
new InvoiceOption { OptionName = "Option2" }
}
},
new InvoiceItem
{
ItemName = "Item2",
Options = new List<InvoiceOption>
{
new InvoiceOption { OptionName = "Option3" },
new InvoiceOption { OptionName = "Option4" }
}
}
};
this.DataContext = _source;
}
...
ListView result:

Categories

Resources