c# - WPF 数据网格 : converter and StringFormat

标签 c# wpf .net-3.5

我有一个标准(WPF 工具包)数据网格。某些列(明确定义)必须显示为百分比。如果值低于 0,则某些列必须显示为红色。(两组列不同)。我尝试分别使用 StringFormatStyle 来实现这些要求。我的 XAML:

<Window xmlns:local="clr-namespace:myNamespace"
        xmlns:tk="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit">
    <Window.Resources>
        <local:ValueConverter x:Key="valueToForeground" />
        <Style TargetType="{x:Type tk:DataGridCell}">
            <Setter Property="Foreground"
                    Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource valueToForeground}}" />
        </Style>
    </Window.Resources>
    <Grid>
        <tk:DataGrid AutoGenerateColumns="False"
                     ItemsSource="{Binding Path=myClass/myProperty}">
            <tk:DataGrid.Columns>
                <tk:DataGridTextColumn Header="A"
                                       Binding="{Binding colA}" />
                <tk:DataGridTextColumn Header="B"
                                       Binding="{Binding colB, StringFormat=\{0:P\}}" />
                <tk:DataGridTextColumn Header="C"
                                       Binding="{Binding colC, StringFormat=\{0:P\}}" />
                <tk:DataGridTextColumn Header="D"
                                       Binding="{Binding colD, StringFormat=\{0:P\}}" />
            </tk:DataGrid.Columns>
        </tk:DataGrid>
    </Grid>
</Window>

以及相关的转换器:

namespace myNamespace
{
    public class ValueConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            SolidColorBrush brush = new SolidColorBrush(Colors.Black);

            Double doubleValue = 0.0;
            if (value != null)
            {
                if (Double.TryParse(value.ToString(), out doubleValue))
                {
                    if (doubleValue < 0)
                        brush = new SolidColorBrush(Colors.Red);
                }
            }
            return brush;
        }

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

我认为这一切都非常标准,但问题是转换器在通过 StringFormat 后获取 Text 值,此时很难解析它正确(因为实际上,并非所有列都具有相同的格式)。如果我取出 StringFormats,转换器工作正常并且文本显示为红色。我错过了一些明显的东西吗?有没有一种简单的方法可以解决这个问题?我现在唯一能想到的就是将格式转移到不同的转换器中,但我不相信这会奏效。

最佳答案

我们有类似的情况,我们需要一个不同的 Path属性为Binding但在其他方面类似 CellStyle对于每个 DataGridColumn .我们用自定义 MarkupExtension 解决了这个问题.在你的情况下它看起来像这样

<tk:DataGrid AutoGenerateColumns="False" 
                ItemsSource="{Binding MyItems}">
    <tk:DataGrid.Columns>
        <tk:DataGridTextColumn Header="A" 
                               Binding="{Binding colA}" />
        <tk:DataGridTextColumn Header="B" 
                               Binding="{Binding colB, StringFormat=\{0:P\}}"
                               CellStyle="{markup:ForegroundCellStyle PropertyName=colB}"/>
        <tk:DataGridTextColumn Header="C" 
                               Binding="{Binding colC, StringFormat=\{0:P\}}"
                               CellStyle="{markup:ForegroundCellStyle PropertyName=colC}"/>
        <tk:DataGridTextColumn Header="D" 
                               Binding="{Binding colD, StringFormat=\{0:P\}}"
                               CellStyle="{markup:ForegroundCellStyle PropertyName=colD}"/>
    </tk:DataGrid.Columns>
</tk:DataGrid>

然后 ForegroundCellStyleExtension创建Style对于 DataGridCell取决于 PropertyName

ForegroundCellStyleExtension

public class ForegroundCellStyleExtension : MarkupExtension
{
    public ForegroundCellStyleExtension() { }
    public ForegroundCellStyleExtension(string propertyName)
    {
        PropertyName = propertyName;
    }

    public string PropertyName
    {
        get;
        set;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        IProvideValueTarget service = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
        DependencyObject targetObject = service.TargetObject as DependencyObject;
        if (targetObject == null)
        {
            return null;
        }

        Binding foregroundBinding = new Binding
        {
            Path = new PropertyPath(PropertyName),
            Converter = new ValueConverter()
        };
        Style foregroundCellStyle = new Style(typeof(DataGridCell));
        foregroundCellStyle.Setters.Add(new Setter(DataGridCell.ForegroundProperty, foregroundBinding));

        return foregroundCellStyle;
    }
}

此外,如果您还有一些其他的 Setters等你想使用然后他们可以通过另一个参数包含到 MarkupExtension .

<Window.Resources>
    <Style x:Key="dataGridCellStyle" TargetType="{x:Type tk:DataGridCell}">
        <Setter Property="Background" Value="Blue"/>
    </Style>
</Window.Resources>
<!-- ... -->
<tk:DataGridTextColumn Header="B" 
                       Binding="{Binding colB, StringFormat=\{0:P\}}"
                       CellStyle="{markup:ForegroundCellStyle colB, {StaticResource dataGridCellStyle}}"/>

ForegroundCellStyleExtension然后将第二个参数用作 BasedOn对于 DataGridCell Style

带有 BasedOn 的 ForegroundCellStyleExtension

public class ForegroundCellStyleExtension : MarkupExtension
{
    public ForegroundCellStyleExtension() { }
    public ForegroundCellStyleExtension(string propertyName, Style basedOnCellStyle)
    {
        PropertyName = propertyName;
        BasedOnCellStyle = basedOnCellStyle;
    }

    public string PropertyName
    {
        get;
        set;
    }
    public Style BasedOnCellStyle
    {
        get;
        set;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        IProvideValueTarget service = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
        DependencyObject targetObject = service.TargetObject as DependencyObject;
        if (targetObject == null)
        {
            return null;
        }

        Binding foregroundBinding = new Binding
        {
            Path = new PropertyPath(PropertyName),
            Converter = new ValueConverter()
        };
        Style foregroundCellStyle = new Style(typeof(DataGridCell), BasedOnCellStyle);
        foregroundCellStyle.Setters.Add(new Setter(DataGridCell.ForegroundProperty, foregroundBinding));

        return foregroundCellStyle;
    }
}

关于c# - WPF 数据网格 : converter and StringFormat,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10796128/

相关文章:

c# - 布局 C# 类的最佳方式是什么?

wpf - 为什么这个标签在绑定(bind)时看起来与静态值不同?

.net - 在不使用来自另一个线程的 Invoke/BeginInvoke 的情况下读取表单控件值(但不更改它)是否是线程安全的

c# - 在货币数据 C# 中查找货币符号

c# - 无法编译Xamarin UWP应用

wpf - 有没有办法对属性的属性使用样式 setter ?

asp.net - 无法计算表达式,因为代码已优化或 native 框架位于调用堆栈顶部

c# - 是否可以在 XAML 中绑定(bind) Canvas 的 Children 属性?

c# - 用户控件自定义属性在构建时失去值(value)

wpf - 使用 WPF MediaElement 渲染 HDVideo 是否成功? WPF 有更好的视频播放器选项吗?