【问题标题】:Binding data grid column to dynamic properties将数据网格列绑定到动态属性
【发布时间】:2014-08-25 18:03:59
【问题描述】:

我正在处理一项要求,可以将任意数量的动态属性添加到实体中。除了实际的对象属性之外,这些动态属性还可以显示在数据网格列中。

为了尊重现有架构,将这些属性存储在一个列表中:

public List<AdaErgaenzungsfeldEntity> Ergaenzungsfelder { get; set; }

为了绑定到列表中的每个属性,我公开了将在网格中显示的值,如下所示:

public Dictionary<Guid, object> ErgaenzungsfeldValues { 
   get { return m_ergaenzungsfeldValues; } 
}

当 Ergaenzungsfelder 列表发生变化时,列表和字典正在同步:

private void RefreshErgaenzungsfeldValues() {
   if (m_ergaenzungsfeldValues == null) {
      m_ergaenzungsfeldValues = new Dictionary<Guid, object>();
   }

   m_ergaenzungsfeldValues.Clear();
   foreach (AdaErgaenzungsfeldEntity entity in Ergaenzungsfelder) {
      m_ergaenzungsfeldValues.Add(entity.Ergaenzungsfeld.ID, entity.Value);
   }
}

到网格上的绑定最终是这样完成的:

List<ErgaenzungsfeldEntity> ergaenzungsfeldEntities = m_presenter.ErgaenzungsfeldService.GetAllErgaenzungsfeldEntities();
   foreach (ErgaenzungsfeldEntity entity in ergaenzungsfeldEntities) {
      m_lstAdas.Columns.Add(new Column {
         Title = entity.Name,
         FieldName = string.Format("ErgaenzungsfeldValues[{0}]", entity.ID)
      });
}

这个实现的问题是字典不包含所有实体的所有动态字段的值,这显然会导致 key not found 异常:

System.Windows.Data 错误:16:无法获取“项目 []”值(类型 '对象')来自'ErgaenzungsfeldValues'(类型'Dictionary2'). BindingExpression:Path=ErgaenzungsfeldValues[04d1be1c-2d83-48ba-b179-aaa9f0d0f7bc]; DataItem='AdaEntity' (HashCode=-800079524); target element is 'DataCell' (Name=''); target property is 'Content' (type 'Object') TargetInvocationException:'System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary. at System.ThrowHelper.ThrowKeyNotFoundException() at System.Collections.Generic.Dictionary2.get_Item(TKey key)---结束 内部异常堆栈跟踪 --- 在 System.RuntimeMethodHandle._InvokeMethodFast(对象目标,对象 [] 参数,SignatureStruct& sig,MethodAttributes 方法属性, RuntimeTypeHandle typeOwner) 在 System.RuntimeMethodHandle.InvokeMethodFast(对象目标,对象 [] 参数,签名 sig,MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner) 在 System.Reflection.RuntimeMethodInfo.Invoke(对象 obj,BindingFlags invokeAttr、Binder binder、Object[] 参数、CultureInfo 文化、 Boolean skipVisibilityChecks)在 System.Reflection.RuntimeMethodInfo.Invoke(对象 obj,BindingFlags invokeAttr、Binder binder、Object[] 参数、CultureInfo 文化)
在 System.Reflection.RuntimePropertyInfo.GetValue(对象 obj, BindingFlags invokeAttr、Binder binder、Object[] index、CultureInfo 文化)在 MS.Internal.Data.PropertyPathWorker.GetValue(Object 项目,Int32 级别)在 MS.Internal.Data.PropertyPathWorker.RawValue(Int32 k)'

实体不知道所有可能的字段,因此不可能为每个实体添加每个动态属性的默认值。

问题:如何将这些动态值正确绑定到数据网格以避免上述异常?

我创建了一个小应用程序来说明这种行为。

MainWindow.xaml:

<Window x:Class="DynamicdataGridBindingTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        Title="MainWindow" 
        Height="350" 
        Width="525">
    <Grid>
        <xcdg:DataGridControl 
            Name="m_dataGridControl" 
            AutoCreateColumns="False" 
            AutoRemoveColumnsAndDetailConfigurations="False"
            ReadOnly="True"
            ItemsSource="{Binding TestEntities}">
            <xcdg:DataGridControl.Columns>
                <xcdg:Column Title="Property"
                             FieldName="DefinedProperty" />
            </xcdg:DataGridControl.Columns>
        </xcdg:DataGridControl>
    </Grid>
</Window>

MainWindow.xaml.cs:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Xceed.Wpf.DataGrid;

