C# Window.Resources中的WPF DataTemplate绑定参数
我正在创建一个datagrid,列标题中有过滤器。这是可行的,但我认为这不是一个好办法。让我向您展示代码,非常简单的示例: 视图C# Window.Resources中的WPF DataTemplate绑定参数,c#,wpf,xaml,mvvm,datagrid,C#,Wpf,Xaml,Mvvm,Datagrid,我正在创建一个datagrid,列标题中有过滤器。这是可行的,但我认为这不是一个好办法。让我向您展示代码,非常简单的示例: 视图 <Window x:Class="TestDataGridApp.Views.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/
<Window x:Class="TestDataGridApp.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:TestDataGridApp.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.DataContext>
<viewModels:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate x:Key="DataGridHeader">
<DockPanel>
<TextBlock DockPanel.Dock="Top" TextAlignment="Left" Text="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<TextBox DockPanel.Dock="Top" Text="{Binding DataContext.FilterName, RelativeSource={RelativeSource AncestorType=Window}, UpdateSourceTrigger=LostFocus}"/>
</DockPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding ItemCollection}" AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id}" Width="60" MinWidth="60" MaxWidth="60" HeaderTemplate="{StaticResource DataGridHeader}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" Width="60" MinWidth="60" MaxWidth="60" HeaderTemplate="{StaticResource DataGridHeader}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
基本上是简单的datagrid,2列。在每列中都有一个带有绑定过滤器的文本框。每个过滤器都有自己的字段,因此在焦点丢失后,我可以使用所有过滤器过滤网格
我的问题是。。我有很多专栏。这是定制的datagrid,因此您可以动态添加和删除列,并且存在大量重复的代码。基本上这是重复的:
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<DockPanel>
<TextBlock DockPanel.Dock="Top" TextAlignment="Left" Text="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<TextBox DockPanel.Dock="Top"
Text="{Binding DataContext.FilterId, RelativeSource={RelativeSource AncestorType=Window}, UpdateSourceTrigger=LostFocus}"/>
</DockPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
但是,我必须等待上下文。。一个文本框。我真的不确定这个解决方案
我的问题是,如何在上述场景中为DataTemplate创建参数?
谢谢你的帮助
另外,这不是重复的。这个问题是关于“如何为DataTemplate创建参数”。“重复”问题是关于词典作为一个绑定-这个问题的一个潜在解决方案。。虽然可能不是。正如另一位用户所建议的,可能有完全不同的更好的解决方案来解决这个问题。两件不同的事情。我感到震惊的是,我不得不解释这一点,最简单的方法是不要只依赖xaml,还要添加一些代码来帮助。例如,使用TextBox
的Loaded
事件,如下所示:
<DataTemplate x:Key="DataGridHeader">
<DockPanel>
<TextBlock DockPanel.Dock="Top" TextAlignment="Left" Text="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<TextBox DockPanel.Dock="Top" Loaded="OnFilterBoxLoaded" />
</DockPanel>
</DataTemplate>
您可以使用attached属性来实现相同的功能,但我认为在这种情况下不需要它。我使用了Evk解决方案和DependencyProperty
而不是使用头
<controls:FilterDataGridTextColumn FilterName="Name" Header="Name" Binding="{Binding Path=Name}" Width="200" HeaderTemplate="{StaticResource HeaderTemplate}" />
可能是@Rekshino的复制品你是认真的吗?这不是复制品。这里我问的是“如何为DataTemplate创建参数”,另一个问题是关于“作为绑定的字典”。这个问题的答案可能与词典毫无关系。你读过这两个问题吗?谢谢!我没有想到这种方法。但这可能奏效!尽管如此,我可能无法使用parent.Column.Header
,因为它可能包含空格、括号等。它肯定会起作用,因为我在发布之前对它进行了测试:)至于Header-您可以使用任何其他属性(可能是绑定路径)或创建附加属性,并将其用于网格列以提供明确的筛选器名称。我可以张贴一个例子,如果你有一些麻烦,使用附加属性为这个。为什么附加属性?我使用了您的解决方案,但使用了简单的DependencyProperty
我将此作为答案发布。你能评论一下这是否正确吗?它起作用了。。我只是不明白为什么要附财产?@LouisaBickley是的,这也是正确的。我考虑的是附加属性,因为有了它们,您可以使用额外的元数据扩展默认类(比如使用过滤器名称扩展DataGridColumn)。在您的情况下,确实可以从列继承,这并不比使用附加属性更糟糕(甚至更好)。
<Window.Resources>
<DataTemplate x:Key="DataGridHeader">
<DockPanel>
<TextBlock DockPanel.Dock="Top" TextAlignment="Left" Text="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<TextBox DockPanel.Dock="Top" Text="{Binding DataContext.FilterName, RelativeSource={RelativeSource AncestorType=Window}, UpdateSourceTrigger=LostFocus}"/>
</DockPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding ItemCollection}" AutoGenerateColumns="False">
<DataGrid.ColumnHeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>
</DataGrid.ColumnHeaderStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id}" Width="60" MinWidth="60" MaxWidth="60" HeaderTemplate="{StaticResource DataGridHeader}"/>
<DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" Width="60" MinWidth="60" MaxWidth="60" HeaderTemplate="{StaticResource DataGridHeader}"/>
</DataGrid.Columns>
</DataGrid>
</Grid>
<TextBox x:Name="Foo" DockPanel.Dock="Top" Text="{Binding DataContext.FiltersDictionary[Foo], RelativeSource={RelativeSource AncestorType=Window}, UpdateSourceTrigger=LostFocus}"/>
<DataTemplate x:Key="DataGridHeader">
<DockPanel>
<TextBlock DockPanel.Dock="Top" TextAlignment="Left" Text="{Binding Content, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
<TextBox DockPanel.Dock="Top" Loaded="OnFilterBoxLoaded" />
</DockPanel>
</DataTemplate>
private void OnFilterBoxLoaded(object sender, RoutedEventArgs e) {
var tb = (TextBox)sender;
// find column
DataGridColumnHeader parent = null;
DependencyObject current = tb;
do {
current = VisualTreeHelper.GetParent(current);
parent = current as DataGridColumnHeader;
}
while (parent == null);
// setup binding
var binding = new Binding();
// use parent column header as name of the filter property
binding.Path = new PropertyPath("DataContext.Filter" + parent.Column.Header);
binding.Source = this;
binding.UpdateSourceTrigger = UpdateSourceTrigger.LostFocus;
tb.SetBinding(TextBox.TextProperty, binding);
}
<controls:FilterDataGridTextColumn FilterName="Name" Header="Name" Binding="{Binding Path=Name}" Width="200" HeaderTemplate="{StaticResource HeaderTemplate}" />
public class FilterDataGridTextColumn : DataGridTextColumn
{
public static readonly DependencyProperty FilterNameProperty =
DependencyProperty.Register("FilterName", typeof(string), typeof(FilterDataGridTextColumn));
public string FilterName
{
get { return (string) GetValue(FilterNameProperty); }
set { SetValue(FilterNameProperty, value); }
}
}