0

我正在使用 MVVM 模式开发 WPF 项目。

到目前为止一切正常,但现在我面临一个丑陋的设计问题。为了显示我的数据,我DataGrid像其他人一样使用 a ,但我ItemsSource的是 aList<List<MyClass>>因为我需要通过DataTemplate. 在我DatagridCells的身上,我也得到了这个工作,但现在我需要在一些 UI 条目之后重新排序我不存在的列,但这会很痛苦,所以想知道你将使用什么样的类表类来提供这些对象?

我需要能够做什么(易于编程):

  • 访问每个单元格
  • 重新排序/交换列
  • 重新排序/交换行

编辑:

之后现在看到要理解我在这里实际做了一些进一步的信息并不容易。

因为他们不明白aList<List<MyClass>>是什么,它只不过是aMyClass[,]

@Charleh
"How do you reorder non-existent columns?"
绝妙的问题......如果你能正确阅读,你会发现我需要一个新类型的数据提供者,也就是一个真正的表,而不是我List<List<MyClass>>没有列的人,因为如果你有这样一个List<List<MyClass>>让你命名 的让MyListListerMyListLister[0]将是一个行并且MyListLister[0][0]会成为一个细胞

You mean you have a single column because you are using a data template to show the object?
我为每个代码创建我的 DataGrid,因为它需要是动态的,因为用户可以在每次选择后根据 Combobox 选择更改整个 DataGrid 的样式我需要重新创建我的 DataGrid 并修改我的 MyListLister 但要将其用作 ItemsSoucre 我必须做这个黑客

@HighCore
Post the relevant XAML
并没有真正有用的 xaml,所以我会在休息后提供一个简单的例子

编辑2:

抱歉这个例子的延迟,但这是我的简单例子

主窗口

XAML

<Window x:Class="TableToDataGrid.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
    <Label Name="theElement"/>
</Window>

。CS

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    theElement.Content = new MyUsercontrol();
}

我的用户控件

XAML

<UserControl x:Class="TableToDataGrid.MyUsercontrol"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:vmv="clr-namespace:TableToDataGrid">
    <UserControl.Resources>
        <DataTemplate x:Key="MyCellTemplate"  DataType="{x:Type vmv:myClass}">
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </UserControl.Resources>
    <Label Name="AddYourDataGridHere"/>
</UserControl>

。CS

using System.Linq;
using System.Windows;
using System.Collections;
using System.Windows.Data;
using System.Windows.Controls;
using System.Collections.Generic;

namespace TableToDataGrid
{
    /// <summary>
    /// Interaktionslogik für MyUsercontrol.xaml
    /// </summary>
    public partial class MyUsercontrol : UserControl
    {
        DataGrid myDataGrid = new DataGrid();
        public MyUsercontrol()
        {
            InitializeComponent();

            var list = new List<List<myClass>>();

            for (int row = 0; row < 3; row++)
            {
                var myRow = new List<myClass>();
                for (int col = 0; col < 5; col++)
                    myRow.Add(new myClass() { ID = col, Name = "Row" + row + " Column:" + col });
                list.Add(myRow);
            }

            #region the hack 
            for (int c = 0; c < 5; c++)
            {
                DataGridTemplateColumn column = new DataGridTemplateColumn();                
                var factory = new FrameworkElementFactory(typeof(ContentPresenter));
                factory.SetBinding(ContentPresenter.ContentProperty, new Binding(string.Format("[{0}]", c.ToString())));
                factory.SetValue(ContentPresenter.ContentTemplateProperty, this.FindResource("MyCellTemplate") as DataTemplate);
                column.SetValue(DataGridTemplateColumn.CellTemplateProperty, new DataTemplate { VisualTree = factory });
                myDataGrid.Columns.Add(column);
            }
            #endregion the hack 

            myDataGrid.ItemsSource = list.AsEnumerable<IEnumerable>();
            myDataGrid.AutoGenerateColumns = false;
            AddYourDataGridHere.Content = myDataGrid;
        }
    }
}

我的类.cs

namespace TableToDataGrid
{
    public class myClass
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
}

如您所见,结果是一个普通的表。有没有人知道如何以更简单的方式提供相同的结果(ItemsSource)我可以从上面做我的 3 分?

4

1 回答 1

2

WiiMaxx,

听起来您正试图以线性方式显示深层对象图,这对于 DataGrid 来说可能非常麻烦。我能够通过从我的实体基类上的 DynamicObject 继承来应对这一挑战(在这种情况下我使用的是实体框架)。如果您不熟悉 DynamicObject,您可以在此链接中了解它

http://msdn.microsoft.com/en-us/library/system.dynamic.dynamicobject.aspx

本质上,它允许您做的是使用属性包来存储动态属性,这些动态属性将在运行时使用动态类型在您的对象上出现和继续。当您需要将图形展平以在数据网格中显示时,这是一个很好的解决方案。您只需要确保覆盖 TryGetMember 和 TrySetMember 方法。这在与数据绑定结合使用时特别漂亮,因为您可以在运行时添加/删除成员,并且通过数据绑定,WPF 将尝试通过那些覆盖的方法访问/更新这些成员。

public class EntityBase : DynamicObject, INotifyPropertyChanged
{
    public Dictionary<string, object> DynamicProperties { get; set; }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises this object's PropertyChanged event.
    /// </summary>
    /// <param name="propertyName">The property that has a new value.</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (!HasProperty(propertyName))
        {
            return;
        }

        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            var e = new PropertyChangedEventArgs(propertyName);
            handler(this, e);
        }
    }

    public bool HasProperty(string propertyName)
    {
        // Verify that the property name matches a real,  
        // public, instance property on this object.
        if (TypeDescriptor.GetProperties(this)[propertyName] != null)
        {
            return true;
        }

        return false;
    }

    #endregion


    #region Ctor

    public EntityBase()
    {
        this.DynamicProperties = new Dictionary<string, object>();
    }

    #endregion


    #region DynamicObject Overrides

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
        string name = binder.Name.ToLower();

        return this.DynamicProperties.TryGetValue(name, out result);
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        this.DynamicProperties[binder.Name.ToLower()] = value;

        OnPropertyChanged(binder.Name);

        return true;
    }

    #endregion
}

现在,使用它作为模型类型的基类,您可以在运行时添加/删除成员并仍然利用 WPF 数据绑定。

所以接下来我们需要展平我们的图表。ViewModelBase 下面的基类简单地实现了 INotifyPropertyChanged。

public class YourViewModel : ViewModelBase
{
    private YourDeepObjectGraphClass _instance;
    public YourDeepObjectGraphClass Instance
    {
        get { return _yourClass; }
        set
        {
            _yourClass = value;

            OnPropertyChanged("Instance");
        }
    }

    public void FlattenGraph()
    {
        foreach (IEnumerable<DeepObjectGraphType> t in Instance.List)
        {
            ((dynamic)Instance).YourDynamicProperty = t.SomeProperty;
        }
    }
}

现在,在您的视图中,您可以将控件(ItemsControl、DataGrid)上的绑定设置为“YourDynamicProperty”,并且 WPF 将为您呈现它,前提是您在后面的代码中调用了 InitializeComponent 之后调用了 FlattenGraph。

希望对您有所帮助,如果您有任何问题,请告诉我。

于 2013-04-30T22:43:00.740 回答