namespace DynamicdataGridBindingTest {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow {
        private readonly Dictionary<Guid, string> m_dynamicColumnNames = new Dictionary<Guid, string> {
            {Guid.NewGuid(),"DynText"}, 
            {Guid.NewGuid(),"DynBool"}, 
            {Guid.NewGuid(),"DynArray"}
        };

        public ObservableCollection<TestEntity> TestEntities { get; private set; }

        public MainWindow() {
            //Licenser.LicenseKey = "xxx";
            TestEntities = new ObservableCollection<TestEntity>();

            InitializeComponent();
            InitializeEntities();
            InitializedataGridColumns();
        }


        private void InitializeEntities() {
            TestEntity testEntity1 = new TestEntity {
                DefinedProperty = "Property Value 1",
            };
            testEntity1.DynamicProperties.Add(m_dynamicColumnNames.ElementAt(0).Key, "My text");
            testEntity1.DynamicProperties.Add(m_dynamicColumnNames.ElementAt(1).Key, true);
            testEntity1.DynamicProperties.Add(m_dynamicColumnNames.ElementAt(2).Key, new[] { "val1.1", "val1.2", "val1.3" });
            TestEntities.Add(testEntity1);

            TestEntity testEntity2 = new TestEntity {
                DefinedProperty = "Property Value 2"
            };
            testEntity2.DynamicProperties.Add(m_dynamicColumnNames.ElementAt(0).Key, "My text 2");
            TestEntities.Add(testEntity2);
        }

        private void InitializedataGridColumns() {
            foreach (string columnName in m_dynamicColumnNames.Values) {
                m_dataGridControl.Columns.Add(new Column {
                    Title = columnName,
                    FieldName = string.Format("DynamicProperties[{0}]", m_dynamicColumnNames.First(kv => kv.Value == columnName).Key)
                });
            }
        }
    }
}

TestEntity.cs:

namespace DynamicdataGridBindingTest {

    public class TestEntity {
        public string DefinedProperty { get; set; }
        public Dictionary<Guid, object> DynamicProperties { get; private set; }

        public TestEntity() {
            DynamicProperties = new Dictionary<Guid, object>();
        }
    }
}

运行时如下所示:

【问题讨论】:

    标签: c# wpf xaml data-binding xceed-datagrid


    【解决方案1】:

    我已经通过实现一个最小的字典实现来解决这个问题,包装一个字典,但不抛出 key not found 异常:

    using System.Collections.Generic;
    
    namespace DynamicdataGridBindingTest {
        /// <summary>
        /// This is a minimal implementation of a Dictionary, which will never throw KeyNotFoundException if trying to access a value for a key which hasn't been set.
        /// </summary>
        /// <typeparam name="TKey">The type of the key.</typeparam>
        /// <typeparam name="TValue">The type of the value.</typeparam>
        public class DictionaryWithReturnValue<TKey, TValue> {
            #region Private Fields
    
            private readonly Dictionary<TKey, TValue> m_dictionary;
    
            #endregion
    
            #region Constructor
    
            /// <summary>
            /// Initializes a new instance of the <see cref="DictionaryWithReturnValue{TKey, TValue}"/> class.
            /// </summary>
            public DictionaryWithReturnValue() {
                m_dictionary = new Dictionary<TKey, TValue>();
            }
    
            #endregion
    
            #region Indexer
    
            /// <summary>
            /// Gets or sets the value for the specified key.
            /// </summary>
            /// <param name="key">The key.</param>
            /// <returns>The value, if it has been previously set; otherwise default(TValue)</returns>
            public TValue this[TKey key] {
                get {
                    TValue value;
                    return m_dictionary.TryGetValue(key, out value) ? value : default(TValue);
                }
                set { m_dictionary[key] = value; }
            }
    
            #endregion
    
            #region Public Methods
    
            /// <summary>
            /// Adds the specified key.
            /// </summary>
            /// <param name="key">The key.</param>
            /// <param name="value">The value.</param>
            public void Add(TKey key, TValue value) {
                m_dictionary.Add(key, value);
            }
    
            /// <summary>
            /// Removes the specified key.
            /// </summary>
            /// <param name="key">The key.</param>
            public void Remove(TKey key) {
                m_dictionary.Remove(key);
            }
    
            /// <summary>
            /// Clears all the entries.
            /// </summary>
            public void Clear() {
                m_dictionary.Clear();
            }
    
            #endregion
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-07-27
      • 2017-02-16
      • 1970-01-01
      • 2013-04-15
      • 2010-12-21
      • 1970-01-01
      • 2016-11-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多