2

我也在Infragistics上问过这个问题,但不知道如何在那里格式化我的代码,所以在这里它是正确格式化的。

我的目标是呈现一个结构化数据表,其中包含使用多种颜色的每个单元格的文本。我有一个类型转换器,它将存储在自定义类中的数据转换为包含几个不同颜色的文本元素的标签或文本块。数据在数据表中提供(任何可行的方法都可以),并且每个值都正确应用于单元格。

问题是,它没有使用我的 TypeConverter,而是使用了 ToString 方法,我重写了该方法,因此我知道模型正确的模型数据逐个单元格地映射到网格上。此外,我正在使用的 ControlTemplate 属性也没有应用,这告诉我 ControlTemplate 没有被使用。

一个问题是,在数据网格中可能不可能有不同字母具有不同颜色的文本。如果是这样,是否有另一种方法可以完成,同时仍然具有良好的用户体验并将设计保留在 xaml 文件中(这对于网格来说很难)。

据我了解,我的代码应该定义一个自定义 CellValuePresenter,任何人都可以帮我应用它吗?

我在这里发布我的相关代码。大部分内容都被混淆了,所以请不要关注拼写错误。

  <Window x:Class="ViewName"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="clr-namespace:LocalNamespace"
          xmlns:ViewModel="clr-namespace:LocalNamespace.ViewModel"
          xmlns:model="clr-namespace:LocalNamespace.Model"
          xmlns:igDP="http://infragistics.com/DataPresenter"
          >
      <Window.Resources>
          <local:Converter x:Key="converter" />
          <ViewModel:ViewModelLocator x:Key="viewModelLocator" />
          <Style TargetType="{x:Type igDP:CellValuePresenter}" x:Key="cellTemplate" x:Name="cellTemplate" >
              <Setter Property="Template">
                  <Setter.Value>
                      <ControlTemplate TargetType="{x:Type igDP:CellValuePresenter}">
                          <Label 
                              Content="{Binding Converter={StaticResource converter}}"
                              Width="200"
                              MaxWidth="600"
                              MinHeight="20"
                              />
                      </ControlTemplate>
                  </Setter.Value>
              </Setter>
          </Style>
      </Window.Resources>
        <StackPanel Name="stackPanel">
            <igDP:XamDataGrid Name="DifferenceGrid" DataSource="{Binding Source={StaticResource viewModelLocator}, Path=ViewModel.Model}" 
                              ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible">
                <igDP:XamDataGrid.FieldLayouts>
                    <igDP:FieldLayout>
                        <igDP:FieldLayout.Fields>
                            <igDP:Field>
                                <igDP:Field.Settings>
                                    <igDP:FieldSettings 
                                        CellValuePresenterStyle="{StaticResource cellTemplate}">
                                    </igDP:FieldSettings>
                                </igDP:Field.Settings>
                            </igDP:Field>
                        </igDP:FieldLayout.Fields>
                    </igDP:FieldLayout>
                </igDP:XamDataGrid.FieldLayouts>
            </igDP:XamDataGrid>
        </StackPanel>
  </Window>

    class ViewModelLocator
    {
        private static ViewModel viewModel = new ViewModel();

        public ViewModel ViewModel
        {
            get
            {
                return viewModel;
            }
        }
    }

  public class ViewModel
    {
        private DataTable model;

        public DataTable Model
        {
            get
            {
                return this.model;
            }

            private set
            {
                this.model = value;
            }
        }

    [global::System.ComponentModel.TypeConverter(typeof(Model.CustomClass))]
    public class Converter : TypeConverter, IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (this.CanConvertTo(targetType))
            {
                return this.ConvertTo(value);
            }
            else
            {
                return null;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (this.CanConvertFrom(targetType))
            {
                return this.ConvertFrom(value);
            }
            else
            {
                return null;
            }
        }

        public new bool CanConvertFrom(Type sourceType)
        {
            // Textboxes don't need to be converted back.
            return sourceType == typeof(Model.CustomClass);
        }

        public new bool CanConvertTo(Type destinationType)
        {
            return destinationType == typeof(Model.CustomClass);
        }

        public object ConvertTo(object value)
        {
            return this.ConvertCustomClassToTextBlock(value);
        }

        public new object ConvertFrom(object value)
        {
            return this.ConvertCustomClassToTextBlock(value);
        }

        private object ConvertCustomClassToTextBlock(object value)
        {
            TextBlock text = new TextBlock();
            Label cell = new Label();

      // Construct the TextBlock.

      cell.Context = text;
      return text; // Or cell, whatever works.
    }
  }
