【发布时间】:2016-07-14 12:09:22
【问题描述】:
在AutoGenerateColmns=True 的设置中,我试图找到一种方法,让我可以在 WPF 中的 C# DataGrid 的单个单元格中显示多色文本。使用自定义单元格模板或在单元格内使用 HTML 解释器的解决方案都可以;出于技术原因,我更喜欢第一个选项,但我花了很多时间试图让其中任何一个工作,但无济于事。
另一个问题是我在这里处理了几个表,我必须使用相同的用户控件来显示它们。只有一张表需要文本格式。我已经知道如何根据我选择的标准动态更改表格的性质,但我不知道如何根据其中的实际文本填充这些修改过的单元格。文本本身包含一个用于分割字符串的标记("|||"—三个管道);一个显示为蓝色,另一个显示为红色。
让我给你看我的代码。我将从App.xaml 的摘录开始,以便清楚我是如何设置DataGrid 风格的。
我的App.xaml
如您所见,我需要让 DataGrid 自动生成列,因为我正在处理一个在编译时我不知道其架构的数据库。由于表格标题可能包含下划线,我创建了一个自定义模板,它不会以通常的方式处理下划线,即作为与 Alt 的简写键组合。
<Style x:Key="DataGridStyle" TargetType="DataGrid">
<Setter Property="AutoGenerateColumns" Value="True" />
<Setter Property="CanUserAddRows" Value="False" />
<Setter Property="ColumnHeaderStyle">
<Setter.Value>
<Style TargetType="DataGridColumnHeader">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{TemplateBinding Content}"
HorizontalAlignment="Center"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="CanUserSortColumns" Value="True" />
</Style>
DataGrid 本身
这有一些修改,其中一个是我正在使用基于另一个用户控件的自定义RowDetailsTemplate。这无关紧要(我希望如此),但为了完整起见,我把它留在这里(以防我遗漏了一些副作用)。 ExpView 是我正在使用的命名空间; “Exp”本身就是软件的名称(这就是为什么DataGrid的祖先项被称为“ExpView:ExpResultsTable”)。
你看我在这里订阅了两个事件。我已经尽可能地尝试让我的代码隐藏为空(如 MSDN 文档中建议的干净的 MVVM 实现),但我担心单独使用 XAML 只能做这么多……请随时纠正我,尽管。我使用这些事件来确定DataGrid 是用于特殊表还是普通表。
<DataGrid Name="DataGrid_Calibs"
Style="{StaticResource DataGridStyle}"
SelectedItem="{Binding Path=SelectedCalib,
RelativeSource={RelativeSource AncestorType=ExpView:ExpResultsTable}}"
AutoGeneratingColumn="DataGrid_Calibs_AutoGeneratingColumn"
LoadingRow="DataGrid_Calibs_LoadingRow">
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<ExpView:CalibrationDetails/>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
我还在此 XAML 文件的开头有以下资源声明,以防我必须显示“特殊”表。
<UserControl.Resources>
<ResourceDictionary>
<DataTemplate x:Key="DifferenceDataTemplate">
<StackPanel Orientation="Vertical">
<TextBlock x:Name="FieldValue_Old" Foreground="Blue"/>
<TextBlock x:Name="FieldValue_New" Foreground="Red"/>
</StackPanel>
</DataTemplate>
</ResourceDictionary>
</UserControl.Resources>
如果必须显示正常数据,计划是用正常数据绑定填充表。 (我没有用RowViews 填充DataGrid;而是将DataGrid 绑定到正确显示公共属性的对象。您将在下面的事件处理程序代码中看到它的效果。)如果数据是“特殊的”,我想用上面资源中定义的StackPanel 替换单元格,并设置TextBlocks(或Labels,如果这些结果更好)的内容关于应该进入单元格的字符串的第一部分和第二部分,在"|||"处拆分。
代码隐藏中的事件处理程序
用于自动生成DataGrid 列的 WPF 事件处理程序的美妙之处在于,除非您明确覆盖该列,否则它会正常工作。这就是为什么下面的代码可以很好地用前面提到的StackPanel 替换DataGrid 的单元格,以防我发现“特殊表”。
private void DataGrid_Calibs_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) {
ParameterDetails parameterDetailsControl = ((ScrollViewer)((DockPanel)((StackPanel)((DataGrid)sender).Parent).Parent).Parent).Parent as ParameterDetails;
ExpUserInterface parent = Window.GetWindow((DependencyObject)parameterDetailsControl) as ExpUserInterface;
ExpResultsTable resultsTableControl = parent.ResultsTable.Content as ExpResultsTable;
string selector = resultsTableControl.SelectedTabItem.Header.ToString();
if (selector.Equals("special")) {
DifferenceDataTemplateColumn col = new DifferenceDataTemplateColumn();
col.Header = e.PropertyName;
col.CellValue = e.PropertyName;
col.CellTemplate = (DataTemplate)FindResource("DifferenceDataTemplate");
col.CellTemplate.DataType = typeof(MyDatabaseObject);
col.IsReadOnly = true;
e.Column = col;
}
}
private void DataGrid_Calibs_LoadingRow(object sender, DataGridRowEventArgs e) {
MyDatabaseObject calib = e.Row.DataContext as MyDatabaseObject;
// anything I can do about the problem in here?
}
这里的第二个事件处理程序主要是为了向您展示我确实绑定到 MyDatabaseObject 而不是 RowView。
我欣然承认前四行是丑陋的,但至少它们现在有效。不过,欢迎提出任何建议。
其余的工作也很好:“正常”表格按计划填充,“特殊”表格在每个单元格中都使用我自定义的StackPanels 格式化。但是,我没有成功填充这些单元格。
问题
这是我这几天一直在思考的问题,但我无法通过查询通常的嫌疑人(Stackoverflow、MSDN 等)来弄清楚:
- 如何访问单元格的内容?
LoadingRow事件是我应该访问字符串、拆分它并设置FieldValue_Old.Text和FieldValue_New.Text的地方。我可以通过calib(见上文)访问该对象——调试器显示我就在那儿——但我终其一生都无法弄清楚如何访问单个的TextBlocks(“特殊”) 单元格,更不用说如何对当前行的所有列执行此操作了。 - 我可以使用
CellTemplateSelector解决这个问题吗?怎么样? - 我是否使用了正确的事件处理程序?有没有我更喜欢这些的活动?
- 还有其他方法可以达到这个结果吗?例如,我可以说服
DataGrid在其单元格中解释 HTML 吗? (这里我不需要担心代码注入,因为我只会在填写DataGrid的那一刻生成 HTML 代码。)
我们非常感谢任何帮助,并且在我为此撕扯头发时,我将不会迅速接近秃顶。谢谢!
更新
我忘记在前面提到的AutoGeneratingColumn 事件处理程序中添加自定义DataGridTemplateColumn 的代码。
public class DifferenceDataTemplateColumn : DataGridTemplateColumn {
public string CellValue { get; set; }
protected override FrameworkElement GenerateElement(DataGridCell cell, object dataItem) {
ContentPresenter presenter = (ContentPresenter)base.GenerateElement(cell, dataItem);
BindingOperations.SetBinding(presenter, ContentPresenter.ContentProperty, new Binding(this.CellValue));
return presenter;
}
}
【问题讨论】: