(WPF) XamDataGrid +分层+按需加载+动态列

本文关键字:加载 动态 分层 WPF XamDataGrid | 更新日期: 2023-09-27 18:03:17

我正在使用XamDataGrid,并且需要每行都是分层的(有几个子节点也是分层的)。它必须按需加载数据基于我正在查询的服务器返回的结果的动态子列。

快进位:

  • 我已经走了使用ITypedList和ICustomPropertyDescriptor来动态添加/删除属性的道路,以便可以操纵相应的列。

  • 我已经尝试动态改变FieldLayouts后面的代码,对于每个特定层次结构,由ParentFieldLayoutKey指定。然而,如果我修改任何字段布局,它会在视觉上将更改应用于所有字段布局,但在后面的代码中,实际上只修改了所选的字段布局。为什么我不能修改一个FieldLayout而不改变所有的?

  • 我还尝试使用包含与建立所需层次结构的关系的表的数据集,但到目前为止,我们还无法按需加载数据。除非有什么办法,而且是我在后勤档案里找不到的?

以下是我的要求:

  • 必须是分级的
  • 必须按需加载数据(扩展)
  • 列不应该完全知道,直到运行时/on expand/服务器被查询。

问题:

  • 是否有可能实现所有这些事情与XamDataGrid?

编辑:没错。这是有可能的。

(WPF) XamDataGrid +分层+按需加载+动态列

这是我的版本。这基本上就是你要找的。在子字段布局中动态添加列,并相应地执行数据绑定

模型:

public class Country
{
    private string _name;
    public string Name
    {
        get { return this._name; }
        set { this._name = value; }
    }
    public ObservableCollection<State> States { get; set; }
}
public class State
{
    private readonly Dictionary<string, object> _info = new Dictionary<string, object>();
    /// <summary>
    /// Attributes of the state can be added dynamically (key will be the attribtue name etc...)
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public object this[string key]
    {
        get
        {
            return this._info[key];
        }
        set
        {
            this._info[key] = value;
        }
    }
    public string StateName { get; set; }
}

行为:

public class GridFieldLayoutBehaviour : Behavior<XamDataGrid>
{
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.FieldLayoutInitialized += OnFieldLayoutInitialized;            
        this.AssociatedObject.RecordExpanded += OnRecordExpanded;
    }
    void OnRecordExpanded(object sender, Infragistics.Windows.DataPresenter.Events.RecordExpandedEventArgs e)
    {
        ((ViewModel)this.AssociatedObject.DataContext).AddStateAttributes();
    }
    void OnFieldLayoutInitialized(object sender, Infragistics.Windows.DataPresenter.Events.FieldLayoutInitializedEventArgs e)
    {
        if( e.FieldLayout.ParentFieldName == "States")
        {
            ((ViewModel)this.AssociatedObject.DataContext).GridFieldLayout = e.FieldLayout;
        }            
    }
    protected override void OnDetaching()
    {
        base.OnDetaching();            
        this.AssociatedObject.FieldLayoutInitialized -= OnFieldLayoutInitialized;
        this.AssociatedObject.RecordExpanded -= OnRecordExpanded;
    }
}

ViewModel:

public class ViewModel
{
    #region Private Fields
    private readonly ObservableCollection<Country> _countries = new ObservableCollection<Country>();        
    private readonly List<string> _stateTotalAttributes = new List<string>();        
    #endregion
    public ViewModel()
    {
        FillData();
        var stateAttributes = new string[] {"Population", "Unemployment Rate", "Capital", "Governor", "TimeZone", "Area"};
        foreach (var stateAttribute in stateAttributes)
            _stateTotalAttributes.Add(stateAttribute);                            
    }
    public ObservableCollection<Country> Countries
    {
        get { return this._countries; }
    }
    public FieldLayout GridFieldLayout { get; set; }
    /// <summary>
    /// Country and the states are populated
    /// </summary>
    private void FillData()
    {
        var country = new Country();
        country.States = new ObservableCollection<State>();            
        country.Name = "USA";            
        var xdoc = XDocument.Load("states_data.xml");
        foreach (var state in xdoc.Descendants("states").Descendants())
        {
            var newState = new State();
            newState.StateName = state.Attributes("name").FirstOrDefault().Value;
            newState["Unemployment Rate"] = state.Attributes("unemployment-rate").FirstOrDefault().Value;
            newState["Capital"] = state.Attributes("capital").FirstOrDefault().Value;
            newState["Governor"] = state.Attributes("governor").FirstOrDefault().Value;
            newState["Area"] = state.Attributes("area").FirstOrDefault().Value;
            newState["TimeZone"] = state.Attributes("timezone").FirstOrDefault().Value;
            newState["Population"] = state.Attributes("population").FirstOrDefault().Value;
            country.States.Add(newState);
        }
        _countries.Add(country);
    }
    public void AddStateAttributes()
    {
        GridFieldLayout.Fields.BeginUpdate();
        // Remove the current columns (except for StateName)
        var removableFields = GridFieldLayout.Fields.Where(f => f.Name != "StateName");
        removableFields.ToList().ForEach(field => GridFieldLayout.Fields.Remove(field));
        // Figure out what state attributes to add
        var random = new Random(DateTime.Now.Millisecond);
        var numCols = random.Next(1, 6);
        var colsToAdd = GetStateAttributes(numCols, random);
        // Finally add the new ones'
        foreach (var col in colsToAdd)
        {
            var field = new UnboundField();
            field.Name = col;
            field.Binding = new Binding()
            {
                Mode = BindingMode.TwoWay,
                Path = new PropertyPath(string.Format("[{0}]",  col)),
                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
            };
            GridFieldLayout.Fields.Add(field);
        }
        GridFieldLayout.Fields.EndUpdate();
    }
    private List<string> GetStateAttributes(int numCols, Random random)
    {            
        List<string> colsToAdd = new List<string>();
        for( int i = 0; i < numCols; i++)
        {
            int idx = random.Next(1, 6) - 1;
            if(colsToAdd.Contains(_stateTotalAttributes[idx]) == false)
            {
                colsToAdd.Add(_stateTotalAttributes[idx]);
            }
        }
        return colsToAdd;
    }
}
XAML:

    <igDP:XamDataGrid DataSource="{Binding Countries}" >
        <i:Interaction.Behaviors>
            <local:GridFieldLayoutBehaviour/>
        </i:Interaction.Behaviors>
    </igDP:XamDataGrid>

States_Data.xml:

<states>
  <state name="New York" population="19,651,127" unemployment-rate="" capital="Albany" governor="Andrew Cuomo" timezone="EST" area="54,556 sq mi"></state>
  <state name="New Hampshire" population="1,323,459 " unemployment-rate="" capital="Concord" governor="Maggie Hassan" timezone="EST" area="9,304 sq mi"></state>
</states>

问候,Vishwa

我明白了

既然我不能粘贴代码(技术上讲,它属于我工作的公司),我想我只能解释一下我做了什么。

我做了两个包装器,一个包装我的对象暴露/创建层次结构(AutoGeneratedColumns="True",默认情况下,假设你的对象内部的对象的集合是你的对象的CHILDREN),和一个ITypedList包装新的包装器,所以你可以动态地添加属性到它。

我希望这篇文章至少能有所帮助。