Now the problem is, if I want to show ImageCustom in both AButton and OtherControl, I had thought of doing this:[ProvideProperty("ImageCustom", typeof(AButton))][ProvideProperty("ImageCustom", typeof(OtherControl))]public class MyImageExtender : Component, IExtenderProvider但这不起作用,我只能在 AButton 上看到 ImageCustom,而在 OtherControl 上看不到.This doesn't work though, I only get to see ImageCustom on AButton, but not on OtherControl.反编译ProvidePropertyAttribute 的源代码,发生这种情况的原因可以说"很清楚.它在内部创建了一个 TypeId,我怀疑是 WinForms 设计者使用的,如下所示:Decompiling the sources for ProvidePropertyAttribute, the reason this happens is "arguably" clear. It internally creates a TypeId, which I suspect is what the WinForms designer is using like this:public override object TypeId{ get { return (object) (this.GetType().FullName + this.propertyName); }}这使得TypeId为"ProvidePropertyAttributeImageCustom",因此无法区分不同的接收器类型.Which makes the TypeId be "ProvidePropertyAttributeImageCustom", so it can't differentiate between the different receiver types.我将测试派生 ProvidePropertyAttribute 并创建一个不同的 TypeId,因为它似乎可以覆盖,但我希望 winforms 设计人员希望特定的 ProvidePropertyAttribute 类型而不是派生的类型(winforms 设计人员对这些东西很挑剔).I'm going to test deriving ProvidePropertyAttribute and create a different TypeId since it seems overridable, but I expect the winforms designer expect the specific ProvidePropertyAttribute type and not a derived one (the winforms designer is picky with these things).哎呀,ProvidePropertyAttribute 是 sealed 所以我无法派生并制作我的自定义 TypeId,这似乎(不是我寄予厚望)这会起作用)Ouch, ProvidePropertyAttribute is sealed so I can't derive and make my custom TypeId, it seems (not that I had high hopes that this would work at all)与此同时,有没有人做过这样的事情并且知道我可以使用的东西?In the meantime, anyone has ever done something like this and know something I could use?推荐答案我知道这是一个快速的答案,但这已经让我发疯了好几天,所以我走了一条似乎有效的不同路线很好.I know this is a quick answer, but this has been driving me nuts for a few days, so I've gone a different route which seems to work just fine.由于目标目标(正如我在我的问题中所解释的)是更改某些属性上的 UITypeEditor,因此我制作了一个覆盖属性的非可视组件(使用自定义 TypeDescriptor) 在这些属性上,并在那里分配我的自定义 UITypeEditor.Since the target goal (as I explained on my question) was to change the UITypeEditor on some properties, I've made a non-visual component that overrides the attributes (using a custom TypeDescriptor) on those properties, and assign my custom UITypeEditor there.我使用这个答案作为实现覆盖属性的TypeDescriptor的基础.I used this answer as a base for implementing the property-overriding TypeDescriptor.作为记录,链接答案中提供的解决方案有效,但是存在一个问题,即 TypeDescriptionProvider 会被派生类选取,但是返回的 TypeDescriptor只会返回基础对象的属性(您在父 TypeDescriptor 中传递的属性),从而导致诸如 winforms 设计器之类的东西的破坏.For the record, the solution provided in the linked answer worked, however it had a problem where the TypeDescriptionProvider would get picked up for derived classes, however the returned TypeDescriptor would only return the properties for the base object (the one for which you passed in the parent TypeDescriptor), causing havok in things like the winforms designer.我制作了一个通用的属性覆盖TypeDescriptionProvider.到目前为止,它运行得很好.这是实现.请参阅链接答案以了解其来源:I made an all purpose property-overrider TypeDescriptionProvider. So far, it has worked just fine. Here's the implementation. See the linked answer for an explanation of where did this come from:提供者:The provider:internal class PropertyOverridingTypeDescriptionProvider : TypeDescriptionProvider{ private readonly Dictionary<Type, ICustomTypeDescriptor> _descriptorCache = new Dictionary<Type, ICustomTypeDescriptor>(); private readonly Func<PropertyDescriptor, bool> _condition; private readonly Func<PropertyDescriptor, Type, PropertyDescriptor> _propertyCreator; public PropertyOverridingTypeDescriptionProvider(TypeDescriptionProvider parentProvider, Func<PropertyDescriptor, bool> condition, Func<PropertyDescriptor, Type, PropertyDescriptor> propertyCreator) : base(parentProvider) { _condition = condition; _propertyCreator = propertyCreator; } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { lock (_descriptorCache) { ICustomTypeDescriptor returnDescriptor; if (!_descriptorCache.TryGetValue(objectType, out returnDescriptor)) { returnDescriptor = CreateTypeDescriptor(objectType); } return returnDescriptor; } } private ICustomTypeDescriptor CreateTypeDescriptor(Type targetType) { var descriptor = base.GetTypeDescriptor(targetType, null); _descriptorCache.Add(targetType, descriptor); var ctd = new PropertyOverridingTypeDescriptor(descriptor, targetType, _condition, _propertyCreator); _descriptorCache[targetType] = ctd; return ctd; }}这是实际的TypeDescriptor:internal class PropertyOverridingTypeDescriptor : CustomTypeDescriptor{ private readonly ICustomTypeDescriptor _parent; private readonly PropertyDescriptorCollection _propertyCollection; private readonly Type _objectType; private readonly Func<PropertyDescriptor, bool> _condition; private readonly Func<PropertyDescriptor, Type, PropertyDescriptor> _propertyCreator; public PropertyOverridingTypeDescriptor(ICustomTypeDescriptor parent, Type objectType, Func<PropertyDescriptor, bool> condition, Func<PropertyDescriptor, Type, PropertyDescriptor> propertyCreator) : base(parent) { _parent = parent; _objectType = objectType; _condition = condition; _propertyCreator = propertyCreator; _propertyCollection = BuildPropertyCollection(); } private PropertyDescriptorCollection BuildPropertyCollection() { var isChanged = false; var parentProperties = _parent.GetProperties(); var pdl = new PropertyDescriptor[parentProperties.Count]; var index = 0; foreach (var pd in parentProperties.OfType<PropertyDescriptor>()) { var pdReplaced = pd; if (_condition(pd)) { pdReplaced = _propertyCreator(pd, _objectType); } if (!ReferenceEquals(pdReplaced, pd)) isChanged = true; pdl[index++] = pdReplaced; } return !isChanged ? parentProperties : new PropertyDescriptorCollection(pdl); } public override object GetPropertyOwner(PropertyDescriptor pd) { var o = base.GetPropertyOwner(pd); return o ?? this; } public override PropertyDescriptorCollection GetProperties() { return _propertyCollection; } public override PropertyDescriptorCollection GetProperties(Attribute[] attributes) { return _propertyCollection; }}这是你如何使用它.我已经评论过了:And here's how you use it. I've commented this:private void ChangeTypeProperties(Type modifiedType, params string[] propertyNames){ // Get the current TypeDescriptionProvider var curProvider = TypeDescriptor.GetProvider(modifiedType); // Create a replacement provider, pass in the parent, this is important var replaceProvider = new PropertyOverridingTypeDescriptionProvider(curProvider, // This the predicate that says wether a `PropertyDescriptor` should be changed // Here we are changing only the System.Drawing.Image properties, // either those whose name we pass in, or all if we pass none pd => typeof (System.Drawing.Image).IsAssignableFrom(pd.PropertyType) && (propertyNames.Length == 0 || propertyNames.Contains(pd.Name)), // This our "replacer" function. It'll get the source PropertyDescriptor and the object type. // You could use pd.ComponentType for the object type, but I've // found it to fail under some circumstances, so I just pass it // along (pd, t) => { // Get original attributes except the ones we want to change var atts = pd.Attributes.OfType<Attribute>().Where(x => x.GetType() != typeof (EditorAttribute)).ToList(); // Add our own attributes atts.Add(new EditorAttribute(typeof (MyOwnEditor), typeof (System.Drawing.Design.UITypeEditor))); // Create the new PropertyDescriptor return TypeDescriptor.CreateProperty(t, pd, atts.ToArray()); } ); // Finally we replace the TypeDescriptionProvider TypeDescriptor.AddProvider(replaceProvider, modifiedType);}现在,根据我的问题的要求,我创建了一个简单的插入式组件,将其放置在基本表单上,它的作用是:Now, for the requirements of my question, I've created a simple drop-in component which I drop on the base form, which does just this:public class ToolbarImageEditorExtender : Component{ private static bool _alreadyInitialized; public ToolbarImageEditorExtender() { // no need to reinitialize if we drop more than one component if (_alreadyInitialized) return; _alreadyInitialized = true; // the ChangeTypeProperties function above. I just made a generic version ChangeTypeProperties<OtherControl>(nameof(OtherControl.Glyph), nameof(OtherControl.LargeGlyph)); ChangeTypeProperties<AButton>(nameof(AButton.SmallImage), nameof(AButton.LargeImage)); // etc. }}到目前为止,它已经产生了奇迹.So far, it has worked wonders. 这篇关于IExtenderProvider 根据对象类型仅添加一些属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
06-18 17:59