C# WPF DataGrid,使用转换器自定义显示

C# WPF DataGrid,使用转换器自定义显示,c#,wpf,xaml,datagrid,ivalueconverter,C#,Wpf,Xaml,Datagrid,Ivalueconverter,我有一个独特的情况。在一个类中,我有一个内部类,它的作用相当于一个“display”类。在外部类中有一个名为GetDisplayObject的方法,该方法返回内部类的类型 我试图用外部类绑定到datagrid,但通过使用转换器,我希望得到正确的显示。这样,我就不必在应用程序中更改大量代码,只需在几个.xaml文件中添加几行代码 我制作了一个小的测试应用程序,它在最基本的层面上概括了我的问题。理想情况下,我希望通过使用转换器和返回值作为显示来解决这个问题,这样当我使用SelectedItem时,我

我有一个独特的情况。在一个类中,我有一个内部类,它的作用相当于一个“display”类。在外部类中有一个名为GetDisplayObject的方法,该方法返回内部类的类型

我试图用外部类绑定到datagrid,但通过使用转换器,我希望得到正确的显示。这样,我就不必在应用程序中更改大量代码,只需在几个.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));
        }
    }
}
}

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

如果我是你,我会改变视图与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";
 }
    <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>

幸运的是,如果一个对象为null,而它的相关字符串为空,我就能够使用优先级绑定和转换器来返回DependencyProperty.UnsetValue并强制它使用下一个绑定。我认为这是最好的解决办法

所以xaml最终看起来是这样的

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

首先,place
this.DataContext=this
初始化组件()之后。我希望您将该窗口用作仅用于测试应用程序的视图模型,而不用于其他任何地方。第二,你的问题是什么?您已经描述了应用程序的体系结构,但它有什么问题?不要使用
value.GetType()==typeof(数据对象)
。有
is
as
操作符。您不应该为
DataGrid
指定
ItemTemplate
。如果您需要自定义单元格内容,则需要指定列并为它们定义
CellTemplate
。是的,我只是快速地将其组合在一起,尝试为这种情况提供一些适当的上下文。澄清一下,我的问题是我不想将itemsSource更改为DataObjectDisplay的集合。但这就是我想要在UI上表示的内容。是的,您不想更改
ItemsSource
。但您已经为自己的任务提供了解决方案:转换器。你问这行吗?这是你真正的问题吗?我正在寻找一个简单的解决方案,这样我就不必改变很多东西。我希望得到一些简单的东西,比如itemTemplate。然而,看起来在每个列单元模板上都有一个转换器可能是最简单的解决方案。我们确实遵循MVVM模式,但我认为只需将一个测试应用程序与代码放在一起就很容易了。老实说,我认为将逻辑移到转换器中不是一个坏主意。它只是一种逻辑,也可以用于任何其他类型的应用程序,因此它非常适合应用程序的较低层
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if(value == null || value as string == string.Empty)
        {
            return DependencyProperty.UnsetValue;
        }
        return value;
    }