Data template parameter

折月煮酒 提交于 2021-01-28 12:03:52

问题


There is list with columns to display. I am using ListView with data templates for cells. And my problem is to access both: row and column from template.

Below is demo, xaml:

<ListView x:Name="listView" ItemsSource="{Binding Items}">
    <ListView.Resources>
        <GridViewColumn x:Key="Column" x:Shared="False">
            <GridViewColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock>
                        <Run Text="{Binding WhatHere}" /> <!-- problem here -->
                        <Run Text="{Binding Mode=OneWay}" />
                    </TextBlock>
                </DataTemplate>
            </GridViewColumn.CellTemplate>
        </GridViewColumn>
    </ListView.Resources>
    <ListView.View>
        <GridView />
    </ListView.View>
</ListView>

and the code:

public partial class MainWindow : Window
{
    public List<string> Items { get; } = new List<string> { "1", "2", "3" };

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        var a = (GridViewColumn)listView.FindResource("Column");
        a.Header = "a";
        ((GridView)listView.View).Columns.Add(a);

        var b = (GridViewColumn)listView.FindResource("Column");
        b.Header = "b";
        ((GridView)listView.View).Columns.Add(b);
    }
}

will produce

My aim is to have:

a     b
a1    b1
a2    b2
a3    b3

Possible? How do I pass column to DataTemplate ? In fact I want to simply know to which column current cell belongs, but please consider following:

  1. This is simplified case.
  2. In reality data templates are more complicated: many elements with bindings, triggers, etc.
  3. In reality column related data are more complicated than just header.
  4. Columns will be generated at runtime with different headers, etc.
  5. Adding columns and setting Header in code-behind is not a problem, DataTemplate is.

I was thinking to use attached property on GridViewColumn, however, it's not parent of cells in the visual tree:


回答1:


If you want to pass parameter to data template, then you need more MVVM (c) unknown wpf programmer

@mm8, was right, my design lack one more abstraction to hold column information (column name). I've to create column view model (simplified again):

public class ViewModelColumn
{
    public string Column { get; }

    public ViewModelColumn(string column)
    {
        Column = column;
    }
}

and the code to add column will become something like

var a = new FrameworkElementFactory(typeof(ContentControl));
a.SetValue(ContentControl.ContentProperty, new ViewModelColumn("a"));
((GridView)listView.View).Columns.Add(new GridViewColumn
{
    Header = "a",
    CellTemplate = new DataTemplate { VisualTree = a }
});

Cell data template is created in code behind. The idea is to supply ContentControl for all cells with column instance bound to Content, then the view needs another data template (this time fully defined in xaml), to know how to visualize it:

<DataTemplate DataType="{x:Type local:ViewModelColumn}">
    <TextBlock>
        <Run Text="{Binding Column, Mode=OneTime}" />
        <Run Text="{Binding DataContext,RelativeSource={RelativeSource AncestorType={x:Type ListViewItem}}, Mode=OneWay}" />
    </TextBlock>
</DataTemplate>

Such cell DataContext contains column information. To access row (access item from Items), we have to use ListViewItem.DataContext.

Now the view will looks like this:

I am pretty happy about this solution, mostly about combination of things what makes it working, but I guess it could be improved. Hopefully after posting the answer the question become clearer.



来源:https://stackoverflow.com/questions/45189875/data-template-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!