WPF 数据网格,使用转换器自定义显示



我有一个独特的情况。在一个类中,我有一个内部类,它几乎只是一个"显示"类。在外部类中,有一个名为 GetDisplayObject 的方法,该方法返回内部类的类型。

我正在尝试使用外部类绑定到数据网格,但通过使用转换器,我想获得正确的显示。这样,我就不必更改应用程序中的一堆代码,只需在几个 .xaml 文件中添加几行即可。

我做了一个小的测试应用程序,几乎总结了我最基本的问题。理想情况下,我想通过使用转换器并仅将值作为显示来解决问题,这样当我使用 SelectedItem 时,我就不必更改依赖于该特定类型的大量代码(在这种情况下将是 DataObject 类型(。

所以这是我被困在处理的对象

namespace TestApp
{
public class DataObject
{
public class DataObjectDisplay
{
public string ObjectDisplay { get; set; }
}
// props
public int Id { get; set; }
public object Object1 { get; set; }
public object Object2 { get; set; }
// method for getting the display
public DataObjectDisplay GetDisplayObject()
{
DataObjectDisplay display = new DataObjectDisplay();
// logic for determining which object should be displayed
if(Object1 == null)
{
display.ObjectDisplay = "Object1";
}
else
{
display.ObjectDisplay = "Object2";
}
return display; 
}
}
}

这是我的 xaml 的代码隐藏

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
namespace TestApp
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
this.DataContext = this;
InitializeComponent();
this.DataObjectCollection = new ObservableCollection<DataObject>();
this.DataObjectCollection.Add(new DataObject() { Id = 1, Object1 = "this", Object2 = "that" });
this.DataObjectCollection.Add(new DataObject() { Id = 1, Object2 = "that" });
this.SelectedItem = new DataObject();
}
private ObservableCollection<DataObject> dataObjectCollection;
private DataObject selectedItem;
public ObservableCollection<DataObject> DataObjectCollection
{
get { return this.dataObjectCollection; }
set
{
dataObjectCollection = value;
OnNotifyPropertyChanged("DataObjectCollection");
}
} 
public DataObject SelectedItem
{
get { return this.selectedItem; }
set
{
selectedItem = value;
OnNotifyPropertyChanged("SelectedItem");
}
}

public event PropertyChangedEventHandler PropertyChanged;
private void OnNotifyPropertyChanged(string property = "")
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
}

这是 xaml(这类似于我想做的事情,使用 itemtemplate 或类似的东西,然后是一个转换器来调用这个 GetDisplay 函数(

<Window x:Class="TestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestApp"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:DataObjectToDisplayDataObjectConverter x:Key="ToDisplayConverter"/>
</Window.Resources>
<StackPanel>
<DataGrid ItemsSource="{Binding DataObjectCollection}" SelectedItem="{Binding SelectedItem}" MinHeight="200">
<DataGrid.ItemTemplate>
<DataTemplate>
<ContentPresenter Content="{Binding Converter={StaticResource ToDisplayConverter}}"/>
</DataTemplate>
</DataGrid.ItemTemplate>
</DataGrid>
</StackPanel>
</Window>

最后是转换器

using System;
using System.Globalization;
using System.Windows.Data;
namespace TestApp
{
public class DataObjectToDisplayDataObjectConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null && value.GetType() == typeof(DataObject))
{
DataObject dataObj = (DataObject)value;
dataObj.GetDisplayObject();
return dataObj;
}
return "Invalid Value";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

我愿意接受建议,但这只是一个小例子。在我们的实际应用中,改变一件事很可能会演变成一个巨大的考验。

如果我是你,我会改变视图与ViewModel的紧密耦合,比如创建新的MainWindowViewModel类并包含所有属性。

我看到的另一件事 GetDisplayObject 方法,从转换器调用这样的方法有什么需要。

你可以重构这段代码,并在转换器中放这样的东西。

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DataObject dataObj = value as DataObject;
if (value == null)
{
return "Invalid Value";
}
if (dataObj.Object1 == null)
{
return "Object1";
}
return "Object2";
}

幸运的是,由于这是一个对象是否为空并且其相关字符串为空的问题,因此我能够将优先级绑定与转换器一起使用以返回 DependencyProperty.UnsetValue 并强制它使用下一个绑定。我认为这是这种情况的最佳解决方案。

所以xaml最终看起来像这样。

<DataGrid ItemsSource="{Binding DataObjectCollection}" SelectedItem="{Binding SelectedItem}" MinHeight="200">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<PriorityBinding>
<Binding Path="Object1" Converter="{StaticResource EmptyStringToDependencyPropertyUnset}"/>
<Binding Path="Object2"/>
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>

转换器的结局是这样的

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value == null || value as string == string.Empty)
{
return DependencyProperty.UnsetValue;
}
return value;
}

最新更新