问题
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:
- This is simplified case.
- In reality data templates are more complicated: many elements with bindings, triggers, etc.
- In reality column related data are more complicated than just header.
- Columns will be generated at runtime with different headers, etc.
- 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