【问题标题】:WPF DataGrid display 'NULL' when bound property is null当绑定属性为空时,WPF DataGrid 显示“NULL”
【发布时间】:2026-01-08 04:35:01
【问题描述】:

当相应的源值为空时,我试图显示一个包含“NULL”字符串的单元格而不是空白单元格。我正在使用绑定到DataTableAutoGenerateColumns="True"DataGrid

以前我设法通过 AutoGeneratedColumns 事件在代码隐藏中做到这一点,但现在我已经切换到 MVVM 设计,我想避免这种情况。

foreach (var column in dgwCustomTableSelected.Columns)
{
    if (column is DataGridTextColumn) 
    {
        ((DataGridTextColumn)column).Binding = 
            new Binding() { 
                Converter = new NullValueConverter((string)column.Header) 
            };
    }
}

我想知道是否有办法将转换器关联到所有数据网格列或任何其他可行的解决方案。

提前致谢

【问题讨论】:

  • mvvm != 没有代码隐藏。具体来说,视图相关的代码应该存在于视图中。许多新的 mvvm 开发人员认为一切都必须出来,并且经常犯将 UI 相关代码放在他们的视图模型中的错误。不要那样做。

标签: c# wpf mvvm datagrid ivalueconverter


【解决方案1】:

我想知道是否有办法将转换器关联到所有数据网格列或任何其他可行的解决方案。

“可行的解决方案”是处理视图中的AutoGeneratingColumn 事件。或者在同一视图的 XAML 标记中显式定义所有列。

这两种方法都不会破坏 MVVM 模式,因为这是与视图相关的功能,而 MVVM 不是要从视图中消除与视图相关的代码。它主要是关于关注点分离和以编程方式执行视图相关的事情,而不是在 XAML 标记中执行它是非常好的。

【讨论】:

  • 谢谢@mm8,我可以聘请你作为个人顾问,如果你在你得到他们的地方休息一下:) 定义所有列是不可能的,因为我使用这种方法来映射 DataGrid从我的服务器端返回的任何类型的结果集。所以我不知道我必须提前处理哪个专栏。我将继续为此使用代码。正如您所说,并非所有代码隐藏都会破坏 MVVM 模式。再次感谢
【解决方案2】:

我会尝试在ViewModel 中执行此操作。假设您的 ViewModel 类看起来像这样(为简单起见,我将 INotofyPropertyChanged 排除在外):

public class ViewModel
{
    private ModelClass model = new ModelClass();

    public string Name
    {
       get
       {
           return model.Name;
       }
       set
       {
           model.name = value;
       }
    }
}

你可以把它重构成这样:

public class ViewModel
{
    private ModelClass model = new ModelClass();

    public string Name
    {
       get
       {
           if(model.Name == null)
           {
              return "NULL";
           }

           return model.Name;
       }
       set
       {
           model.name = value;
       }
    }
}

【讨论】:

  • 感谢@Romano 帮助我。好吧,在我的 ViewModel 中,我直接公开了一个 DataGrid 绑定到的 DataTable。我让 DataGrid 根据 DataTable 内容自动生成它的列
  • @gipinani 你从哪里得到DataTable?你能在填充DataTable之前替换string
  • 我从 WCF 服务获取数据表。好吧,我将继续向 DataGrid 提供 DataModel。在填充 DataGrid 之前替换字符串可能意味着遍历所有行/列并替换值(如果我很好理解的话)。老实说,这似乎有点矫枉过正
【解决方案3】:

您也可以尝试Custom Markup Extension,这将允许您在Binding 中包含Converter。为此,您还必须为不同类型的数据创建DataTemplates,但总体收益(即处理数据类型)将超过编码量。这是来自searchwindevelopment的上述标记扩展的示例

class NumberToBrushConverter : MarkupExtension, IValueConverter
{
    private static NumberToBrushConverter _converter = null;

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        // determine if we have an instance of converter
        // return converter to client
        return _converter ?? (_converter = new NumberToBrushConverter());
    }
    public object Convert(object value, Type targetType,
                      object parameter,CultureInfo culture)
    {

        return new SolidColorBrush(Colors.Orange);
    }

    public object ConvertBack(object value, Type targetType, 
                          object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }

  }  

然后在 xaml 中你会像这样使用它:

<Window x:Class="ValueConverterTips.CustomMarkupTip"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:converters='clr-namespace:ValueConverterTips.Converters'
    Title="CustomMarkupTip" >

    <!-- no longer need the resources section -->

    <Grid>
        <Ellipse Fill='{Binding SomeIntData,  
         Converter={converters:NumberToBrushConverter}}'
         Width='10' Height='10' />
    </Grid>
</Window>  

您必须修改它以适合您的场景。
编辑
这就是你将它与AutoGenerateColumns=true 一起使用的方式:

<Style TargetType="DataGridColumnHeader">
<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate>
            <Button Content="Ok"/>
        </ControlTemplate>
    </Setter.Value>
</Setter>
</Style>

<DataGrid AutGenerateColumns="true" ItemsSource={Binding xxx} etc...>

</DataGrid>

【讨论】:

  • 这如何应用于自动生成的 DataGrid 列和实际问题?
  • @mm8 我向您推荐“我想知道是否有办法将转换器关联到所有数据网格列或任何其他可行的解决方案。”并特别强调关于任何其他可行的解决方案。
  • 问题是这些列没有在 XAML 中定义,而是自动生成的。
  • 是的@XAMlMAX,正如 mm8 所说,我对要渲染的列一无所知。这就是为什么我不能有静态列定义
  • @mm8 我希望这更有意义?如果部分答案来自 SO 帖子,您可以找到 here,这与此问题非常相似。