开发者

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:

WPF dataGrid (or ListView) filled via Binding, different Template for Rows

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());
                        }
                }
        }
    }


WPF dataGrid (or ListView) filled via Binding, different Template for Rows

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>
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