![](/img/trans.png)
[英]How to add dynamic combobox properties in propertygrid using custom property?
[英]Dynamic PropertyGrid properties
因此,對於我正在研究的這個項目,我們決定使用.NET PropertyGrid控件。 根據用戶在ListView控件中選擇的項目,將根據運行時構建的對象填充propertygrid。
因此,如果他們選擇ListView中的第一個項目(例如“Base”),PropertyGrid將顯示該組件的屬性,例如其尺寸。 然后他們選擇“Top”,它將在PropertyGrid中顯示顏色。 無論哪種方式,列表中的每個項目都是一個“組件”對象。
基本上,當選擇ListView項時,循環遍歷數據集以查找與所選組件對象關聯的屬性,然后將其拋入propertygrid中顯示的propertybag類。
我想弄清楚的是,由於這些組件和屬性都是一個類,我如何動態確定哪些屬性應該顯示為下拉菜單,圖像框或文本字段。
我正在使用Visual Studios 2010 / C#.NET,而對於動態屬性生成,我使用的是我在CodeProject上由Tony Allowatt發現的顯然很受歡迎的“Property Bag”類。 我唯一能想到的可能是為數據庫添加一個額外的列來獲取屬性,並使用它來告訴PropertyBag要添加哪些數據類型? 它似乎是一個熱門話題,但我很難找到如何與動態構建的對象一起完成它。
它本身不是一個答案,但我也一直在努力建立這樣一個野獸。 這是stackoverflow對該主題的最大熱門......
如何在運行時修改PropertyGrid(添加/刪除屬性和動態類型/枚舉)
起初我雖然實際上需要基於Expando對象的動態對象,但事實證明並非如此。 您可能希望確保不要陷入該陷阱。
在我的情況下,我真正需要的是一組自定義對象,可以添加一組可變屬性。 其中每個屬性都是三種自定義類型之一(stringType,rangeType或enumType)的實例化。 一旦我意識到“動態”屬性不會是任意類類型,項目就變成了三個stackoverflow示例中討論的代碼的簡單轉折。 問題如何在運行時修改PropertyGrid(添加/刪除屬性和動態類型/枚舉)幾乎是我最終結果的直接示例。
希望我的隨意幫助你找到自己的道路......
對於wpf,這可以解決整個問題:鏈接到源https://xceed.com/forums/topic/propertygrid-dictionary-not-displaying-values-using-icustomtypedescriptor/
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
[RefreshProperties(RefreshProperties.All)]
public class DictionaryPropertyGridAdapter<TKey, TValue> : ICustomTypeDescriptor, INotifyPropertyChanged
{
#region Fields
private readonly IDictionary<TKey, PropertyAttributes> propertyAttributeDictionary;
private readonly IDictionary<TKey, TValue> propertyValueDictionary;
#endregion
#region Constructors and Destructors
public DictionaryPropertyGridAdapter(
IDictionary<TKey, TValue> propertyValueDictionary,
IDictionary<TKey, PropertyAttributes> propertyAttributeDictionary = null)
{
this.propertyValueDictionary = propertyValueDictionary;
this.propertyAttributeDictionary = propertyAttributeDictionary;
}
#endregion
#region Events
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public AttributeCollection GetAttributes()
{
return TypeDescriptor.GetAttributes(this, true);
}
public string GetClassName()
{
return TypeDescriptor.GetClassName(this, true);
}
public string GetComponentName()
{
return TypeDescriptor.GetComponentName(this, true);
}
public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
public EventDescriptor GetDefaultEvent()
{
return TypeDescriptor.GetDefaultEvent(this, true);
}
public PropertyDescriptor GetDefaultProperty()
{
return null;
}
public object GetEditor(Type editorBaseType)
{
return TypeDescriptor.GetEditor(this, editorBaseType, true);
}
public EventDescriptorCollection GetEvents(Attribute[] attributes)
{
return TypeDescriptor.GetEvents(this, attributes, true);
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
ArrayList properties = new ArrayList();
foreach (var kvp in this.propertyValueDictionary)
{
properties.Add(
new DictionaryPropertyDescriptor(
kvp.Key,
this.propertyValueDictionary,
this.propertyAttributeDictionary));
}
PropertyDescriptor[] props = (PropertyDescriptor[])properties.ToArray(typeof(PropertyDescriptor));
return new PropertyDescriptorCollection(props);
}
public object GetPropertyOwner(PropertyDescriptor pd)
{
return this;
}
EventDescriptorCollection ICustomTypeDescriptor.GetEvents()
{
return TypeDescriptor.GetEvents(this, true);
}
PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties()
{
return ((ICustomTypeDescriptor)this).GetProperties(new Attribute[0]);
}
//[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public class PropertyAttributes
{
public string Category { get; set; }
public string Description { get; set; }
public string DisplayName { get; set; }
public bool IsReadOnly { get; set; }
}
internal class DictionaryPropertyDescriptor : PropertyDescriptor
{
#region Fields
private readonly IDictionary<TKey, PropertyAttributes> attributeDictionary;
private readonly TKey key;
private readonly IDictionary<TKey, TValue> valueDictionary;
#endregion
#region Constructors and Destructors
internal DictionaryPropertyDescriptor(
TKey key,
IDictionary<TKey, TValue> valueDictionary,
IDictionary<TKey, PropertyAttributes> attributeDictionary = null)
: base(key.ToString(), null)
{
this.valueDictionary = valueDictionary;
this.attributeDictionary = attributeDictionary;
this.key = key;
}
#endregion
public override string Category => this.attributeDictionary?[this.key].Category ?? base.Category;
public override Type ComponentType => null;
public override string Description => this.attributeDictionary?[this.key].Description ?? base.Description;
public override string DisplayName => this.attributeDictionary?[this.key].DisplayName ?? base.DisplayName;
public override bool IsReadOnly => this.attributeDictionary?[this.key].IsReadOnly ?? false;
public override Type PropertyType => this.valueDictionary[this.key].GetType();
public override bool CanResetValue(object component)
{
return false;
}
public override object GetValue(object component)
{
return this.valueDictionary[this.key];
}
public override void ResetValue(object component)
{
}
public override void SetValue(object component, object value)
{
this.valueDictionary[this.key] = (TValue)value;
}
public override bool ShouldSerializeValue(object component)
{
return false;
}
}
}
對於viewmodel
class classViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private IDictionary<string, object> Variables { get; set; } = new ConcurrentDictionary<string, object>();
private DictionaryPropertyGridAdapter<string, object> _selectedObj;
public DictionaryPropertyGridAdapter<string, object> SelectedObj
{
get
{
this.Variables["Bool"] = false;
this.Variables["Int"] = 200;
this.Variables["Float"] = 200.5;
this.Variables["String"] = "help";
_selectedObj = new DictionaryPropertyGridAdapter<string, object>(this.Variables);
return _selectedObj;
}
set {
_selectedObj = value;
OnPropertyChanged(nameof(this.SelectedObj));
}
}
}
和xaml
<Window x:Class="testPropertyGrid.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:testPropertyGrid"
xmlns:wpftoolkit="http://schemas.xceed.com/wpf/xaml/toolkit"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:classViewModel x:Key="ViewModel"/>
</Window.Resources>
<Grid>
<wpftoolkit:PropertyGrid Name="propertyGrid1" SelectedObject="{Binding SelectedObj ,Source={StaticResource ViewModel}}">
</wpftoolkit:PropertyGrid>
</Grid>
我相信這個鏈接將為您提供體面的輸入來解決您的問題。 Hpe它有幫助。
編輯以包含鏈接的內容:
動態屬性聲明:
dynamic employee = new BusinessObject();
employee.FirstName = "John";
employee.LastName = "Doe";
支持動態屬性的類:
public class BusinessObject : DynamicObject
{
private readonly IDictionary<string, object> dynamicProperties =
new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var memberName = binder.Name;
return dynamicProperties.TryGetValue(memberName, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
var memberName = binder.Name;
dynamicProperties[memberName] = value;
return true;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.