当所选对象具有不同的属性值时,是否可以自定义属性的显示值?
网格的默认行为是在所有选定对象具有相同值时显示值,但只是在字段不同时将其清空。无法知道 他们的差异。
例如,给定以下类和代码,是否可以将检查器和类配置为显示如下内容(整数值的范围,其他任何值的多个)
TestLong|[50 - 60]
TestInt|10
TestEnum|[Multiple]
即如果值不同显示某些内容表明它们有何不同,但是如果它们都相同则显示该值?
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
},
}
...
答案 0 :(得分:1)
我认为你不能改变显示,因为PropertyGrid一般使用TypeConverters(包括隐式的)来显示值,但是对于多次选择,它不会被使用。
虽然你可以做什么,但这并不是答案,当网格处于多选模式时提出自定义UITypeEditor,如下所示:
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;
}
}
答案 1 :(得分:1)
我已经解决了这个问题,虽然不像我原先的意图那样。
问题的根本原因是当存在多个选定对象时未应用TypeConverters。为了解决这个问题,我引入了一个聚合类,它对各个对象进行聚合,但是作为单个对象呈现。这样,可以调用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 }
});