简体   繁体   English

WPF datagrid:converter和StringFormat

[英]WPF datagrid: converter and StringFormat

I have a standard (WPF toolkit) data grid. 我有一个标准(WPF工具包)数据网格。 Some of the columns (which are explicitly defined) have to be shown as percentages. 一些列(明确定义)必须以百分比显示。 Some columns have to be shown in red if the values are below 0. (The two sets of columns are not the same). 如果值低于0,则某些列必须以红色显示。(两组列不相同)。 I tried to implement these requirements using a StringFormat and Style , respectively. 我尝试分别使用StringFormatStyle实现这些要求。 My XAML: 我的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>

And the relevant converter: 和相关的转换器:

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

I think it's all pretty standard, but the problem is that the converter gets the Text value after it's gone through the StringFormat , and at that point it's difficult to parse it correctly (since in reality, not all columns have the same format). 我认为这一切都很标准,但问题是转换器在经过StringFormat之后获取Text值,并且此时很难正确解析它(因为实际上并非所有列都具有相同的格式)。 If I take out the StringFormats , the converter works fine and the text shows up in red. 如果我取出StringFormats ,转换器工作正常,文本显示为红色。 Am I missing something obvious? 我错过了一些明显的东西吗 Is there an easy way to work around this? 有一种简单的方法可以解决这个问题吗? The only thing that I can think of right now is moving the formatting into a different converter, and I'm not convinced that would work. 我现在唯一能想到的就是将格式转移到另一个转换器中,我不相信它会起作用。

We had a similar situation where we needed a different Path Property for the Binding but otherwise a similar CellStyle for each DataGridColumn . 我们遇到类似的情况,我们需要为Binding使用不同的Path属性,否则每个DataGridColumn都需要一个类似的CellStyle We solved this with a custom MarkupExtension . 我们使用自定义MarkupExtension解决了这个问题。 In your case it would look like this 在你的情况下,它看起来像这样

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

and then ForegroundCellStyleExtension creates the Style for DataGridCell depending on PropertyName 然后ForegroundCellStyleExtension根据PropertyNameDataGridCell创建Style

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

Also, if you have some other Setters etc. that you would like to use then they can be included by another parameter to the MarkupExtension . 此外,如果您要使用其他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}}"/>

And ForegroundCellStyleExtension would then use the second parameter as BasedOn for the DataGridCell Style 然后ForegroundCellStyleExtension将第二个参数用作DataGridCell Style BasedOn

ForegroundCellStyleExtension with BasedOn 使用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;
    }
}

Specify a cell style for each column as follows: 为每列指定单元格样式,如下所示:

<DataGridTextColumn Header="ColA" Binding="{Binding colA, StringFormat=\{0:P\}}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">
            <Setter Property="Foreground" 
                    Value="{Binding colA, Converter={StaticResource valueToForeground}}" />
         </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

<DataGridTextColumn Header="ColB" Binding="{Binding colB, StringFormat=\{0:P\}}">
    <DataGridTextColumn.CellStyle>
        <Style TargetType="DataGridCell">
            <Setter Property="Foreground" 
                    Value="{Binding colB, Converter={StaticResource valueToForeground}}" />
         </Style>
    </DataGridTextColumn.CellStyle>
</DataGridTextColumn>

... 

and modify your converter 并修改您的转换器

public class ValueConverter : IValueConverter
{
    public object Convert(
                object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((double) value < 0) ? Brushes.Red : Brushes.Black;
    }

    public object ConvertBack(
                object value, Type targetType, object parameter, CultureInfo culture)
    {
        return Binding.DoNothing;
    }
}

在此输入图像描述

The simplest way I figured out is to bind your full item instead of the item/content.text only to your converter. 我想出的最简单的方法是将您的完整项目而不是item / content.text仅绑定到您的转换器。 Then you will be able to do what you wanted to do with your cells with need to worry about the item and parameter values. 然后,您将能够对您的单元格执行您需要担心的项目和参数值。

In your Cell Style: 在你的细胞风格:

 <Setter Property="Foreground"
     Value="{Binding Converter={StaticResource valueToForeground}}" />

and in your Converter code: 并在您的转换器代码中:

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)
    {
        mydatatype data = value as mydatatype;
        //your logic goes here and also can play here with your dataitem. 
        if (Double.TryParse(data.CollD.ToString(), out doubleValue))
        {
            if (doubleValue < 0)
               brush = new SolidColorBrush(Colors.Red);
        }        
    }
    return brush;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM