You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF DataGrid用DataTemplate/DataTriggers数据不显示:TestField不在集合上下文

解决方法

核心思路

要解决这个问题,关键是在DataGrid的列/模板中同时获取两个上下文:集合项(TestCollection里的元素)和ViewModel的TestField。以下是几种实用的实现方式:


方法1:用DataTrigger结合RelativeSource切换模板

直接在XAML里通过RelativeSource找到DataGrid的DataContext(也就是ViewModel),再根据TestField的值动态切换CellTemplate:

<DataGrid ItemsSource="{Binding TestCollection}"
          AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="动态列">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <!-- ContentControl的DataContext是集合项,同时通过RelativeSource绑定ViewModel的TestField -->
                    <ContentControl>
                        <ContentControl.Style>
                            <Style TargetType="ContentControl">
                                <!-- 默认模板 -->
                                <Setter Property="ContentTemplate">
                                    <Setter.Value>
                                        <DataTemplate>
                                            <TextBlock Text="{Binding 默认属性}" />
                                        </DataTemplate>
                                    </Setter.Value>
                                </Setter>
                                <!-- TestField为ABCD时的模板 -->
                                <Style.Triggers>
                                    <DataTrigger 
                                        Binding="{Binding DataContext.TestField, RelativeSource={RelativeSource AncestorType=DataGrid}}" 
                                        Value="ABCD">
                                        <Setter Property="ContentTemplate">
                                            <Setter.Value>
                                                <DataTemplate>
                                                    <!-- 绑定集合项的属性,比如Name -->
                                                    <TextBlock Text="{Binding Name}" Foreground="Blue" />
                                                </DataTemplate>
                                            </Setter.Value>
                                        </Setter>
                                    </DataTrigger>
                                    <!-- TestField为EFGH时的模板 -->
                                    <DataTrigger 
                                        Binding="{Binding DataContext.TestField, RelativeSource={RelativeSource AncestorType=DataGrid}}" 
                                        Value="EFGH">
                                        <Setter Property="ContentTemplate">
                                            <Setter.Value>
                                                <DataTemplate>
                                                    <!-- 绑定集合项的属性,比如Id -->
                                                    <Button Content="{Binding Id}" Width="80" />
                                                </DataTemplate>
                                            </Setter.Value>
                                        </Setter>
                                    </DataTrigger>
                                </Style.Triggers>
                            </Style>
                        </ContentControl.Style>
                    </ContentControl>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

方法2:自定义DataTemplateSelector切换模板

如果模板逻辑复杂,写在XAML里太臃肿,可以自定义模板选择器,在代码里获取ViewModel的TestField来选择模板:

1. 编写模板选择器

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

public class TestTemplateSelector : DataTemplateSelector
{
    // 可在XAML中绑定的模板属性
    public DataTemplate AbcdTemplate { get; set; }
    public DataTemplate EfghTemplate { get; set; }
    public DataTemplate DefaultTemplate { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        // 从VisualTree中找到父级DataGrid,获取ViewModel
        var dataGrid = FindAncestor<DataGrid>(container);
        if (dataGrid?.DataContext is ViewModel vm)
        {
            return vm.TestField switch
            {
                "ABCD" => AbcdTemplate,
                "EFGH" => EfghTemplate,
                _ => DefaultTemplate
            };
        }
        return DefaultTemplate;
    }

    // 递归查找父级控件
    private T FindAncestor<T>(DependencyObject obj) where T : DependencyObject
    {
        while (obj != null)
        {
            if (obj is T ancestor)
                return ancestor;
            obj = VisualTreeHelper.GetParent(obj);
        }
        return null;
    }
}

2. 在XAML中使用

<Window.Resources>
    <!-- 定义不同的模板 -->
    <DataTemplate x:Key="AbcdTemplate">
        <TextBlock Text="{Binding Name}" Foreground="Blue" />
    </DataTemplate>
    <DataTemplate x:Key="EfghTemplate">
        <Button Content="{Binding Id}" Width="80" />
    </DataTemplate>
    <DataTemplate x:Key="DefaultTemplate">
        <TextBlock Text="{Binding Description}" />
    </DataTemplate>

    <!-- 实例化自定义选择器 -->
    <local:TestTemplateSelector x:Key="TestSelector"
                                AbcdTemplate="{StaticResource AbcdTemplate}"
                                EfghTemplate="{StaticResource EfghTemplate}"
                                DefaultTemplate="{StaticResource DefaultTemplate}" />
</Window.Resources>

<DataGrid ItemsSource="{Binding TestCollection}"
          AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="动态列"
                                CellTemplateSelector="{StaticResource TestSelector}" />
    </DataGrid.Columns>
</DataGrid>

方法3:ViewModel动态生成列集合

如果需要根据TestField显示完全不同的列(比如不同数量、不同类型的列),可以在ViewModel中生成列集合,直接绑定到DataGrid的Columns:

1. 修改ViewModel

using System.Collections.ObjectModel;
using System.Windows.Controls;
using System.ComponentModel;

public class ViewModel : INotifyPropertyChanged
{
    private string _testField;
    public string TestField
    {
        get => _testField;
        set
        {
            _testField = value;
            OnPropertyChanged();
            // TestField变化时重新生成列
            GenerateColumns();
        }
    }

    public ObservableCollection<object> TestCollection { get; set; }
    public ObservableCollection<DataGridColumn> Columns { get; set; }

    public ViewModel()
    {
        TestField = "ABCD";
        TestCollection = new ObservableCollection<object>();
        Columns = new ObservableCollection<DataGridColumn>();
        GenerateColumns();
    }

    private void GenerateColumns()
    {
        Columns.Clear();
        var app = System.Windows.Application.Current;

        if (TestField == "ABCD")
        {
            Columns.Add(new DataGridTemplateColumn
            {
                Header = "名称",
                CellTemplate = app.FindResource("AbcdTemplate") as DataTemplate
            });
            // 可以添加更多列
            Columns.Add(new DataGridTextColumn
            {
                Header = "编号",
                Binding = new System.Windows.Data.Binding("Id")
            });
        }
        else if (TestField == "EFGH")
        {
            Columns.Add(new DataGridTemplateColumn
            {
                Header = "操作按钮",
                CellTemplate = app.FindResource("EfghTemplate") as DataTemplate
            });
        }
        // 其他TestField值的列配置...
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. XAML绑定

<DataGrid ItemsSource="{Binding TestCollection}"
          Columns="{Binding Columns}"
          CanUserAddColumns="False"
          CanUserDeleteColumns="False"
          AutoGenerateColumns="False" />

内容的提问来源于stack exchange,提问作者Павел Закриев

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 20:22:49