4

2 回答 2

4

XamDataGrid 单元格包含编辑器,对于应显示为文本的值,编辑器是 XamTextEditor。

您必须修改 XamTextEditor 的模板并在以下代码中提供您自己的模板:

<Window x:Class="XamDataGridApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:igDP="http://infragistics.com/DataPresenter"
        xmlns:igEditors="http://infragistics.com/Editors"
        xmlns:local="clr-namespace:XamDataGridApp"
        Title="Colorful XamDataGrid" SizeToContent="WidthAndHeight">
    <igDP:XamDataGrid FieldLayoutInitialized="OnFieldLayoutInitialized">
        <igDP:XamDataGrid.DataSource>
            <!-- Replace this with your data source. -->
            <local:DataSourceMock/>
        </igDP:XamDataGrid.DataSource>
        <igDP:XamDataGrid.Resources>
            <local:XamTextEditorConverter x:Key="XamTextEditorConverter" x:Shared="True"/>
            <Style TargetType="igEditors:XamTextEditor" BasedOn="{StaticResource {x:Type igEditors:XamTextEditor}}">
                <Style.Setters>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type igEditors:XamTextEditor}">
                                <Border x:Name="MainBorder" 
                                        Background="{TemplateBinding Background}"
                                        BorderBrush="{TemplateBinding BorderBrush}"
                                        BorderThickness="{TemplateBinding BorderThickness}"
                                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
                                    <ContentPresenter
                                        Margin="{TemplateBinding Padding}"
                                        HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                        VerticalAlignment="{TemplateBinding VerticalContentAlignment}">
                                        <ContentPresenter.Content>
                                            <MultiBinding Converter="{StaticResource XamTextEditorConverter}">
                                                <Binding Path="DisplayText" RelativeSource="{RelativeSource TemplatedParent}"/>
                                                <Binding RelativeSource="{RelativeSource TemplatedParent}"/>
                                            </MultiBinding>
                                        </ContentPresenter.Content>
                                    </ContentPresenter>
                                </Border>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style.Setters>
            </Style>
            <Style TargetType="igEditors:XamTextEditor" x:Key="CustomClassXamTextEditorStyle" x:Shared="True" BasedOn="{StaticResource {x:Type igEditors:XamTextEditor}}">
                <Setter Property="ValueToDisplayTextConverter" Value="{x:Static local:CustomClassToStringConverter.Instance}"/>
                <Setter Property="ValueToTextConverter" Value="{x:Static local:CustomClassToStringConverter.Instance}"/>
            </Style>
        </igDP:XamDataGrid.Resources>
    </igDP:XamDataGrid>
</Window>

以下 IMultiValueConverter 用于强制生成 XamTextEditor 内容:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using Infragistics.Windows.DataPresenter;
using Infragistics.Windows.Editors;

namespace XamDataGridApp
{
    class XamTextEditorConverter : IMultiValueConverter
    {
        private static readonly IList<Brush> colors = new Brush[] { Brushes.Red, Brushes.Green, Brushes.Blue };

        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var displayText = (string)values[0] ?? string.Empty;

            // Context that can be used for custom coloring.
            var editor = (XamTextEditor)values[1];
            var dataItemPresenter = editor.Host as DataItemPresenter;

            // Context that can be used for custom coloring.
            var dataValue = editor.Value;
            var dataItem = dataItemPresenter != null ? dataItemPresenter.Record.DataItem : null;

