【问题标题】:WPF DataGrid cell string format as a style or templateWPF DataGrid 单元格字符串格式作为样式或模板
【发布时间】:2011-09-09 17:23:25
【问题描述】:

我尝试了几种方法来分解 WPF DataGrid(.NET 4 提供的一种)中单元格的格式:

  • 数据转换器,
  • 样式中的“StringFormat”绑定属性,
  • 数据模板中的“StringFormat”绑定属性。

我将描述我的尝试,因为它可能对其他人有所帮助,我希望有人可以给我建议以改进这些解决方案。请注意,我对 WPF 相当陌生...

预期的行为是单元格字符串被格式化为特定的格式,例如“1,234,567”以进行显示,但在编辑单元格时它应该被格式化为“1234567”(其默认格式)。当我尝试使用数据转换器时,我没有找到在编辑时使用默认格式的方法,因此我将精力集中在样式和模板上。

使用样式,DataGridTextColumn 的定义如下:

<DataGridTextColumn Header="Price (Style)" SortMemberPath="BILL_PRICE">
    <DataGridTextColumn.ElementStyle>
        <Style TargetType="{x:Type TextBlock}">
            <Setter Property="Text" Value="{Binding Path=BILL_PRICE, StringFormat={}{0:N0}}"/>
        </Style>
    </DataGridTextColumn.ElementStyle>
    <DataGridTextColumn.EditingElementStyle>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Text" Value="{Binding Path=BILL_PRICE}"/>
            <Setter Property="Padding" Value="0"/>
            <Setter Property="BorderThickness" Value="0"/>
        </Style>
    </DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>

行为正是预期的。但是,由于绑定的原因,我无法分解出这种样式并多次使用它。为了解决分解问题,我使用了 DataGridTemplateColumn 和数据模板。这是我的 DataGridTemplateColumn 定义:

<DataGridTemplateColumn Header="Price (Template)" SortMemberPath="BILL_PRICE">
    <DataGridTemplateColumn.CellTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding BILL_PRICE}" Template="{StaticResource CurrencyCellControlTemplate}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellTemplate>
    <DataGridTemplateColumn.CellEditingTemplate>
        <DataTemplate>
            <ContentControl Content="{Binding BILL_PRICE, Mode=TwoWay}" Template="{StaticResource CurrencyCellEditingControlTemplate}"/>
        </DataTemplate>
    </DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>

以及 ControlTemplate 定义:

<ControlTemplate x:Key="CurrencyCellControlTemplate" TargetType="ContentControl">
    <TextBlock Margin="2,0,2,0" Padding="0" TextAlignment="Right">
        <TextBlock.Text>
            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Content" StringFormat="{}{0:N0}"/>
        </TextBlock.Text>
    </TextBlock>
</ControlTemplate>

<ControlTemplate x:Key="CurrencyCellEditingControlTemplate" TargetType="ContentControl">
    <TextBox Padding="0" BorderThickness="0" TextAlignment="Right">
        <TextBox.Text>
            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Content"/>
        </TextBox.Text>
    </TextBox>
</ControlTemplate>

使用数据模板解决了分解 DataGrid 单元格格式的最初问题,但使用控制模板会带来人体工程学和视觉问题。例如,由控件模板引起的双标签导航(在许多其他地方讨论过),以及编辑文本框的外观(我尝试通过边框粗细、填充和其他属性设置来修复。)

与此问题相关的具体问题是:

  • 是否可以使用数据转换器来格式化字符串以进行显示并使用默认格式进行编辑?
  • 是否可以排除 DataGridTextColumn 样式,同时仍然能够指定绑定源?
  • 有没有一种方法可以使用 DataGridTemplateColumn 而只是让它看起来和感觉像 DataGridTextColumn?

【问题讨论】:

  • 您是否尝试过获取和使用 DataGridTextColumn 的“默认”模板并且只更改您需要的位?您可能需要默认模板中内置的所有触发器。
  • 我不确定如何处理这个问题。默认模板是否具体化为某些 XAML?我尝试了方便地显示默认模板的工具(在选择主题和特定控件时显示为 XAML),但 DataGridTextColumn 没有。或者你的意思是我应该在后面的代码中获取默认模板并将其动态应用于列?

标签: wpf datagrid datagridtemplatecolumn string-formatting datagridtextcolumn


【解决方案1】:

制作您自己的自定义 DataGridTextColumn 并创建绑定以分配给 Element 和 EditingElement(其中一个带有转换器,其中一个没有转换器)。

转换器将字符串格式化为带逗号的小数。

 public class MyDataGridTextColumn : DataGridTextColumn
{
    Binding formattedBinding;
    Binding unformattedBinding;
    FormatConverter formatConverter = new FormatConverter();

    protected override FrameworkElement
    GenerateElement(DataGridCell cell, object dataItem)
    {
       var element = base.GenerateElement(cell, dataItem) as TextBlock;
       element.SetBinding(TextBlock.TextProperty, GetFormattedTextBinding());
        return element;
    }

    protected override FrameworkElement
    GenerateEditingElement (DataGridCell cell, object dataItem)
    {
        var element = base.GenerateEditingElement(cell, dataItem) as TextBox;
        element.SetBinding(TextBox.TextProperty, GetTextBinding());
        return element;
    }

    Binding
    GetTextBinding()
    {

            var binding = (Binding)Binding;
            if (binding == null) return new Binding();
            unformattedBinding = new Binding
            {
                Path = binding.Path,
                Mode=BindingMode.TwoWay
            };

        return unformattedBinding;
    }

    Binding
    GetFormattedTextBinding()
    {
         var binding = (Binding)Binding;
            if (binding == null) return new Binding();
            formattedBinding = new Binding
            {
                Path = binding.Path,
                Converter = Formatter,
            };

        return formattedBinding;
    }

    public FormatConverter
    Formatter
    {
        get { return formatConverter; }
        set { formatConverter = value; }
    }
}
public class FormatConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string textvalue = value as string;
        if (!string.IsNullOrEmpty(textvalue))
        {
            decimal decimalvalue = decimal.Parse(textvalue);
            var test = String.Format("{0:0,0.00}", decimalvalue);
            return test;
        }
        else
            return "";

    }
    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new InvalidOperationException("FormatConverter can only be used OneWay.");
    }
}

我不明白你发布的格式化字符串是如何工作的,所以我做了一个简单的,如果你想要更多的小数位,只需在转换器中对其进行排序。

您现在需要做的就是在您的 xaml 中放置对命名空间的引用,然后在数据网格中创建一个列。

那么一切都会好起来的

u_u

【讨论】:

  • 确实,子类化是要走的路。起初我在寻找一种纯粹在 XAML 中的方法,但如果没有自定义 DataGridColumn 似乎是不可能的。
  • @Jason Ridge 认真的吗?要格式化列单元格中的内容,这个解决方案非常复杂。
猜你喜欢
  • 1970-01-01
  • 2020-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-08
  • 2011-05-12
相关资源
最近更新 更多