質問

I am using XamDataGrid and need each row to be hierarchical (with several child nodes that are also hierarchical). It must load its data on demand and have dynamic child columns based on the results that are returned by a server I'm querying.

Fast forwarding a bit:

  • I have gone down the road of using ITypedList and ICustomPropertyDescriptor to dynamically add/remove properties so that the corresponding columns can be manipulated. To no avail.

  • I have tried dynamically changing FieldLayouts in the code behind, for each specific level of hierarchy, specified by ParentFieldLayoutKey. Yet, if I modify ANY of my field layouts, it applies the changes to all field layouts visually, but in the code behind, only the chosen field layout is actually modified. Why can't I modify one FieldLayout without changing all of them?

  • I have also tried using a DataSet that contains tables with relationships to ESTABLISH the desired hierarchy, but in doing so have thus far been unable to load data on demand. Unless there's some way to do that, that I haven't been able to find anywhere in the infragistics docs?

Here are my requirements:

  • Must be hierarchical
  • Must load data on demand (on expand)
  • Columns should not be known fully until runtime/on expand/when server is queried.

Questions:

  • Is it possible to achieve all of these things with XamDataGrid?

Edit: Yep. It's possible.

役に立ちましたか?

解決 2

Figured it out.

Since I can't paste the code (technically, it belongs to the company I work for), I guess I'll just have to settle with explaining BASICALLY what I did.

I made two wrappers, one to wrap my object to expose/create hierarchy (AutoGeneratedColumns="True", by default, assumes that a collection of objects inside of your object is your object's CHILDREN), and an ITypedList to wrap the new wrapper, so you can dynamically add properties to it.

I hope this post was at least somewhat informative.

他のヒント

Here is my version. This basically does what you were looking for. In the child fieldlayout columns are dynamically added and data binding is performed accordingly

Models:

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

Behaviour:

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>

Regards, Vishwa

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top