            var textBlock = new TextBlock()
            {
                TextWrapping = editor.TextWrapping,
                TextAlignment = editor.TextAlignment
            };

            for (int i = 0; i < displayText.Length; ++i)
                textBlock.Inlines.Add(new Run(displayText[i].ToString()) { Foreground = colors[i % colors.Count] });

            return textBlock;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}

XamTextEditor 模板中的 ContentPresenter 必须将数据绑定到编辑器的 DisplayText 属性,因为 XamDataGrid 单元格是虚拟化的,并且通过绑定我们指示 XamDataGrid 在单元格虚拟化启动时重新生成 ContentPresenter 内容(当 CellValuePresenter 被重用以呈现另一个值时)。此外,由于数据绑定,即使在 XamDataGrid 之外更改了内容,也会重新生成内容。

MultiBinding 用于传递上下文 (XamTextEditor),可以从中提取数据值和数据项并在着色逻辑中使用。如果不需要上下文,可以使用 IValueConverter 简单绑定到 DisplayText。


更新:

为了让 XamDataGrid 使用您的转换器,您必须在 FieldSettings(而不是 FieldLayouts)中定义 CellValuePresenterStyle,如下面的 XAML 片段所示:

<igDP:XamDataGrid Name="DifferenceGrid" DataSource="{Binding Source={StaticResource viewModelLocator}, Path=ViewModel.Model}" 
                      ScrollViewer.CanContentScroll="True" ScrollViewer.HorizontalScrollBarVisibility="Visible" ScrollViewer.VerticalScrollBarVisibility="Visible">
    <igDP:XamDataGrid.FieldSettings>
        <igDP:FieldSettings CellValuePresenterStyle="{StaticResource cellTemplate}"/>
    </igDP:XamDataGrid.FieldSettings>
</igDP:XamDataGrid>

使用此代码片段,您可以为 XamDataGrid 中的所有单元格指定默认 CellValuePresenterStyle。

如果您想指定您的 CustomClass 列使用 XamTextEditor 并且所有其他列使用它们自己的默认编辑器,您可以通过处理FieldLayoutInitialized事件来做到这一点,如下面的代码:

private void OnFieldLayoutInitialized(object sender, FieldLayoutInitializedEventArgs e)
{
    foreach (var field in e.FieldLayout.Fields)
        if (field.DataType == typeof(Model.CustomClass))
        {
            field.Settings.EditorType = typeof(XamTextEditor);
            // Set Editor style in which display converter and edit converter are specified.
            field.Settings.EditorStyle = (Style)((FrameworkElement)sender).FindResource("CustomClassXamTextEditorStyle");
        }
}

更新了上面的 MainWindow.xaml 以反映这些更改。

这里还有 CustomClassToStringConverter 的代码,当我在 XamDataGrid 中显示和编辑 CustomClass 时,我用它来将 CustomClass 转换为字符串并再次返回(我将 Text 属性添加到 CustomClass,因为我不知道如何从中提取文本):

class CustomClassToStringConverter : IValueConverter
{
    public static CustomClassToStringConverter Instance = new CustomClassToStringConverter();

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ((CustomClass)value).Text;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return new CustomClass() { Text = (string)value };
    }
}
于 2012-12-10T21:22:54.967 回答
0

谢谢我现在开始工作了。必须提供带有文本块的单独数据源,现在不需要多重绑定。但我不知道 MVVM 是否仍然适用,这是一个非常丑陋的解决方案。

    public DataTable TextBlocks
    {
        get
        {
            Converter converter = new DifferenceToTextConverter();
            DataTable table = new DataTable();

            foreach (DataColumn col in this.Model.Columns)
                table.Columns.Add(col.ColumnName, typeof(TextBlock));

            foreach (DataRow row in this.Model.Rows)
            {
                DataRow addedRow = table.NewRow();
                for (int col = 0; col < row.ItemArray.Length; col++)
                {
                    addedRow[col] = converter.ConvertTo(row[col]);
                }

                table.Rows.Add(addedRow);
            }

            return table;
        }
    }
于 2012-12-14T12:19:54.647 回答