如何为非泛型集合的项指定设计时类型?
嘿,我懂你现在的麻烦——运行时所有功能都正常,但设计时就是没法让ReSharper正确识别非泛型集合的绑定,没法用上它的重构工具和无效绑定警告对吧?非泛型IList因为没有明确的元素类型,ReSharper和VS设计器没法自动推断集合内元素的属性,所以才会出现这个设计时的问题。下面给你几个实用的解决方案,完全不会影响运行时逻辑:
方案1:给自定义非泛型集合添加强类型辅助属性
在你的MyList类里加一个返回泛型IEnumerable<T>的只读属性,专门给设计时工具提供类型信息:
public class MyList : IList { // 你的IList实现代码... // 设计时用的强类型集合视图,运行时也兼容 public IEnumerable<MyClass> TypedItems { get { foreach (var item in this) { if (item is MyClass typedItem) yield return typedItem; } } } }
然后在XAML的设计时绑定里,你可以直接用这个TypedItems属性:
<!-- 假设你的DataContext是MyClass实例 --> <ItemsControl ItemsSource="{Binding TypedItems}"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" /> <!-- ReSharper现在能识别Name属性,提供绑定警告和重构支持 --> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
运行时你依然可以用原来的非泛型集合属性,或者直接用TypedItems——因为它只是包装了原有集合的元素,逻辑完全一致。
方案2:创建设计时专用的视图模型包装类
如果不想修改原集合类,可以专门写一个设计时用的视图模型,把非泛型集合转换成泛型:
public class MyClassDesignVm { // 实例化你的业务类 public MyClass BusinessModel { get; } = new MyClass(); // 设计时用的泛型集合,转换自非泛型的MyList public List<MyClass> DesignTimeItems => BusinessModel.Items.Cast<MyClass>().ToList(); }
然后在XAML里指定设计时DataContext:
<UserControl xmlns:d="http://schemas.microsoft.com/expression/blend/2008" d:DataContext="{d:DesignInstance Type=local:MyClassDesignVm, IsDesignTimeCreatable=True}"> <ItemsControl ItemsSource="{Binding DesignTimeItems}"> <ItemsControl.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding Name}" /> <!-- ReSharper完美识别属性 --> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </UserControl>
这个方法的好处是完全不改动业务代码,只在设计时用包装类提供类型信息,运行时XAML会自动使用真实的DataContext,完全无影响。
方案3:用TypeDescriptionProvider给集合添加类型元数据
这个方法更底层,能让ReSharper和VS设计器直接把你的非泛型MyList识别为MyClass的集合,不需要修改绑定代码:
using System.ComponentModel; // 自定义类型描述提供器,指定集合元素类型 public class MyListTypeProvider : TypeDescriptionProvider { public MyListTypeProvider() : base(TypeDescriptor.GetProvider(typeof(MyList))) { } public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) { var baseDescriptor = base.GetTypeDescriptor(objectType, instance); return new MyListTypeDescriptor(baseDescriptor); } } public class MyListTypeDescriptor : CustomTypeDescriptor { public MyListTypeDescriptor(ICustomTypeDescriptor parent) : base(parent) { } public override PropertyDescriptorCollection GetProperties() { var baseProps = base.GetProperties(); // 添加一个强类型的集合属性,让设计器识别元素类型 var typedProp = TypeDescriptor.CreateProperty( typeof(MyList), "TypedItems", typeof(IEnumerable<MyClass>), new BrowsableAttribute(true)); return new PropertyDescriptorCollection( baseProps.Cast<PropertyDescriptor>().Append(typedProp).ToArray()); } } // 在MyList上应用这个类型描述器 [TypeDescriptionProvider(typeof(MyListTypeProvider))] public class MyList : IList { // 你的IList实现代码... }
这样设置后,ReSharper会自动识别MyList包含MyClass元素,直接绑定原来的集合属性就能得到正确的绑定提示和重构支持。
这些方法的核心都是给ReSharper提供明确的元素类型信息——因为非泛型IList本身没有类型参数,工具没法自动推断元素类型,只要补上这个信息,就能正常使用ReSharper的所有绑定相关功能了。
内容的提问来源于stack exchange,提问作者stevenJ

