【问题标题】:(WPF) XamDataGrid + Hierarchical + Load on Demand + Dynamic Columns(WPF) XamDataGrid + 分层 + 按需加载 + 动态列
【发布时间】:2014-05-14 16:42:23
【问题描述】:

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

快进一点:

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

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

  • 我还尝试使用包含与 ESTABLISH 所需层次结构关系的表的 DataSet, 但这样做至今无法按需加载数据。除非有某种方法可以做到这一点,否则我无法在基础设施文档中找到任何地方?

这是我的要求:

  • 必须分层
  • 必须按需加载数据(扩展时)
  • 在运行时/展开/查询服务器之前,不应完全了解列。

问题:

  • 是否可以使用 XamDataGrid 实现所有这些目标?

编辑:是的。这是可能的。

【问题讨论】:

    标签: c# wpf infragistics xamdatagrid


    【解决方案1】:

    这是我的版本。这基本上可以满足您的需求。在子字段布局中动态添加列并相应地执行数据绑定

    型号:

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

    视图模型:

    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>
    

    问候, 维什瓦

    【讨论】:

    • 在 ViewModel 中添加 FieldLayout 对象?这不是在谋杀 MVVM 指南吗?那么为什么会有这些行为戏剧呢?
    【解决方案2】:

    想通了。

    由于我无法粘贴代码(从技术上讲,它属于我工作的公司),我想我只需要解释一下我做了什么。

    我制作了两个包装器,一个用于包装我的对象以公开/创建层次结构(AutoGeneratedColumns="True",默认情况下,假定您的对象内的对象集合是您对象的 CHILDREN),以及一个用于包装对象的 ITypedList新的包装器,因此您可以向其动态添加属性。

    我希望这篇文章至少能提供一些信息。

    【讨论】:

      猜你喜欢
      • 2020-05-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-12-29
      相关资源
      最近更新 更多