gpt4 book ai didi

c# - Window.Resources 中的 WPF DataTemplate 绑定(bind)参数

转载 作者:行者123 更新时间:2023-11-30 21:41:43 26 4
gpt4 key购买 nike

我正在创建一个数据网格,在列标题中使用过滤器。它有效,但我认为这不是一个好方法。让我向您展示代码,非常简单的示例:

View

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

View 模型

namespace TestDataGridApp.ViewModels
{
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Data;
using TestDataGridApp.Entities;
using Prism.Mvvm;
public class MainWindowViewModel : BindableBase
{
private string _filterId;
private string _filterName;
private ObservableCollection<Item> _items = new ObservableCollection<Item>();

public MainWindowViewModel()
{
for (int i = 1; i <= 100; ++i)
{
Items.Add(new Item() {Id = i, Name = $"Item{i}"});
}
}
public string FilterId
{
get { return _filterId; }
set
{
SetProperty(ref _filterId, value);
TriggerFilters();
}
}
public string FilterName
{
get { return _filterName; }
set
{
SetProperty(ref _filterName, value);
TriggerFilters();
}
}
public ObservableCollection<Item> Items
{
get { return _items; }
set { SetProperty(ref _items, value); }
}
public ICollectionView ItemCollection => CollectionViewSource.GetDefaultView(Items);

private void TriggerFilters()
{
ItemCollection.Filter = o => FilterItem((Item)o);
}
private bool FilterItem(Item item)
{
try
{
bool checkId = false;
bool checkName = false;

int itemId = 0;
if (!string.IsNullOrEmpty(FilterId) && int.TryParse(FilterId, out itemId)) checkId = true;
if (!string.IsNullOrEmpty(FilterName)) checkName = true;

if (!checkId && !checkName) return true;
if (item == null) return false;

bool checkIdIsOk = (checkId && item.Id == int.Parse(FilterId) || !checkId);
bool checkNameIsOk = (checkName && item.Name.ToUpper().Contains(FilterName.ToUpper()) || !checkName);
if (checkIdIsOk && checkNameIsOk) return true;
}
catch (Exception e)
{
Console.WriteLine(e);
}
return false;
}
}
}

项目

public class Item
{
public int Id { get; set; }
public string Name { get; set; }
}

基本简单的数据网格,2 列。在每一列中都有一个 TextBox带绑定(bind)过滤器。每个过滤器都有自己的字段,所以在失去焦点后,我可以通过所有过滤器过滤网格。

我的问题是..我有很多专栏。这是定制的数据网格,因此您可以即时添加和删除列,并且有很多重复代码。基本上这是重复的:

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

... 只有这个 <TextBox DockPanel.Dock="Top" Text="{Binding DataContext.FilterId, ...正在针对不同的列进行更改。

所以,我想,我可以很容易地用这个解决方案替换它,但是现在..我失去了对 ViewModel 中我的过滤器字段的绑定(bind):

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

SOO.. 我在想,创建一个Dictionary对于过滤器,其中 key 是列的名称,在 value 中我将存储当前过滤器(或者 null,如果此时此列没有过滤器)。像..

<TextBox x:Name="Foo" DockPanel.Dock="Top" Text="{Binding DataContext.FiltersDictionary[Foo], RelativeSource={RelativeSource AncestorType=Window}, UpdateSourceTrigger=LostFocus}"/>

但是我必须为一个 TextBox 投标上下文。我真的不确定这个解决方案..

我的问题是,如何在上述场景中为 DataTemplate 创建参数?

感谢您的帮助!

附言。这不是重复的。这个问题是关于“如何为 DataTemplate 创建参数”。 “重复”问题是关于字典作为绑定(bind)的—​​—这个问题的潜在解决方案……虽然可能不是。正如另一位用户所建议的那样,可能有完全不同的更好的解决方案来解决这个问题。两种不同的东西。我很震惊,我必须解释这个

最佳答案

最简单的方法是不要只依赖 xaml 并添加一些代码来提供帮助。例如,像这样使用 TextBoxLoaded 事件:

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

并在加载时设置绑定(bind):

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

您可以使用附加属性来实现相同的目的,但我认为在这种情况下不需要它。

关于c# - Window.Resources 中的 WPF DataTemplate 绑定(bind)参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43006104/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com