C# PropertyGrid是否可以为不同的选定对象自定义显示值,而不是空白?
当选定对象具有不同的特性值时,是否可以自定义特性的显示值 网格的默认行为是,当所有选定对象具有相同的值时,显示一个值,但当它们不同时,仅将字段留空。没有办法知道他们有什么不同 例如,给定以下类和代码,是否可以将检查器和类配置为显示如下内容(整数值的范围,其他值的倍数) 也就是说,如果值不同,则表示它们之间的差异,但如果它们都相同,则表示该值C# PropertyGrid是否可以为不同的选定对象自定义显示值,而不是空白?,c#,propertygrid,C#,Propertygrid,当选定对象具有不同的特性值时,是否可以自定义特性的显示值 网格的默认行为是,当所有选定对象具有相同的值时,显示一个值,但当它们不同时,仅将字段留空。没有办法知道他们有什么不同 例如,给定以下类和代码,是否可以将检查器和类配置为显示如下内容(整数值的范围,其他值的倍数) 也就是说,如果值不同,则表示它们之间的差异,但如果它们都相同,则表示该值 public enum TestEnum { EnumVal1, EnumVal2, EnumVal3 } public clas
public enum TestEnum
{
EnumVal1,
EnumVal2,
EnumVal3
}
public class TestClass
{
public long TestLong { get; set; }
public int TestInt { get; set; }
public TestEnum TestEnum { get; set; }
}
...
control.SelectedObjects = new []
{
new TestClass
{
TestLong = 50,
TestInt = 10,
TestEnum = TestEnum.EnumVal1
},
new TestClass
{
TestLong = 60,
TestInt = 10,
TestEnum = TestEnum.EnumVal3
},
}
...
我不认为您可以更改显示,因为PropertyGrid一般使用(包括隐式的)来显示值,但是对于多个选择,不使用它 不过,您可以做的是,当网格处于多重选择模式时,提出一个自定义选项,如下所示:
public class TestClass
{
// decorate the property with a custom UITypeEditor
[Editor(typeof(MyMultiSelectionEditor), typeof(UITypeEditor))]
public long TestLong { get; set; }
public int TestInt { get; set; }
public TestEnum TestEnum { get; set; }
}
public class MyMultiSelectionEditor : UITypeEditor
{
public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{
// adapt to your need
if (!IsPropertyGridInMultiView(context))
return UITypeEditorEditStyle.None;
return UITypeEditorEditStyle.Modal;
}
public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{
if (IsPropertyGridInMultiView(context))
{
// multi view, show my custom stuff
MessageBox.Show("hello from multi selection");
}
return base.EditValue(context, provider, value);
}
// gets a PropertyGrid instance from the context, if any
private static PropertyGrid GetPropertyGrid(ITypeDescriptorContext context)
{
IServiceProvider sp = context as IServiceProvider;
if (sp == null)
return null;
Control view = sp.GetService(typeof(IWindowsFormsEditorService)) as Control;
if (view == null)
return null;
return view.Parent as PropertyGrid;
}
// determines if there is a PropertyGrid in the context, and if it's selection is multiple
private static bool IsPropertyGridInMultiView(ITypeDescriptorContext context)
{
PropertyGrid pg = GetPropertyGrid(context);
if (pg == null)
return false;
return pg.SelectedObjects != null && pg.SelectedObjects.Length > 1;
}
}
我已经解决了这个问题,虽然不是我原来打算的那样 问题的根本原因是当有多个选定对象时,没有应用TypeConverter。为了解决这个问题,我引入了一个聚合类,它对单个对象进行聚合,但作为单个对象呈现。这样,就可以调用TypeConverter 示例代码(真实生产代码的黑客版本)如下:
public interface ISupportAggregate
{
object[] Individuals { get; }
}
public class AggregateTypeConverter : TypeConverter
{
public const string MULTIPLE = @"[multiple]";
private TypeConverter mTypeConverter;
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
Initialize(context);
if (context != null && destinationType == typeof(string))
{
var aggregate = context.Instance as ISupportAggregate;
if (aggregate != null && IsDifferingItems(context.PropertyDescriptor.Name, aggregate.Individuals))
{
return MULTIPLE;
}
}
return mTypeConverter.ConvertTo(context, culture, value, destinationType);
}
public static bool IsDifferingItems(string propertyName, object[] items)
{
PropertyDescriptor itemProperty = TypeDescriptor.GetProperties(items[0].GetType())[propertyName];
return items.Select(itemProperty.GetValue).Distinct().Count() > 1;
}
private void Initialize(ITypeDescriptorContext context)
{
if (mTypeConverter == null)
mTypeConverter = TypeDescriptor.GetConverter(context.PropertyDescriptor.PropertyType);
}
#region Calling through to mTypeConverter
public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
{
Initialize(context);
return mTypeConverter.CreateInstance(context, propertyValues);
}
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetCreateInstanceSupported(context);
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
Initialize(context);
return mTypeConverter.GetProperties(context, value, attributes);
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetPropertiesSupported(context);
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetStandardValues(context);
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetStandardValuesExclusive(context);
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetStandardValuesSupported(context);
}
public override bool IsValid(ITypeDescriptorContext context, object value)
{
Initialize(context);
return mTypeConverter.IsValid(context, value);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
Initialize(context);
return mTypeConverter.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
Initialize(context);
return mTypeConverter.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
Initialize(context);
return mTypeConverter.CanConvertTo(context, destinationType);
}
#endregion
}
public class AggregateTestClass : TestClass
{
private readonly TestClass[] mObjects;
public AggregateTestClass(TestClass[] objects)
{
mObjects = objects;
}
protected override object[] GetIndividuals()
{
return mObjects;
}
}
public class TestClass : ISupportAggregate
{
[TypeConverter(typeof(AggregateTypeConverter))]
public int IntProperty { get; set; }
[TypeConverter(typeof(AggregateTypeConverter))]
public string StringProperty { get; set; }
[BrowsableAttribute(false)]
public object[] Individuals
{
get { return GetIndividuals(); }
}
virtual protected object[] GetIndividuals()
{
return new[] { this };
}
}
public class TestSupportAggregate : ISupportAggregate, TestClass
{
private readonly TestClass[] mItems;
public TestSupportAggregate(TestClass[] items)
{
mItems = items;
}
public object[] Individuals
{
get { return mItems; }
}
}
To use in code:
control.SelectedObject = new TestSupportAggregate(new[]
{
new TestClass { IntProperty = 5150 },
new TestClass { IntProperty = 1984 }
});
谢谢你,西蒙。我已经试过了,虽然它很有用,但并不是我所需要的。我想在编辑之前自定义显示值。
public interface ISupportAggregate
{
object[] Individuals { get; }
}
public class AggregateTypeConverter : TypeConverter
{
public const string MULTIPLE = @"[multiple]";
private TypeConverter mTypeConverter;
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
Initialize(context);
if (context != null && destinationType == typeof(string))
{
var aggregate = context.Instance as ISupportAggregate;
if (aggregate != null && IsDifferingItems(context.PropertyDescriptor.Name, aggregate.Individuals))
{
return MULTIPLE;
}
}
return mTypeConverter.ConvertTo(context, culture, value, destinationType);
}
public static bool IsDifferingItems(string propertyName, object[] items)
{
PropertyDescriptor itemProperty = TypeDescriptor.GetProperties(items[0].GetType())[propertyName];
return items.Select(itemProperty.GetValue).Distinct().Count() > 1;
}
private void Initialize(ITypeDescriptorContext context)
{
if (mTypeConverter == null)
mTypeConverter = TypeDescriptor.GetConverter(context.PropertyDescriptor.PropertyType);
}
#region Calling through to mTypeConverter
public override object CreateInstance(ITypeDescriptorContext context, System.Collections.IDictionary propertyValues)
{
Initialize(context);
return mTypeConverter.CreateInstance(context, propertyValues);
}
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetCreateInstanceSupported(context);
}
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes)
{
Initialize(context);
return mTypeConverter.GetProperties(context, value, attributes);
}
public override bool GetPropertiesSupported(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetPropertiesSupported(context);
}
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetStandardValues(context);
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetStandardValuesExclusive(context);
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
Initialize(context);
return mTypeConverter.GetStandardValuesSupported(context);
}
public override bool IsValid(ITypeDescriptorContext context, object value)
{
Initialize(context);
return mTypeConverter.IsValid(context, value);
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
Initialize(context);
return mTypeConverter.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
Initialize(context);
return mTypeConverter.ConvertFrom(context, culture, value);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
Initialize(context);
return mTypeConverter.CanConvertTo(context, destinationType);
}
#endregion
}
public class AggregateTestClass : TestClass
{
private readonly TestClass[] mObjects;
public AggregateTestClass(TestClass[] objects)
{
mObjects = objects;
}
protected override object[] GetIndividuals()
{
return mObjects;
}
}
public class TestClass : ISupportAggregate
{
[TypeConverter(typeof(AggregateTypeConverter))]
public int IntProperty { get; set; }
[TypeConverter(typeof(AggregateTypeConverter))]
public string StringProperty { get; set; }
[BrowsableAttribute(false)]
public object[] Individuals
{
get { return GetIndividuals(); }
}
virtual protected object[] GetIndividuals()
{
return new[] { this };
}
}
public class TestSupportAggregate : ISupportAggregate, TestClass
{
private readonly TestClass[] mItems;
public TestSupportAggregate(TestClass[] items)
{
mItems = items;
}
public object[] Individuals
{
get { return mItems; }
}
}
To use in code:
control.SelectedObject = new TestSupportAggregate(new[]
{
new TestClass { IntProperty = 5150 },
new TestClass { IntProperty = 1984 }
});