WPF dataGrid (or ListView) filled via Binding, different Template for Rows
I have a WPF dataGrid which is filled via DataBinding. This list contains different columns. I have two types of rows, one type contains all the columns in the rows, and the other should span one column over all the columns.
Is there a easy way to make this possible? (maybe use a ListView instead of a DataGrid?)
I attached a screenshot how it should look like:
I now tried with Item Template Selector:
My templates in the Resources (The two templates are not correct, but they are only for testing!)
<DataTemplate x:Key="commentTemplate">
<TextBlock Text="{Binding}"/>
</DataTemplate>
<DataTemplate x:Key="normalTemplate">
<Image Source="{Binding }" />
</DataTemplate>
<WPFVarTab:VarTabRowItemTemplateSelector
NormalRowsTemplate="{StaticResource normalTemplate}"
CommentRowsTemplate="{StaticResource commentTemplate}"
x:Key="vartabrowItemTemplateSelector" />
and my Datagrid:
<DataGrid AutoGenerateColumns="False" Margin="0,22,0,22"
Name="dataGrid" Grid.RowSpan="2" CanUserAddRows="True"
RowBackground="Azure" AlternatingRowBackground="LightSteelBlue"
ItemTemplateSelector="{StaticResource vartabrowItemTemplateSelector}" >
and my Template Selector:
public class VarTabRowItemTemplateSelector : DataTemplateSelector
{
public DataTemplate NormalRowsTemplate { get; set; }
public DataTemplate CommentRowsTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, 开发者_如何学CDependencyObject container)
{
S7VATRow vRow = item as S7VATRow;
if (vRow == null || string.IsNullOrEmpty(vRow.Comment))
return NormalRowsTemplate;
return CommentRowsTemplate;
}
}
I put a stop in the first row in SelectTemplate but this is never called!
You can use item template selector with ListView
. Or with DataGrid
, it's available there, too. Here is an example.
Use binding to turn the visibility of datarow on and off like so. I am assuming you defined columns.
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<ContentControl Style="{StaticResource CommentTemplate}" Content="{Binding Comment}" Visibility="{Binding IsCommentVisible, Converter={StaticResource BooleanToVisibilityConverter}}"/>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
Check this http://www.wpf-tutorial.com/datagrid-control/details-row/. Incase the link is broken, code for row and column details for your reference is pasted below.
<Window x:Class="WpfTutorialSamples.DataGrid_control.DataGridDetailsSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataGridDetailsSample" Height="200" Width="400">
<Grid Margin="10">
<DataGrid Name="dgUsers" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Birthday" Binding="{Binding Birthday}" />
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock Text="{Binding Details}" Margin="10" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
Code view model
using System;
using System.Collections.Generic;
using System.Windows;
namespace WpfTutorialSamples.DataGrid_control
{
public partial class DataGridDetailsSample : Window
{
public DataGridDetailsSample()
{
InitializeComponent();
List<User> users = new List<User>();
users.Add(new User() { Id = 1, Name = "John Doe", Birthday = new DateTime(1971, 7, 23) });
users.Add(new User() { Id = 2, Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17) });
users.Add(new User() { Id = 3, Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2) });
dgUsers.ItemsSource = users;
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
public string Details
{
get
{
return String.Format("{0} was born on {1} and this is a long description of the person.", this.Name, this.Birthday.ToLongDateString());
}
}
}
}
viewmodel for data and comment. Also for empty space.
public abstract class RowViewModelBase
{
public bool IsSpecial { get; set; }
}
public class EmptySpaceViewModel : RowViewModelBase
{
public EmptySpaceViewModel() => IsSpecial = true;
}
public class DataViewModel : RowViewModelBase
{
public DataViewModel(string column1, string column2)
{
Column1 = column1;
Column2 = column2;
}
public string Column1 { get; set; }
public string Column2 { get; set; }
}
public class CommentViewModel : RowViewModelBase
{
public string Comment { get; }
public CommentViewModel(string comment)
{
Comment = comment;
IsSpecial = true;
}
}
template selector
public class RowContentSelector : DataTemplateSelector
{
public DataTemplate EmptyTemplate { get; set; }
public DataTemplate CommentTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is EmptySpaceViewModel)
return EmptyTemplate;
if (item is CommentViewModel)
return CommentTemplate;
return base.SelectTemplate(item, container);
}
}
xaml
<Window
...>
<Window.Resources>
<DataTemplate x:Key="EmptyRow">
<Border Height="30" />
</DataTemplate>
<DataTemplate x:Key="CommentTempate">
<TextBlock Foreground="Green" Text="{Binding Comment}" />
</DataTemplate>
<local:RowContentSelector
x:Key="RowContentSelector"
CommentTemplate="{StaticResource CommentTempate}"
EmptyTemplate="{StaticResource EmptyRow}" />
</Window.Resources>
<DataGrid
AutoGenerateColumns="False"
CanUserAddRows="False"
ItemsSource="{Binding}"
RowDetailsTemplateSelector="{StaticResource RowContentSelector}"
RowDetailsVisibilityMode="Visible">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Column1}" Header="column1" />
<DataGridTextColumn Binding="{Binding Column2}" Header="column2" />
</DataGrid.Columns>
<DataGrid.ItemContainerStyle>
<Style TargetType="{x:Type DataGridRow}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridRow}">
<Border
x:Name="DGR_Border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
SnapsToDevicePixels="True">
<SelectiveScrollingGrid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DataGridCellsPresenter
x:Name="cells"
Grid.Column="1"
ItemsPanel="{TemplateBinding ItemsPanel}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
<DataGridDetailsPresenter
x:Name="details"
Grid.Row="1"
Grid.Column="1"
SelectiveScrollingGrid.SelectiveScrollingOrientation="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=AreRowDetailsFrozen, Converter={x:Static DataGrid.RowDetailsScrollingConverter}, ConverterParameter={x:Static SelectiveScrollingOrientation.Vertical}}"
Visibility="{TemplateBinding DetailsVisibility}" />
<DataGridRowHeader
x:Name="header"
Grid.RowSpan="2"
SelectiveScrollingGrid.SelectiveScrollingOrientation="Vertical"
Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}, Path=HeadersVisibility, Converter={x:Static DataGrid.HeadersVisibilityConverter}, ConverterParameter={x:Static DataGridHeadersVisibility.Row}}" />
</SelectiveScrollingGrid>
</Border>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding IsSpecial}" Value="True">
<Setter TargetName="cells" Property="Visibility" Value="Collapsed" />
<!--<Setter TargetName="header" Property="Visibility" Value="Collapsed" />-->
</DataTrigger>
<DataTrigger Binding="{Binding IsSpecial}" Value="False">
<Setter TargetName="details" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.ItemContainerStyle>
</DataGrid>
</Window>
example
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new List<RowViewModelBase> {
new EmptySpaceViewModel(),
new DataViewModel("aaaa", "bbb"),
new EmptySpaceViewModel(),
new DataViewModel("aaaa", "bbb"),
new CommentViewModel("//comment"),
new DataViewModel("aaaa", "bbb"),
new CommentViewModel("//comment"),
new CommentViewModel("//comment"),
new DataViewModel("aaaa", "bbb"),
};
}
}
Of course, if you has one alternative template - you no need template selector and can set template directly
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<TextBlock Text="{Binding Comment}" />
</DataTemplate>
</DataGrid.RowDetailsTemplate>
精彩评论