如何在编写Bindings时提供Visual Studio XAML Designer使用的自定义属性名称列表?

时间:2014-03-27 09:39:03

标签: .net wpf visual-studio xaml intellisense

我有一个名为Model<T>的类,它实现IDynamicObjectProvider并包装类型为T的对象,转发对基础值的属性访问,同时添加额外的东西(例如{ {1}}实现Model<T>,而INotifyPropertyChanged则不实现。

我在WPF中使用这些T个对象作为Model<T>的属性,基本上是:

DataContext
public class Person { public string Name { get; set; } }

public class EditPersonViewModel {
    public Model<Person> Person { get; set; }
    public ICommand SavePersonCommand { get; set; }
}

WPF绑定引擎成功绑定到<StackPanel d:DataContext="{d:DesignInstance vm:EditPersonViewModel}"> <TextBox Text="{Binding Person.Name}" /> <Button Command="{Binding SavePersonCommand}" /> </StackPanel> 动态getter和setter。

现在,当我编写一个以Model<Person>开头的绑定时,我希望从XAML设计器中Person类型的属性中自动完成,其方式需要的应用程序代码尽可能少。可能;理想情况下,它可以完全由定义Person.的库的提供者实现。 (我是编写库的人,我希望我的客户能够尽可能少地使用Model<T>类。)

以下是我知道的方法,以及我对他们的反对意见:

  1. 定义一个新类Model<T>,它将镜像所有EditPersonViewModelDesign属性,并将其用作设计实例。

    EditPersonViewModel
    public class EditPersonViewModelDesign {
        public Person Person { get; set; }
        public ICommand SavePersonCommand { get; set; }
    }
    

    虽然这不需要过多的代码,但是这个类仍然会在运行时保留在库中,除非我要求人们使构建复杂化(他们是否只添加了这些类的项目,或者他们添加了构建变量)与我完全不相容。此外,Design和View模型类更容易分开。

  2. 优化内部元素的数据上下文并影响新的设计实例,例如:

    <StackPanel d:DataContext="{d:DesignInstance vm:EditPersonViewModelDesign}">
        <TextBox Text="{Binding Person.Name}" />
        <Button Command="{Binding SavePersonCommand}" /> 
    </StackPanel>
    

    虽然该解决方案不需要创建新类型,但添加的XAML代码对我来说非常具有侵略性。

1 个答案:

答案 0 :(得分:3)

我不认为这里确实存在令人满意的解决方案,因为唯一真正的“非解决方法”是IntelliSense对动态绑定目标的本机支持(即{{1}上的GetDynamicMemberNames调用由DynamicMetaObject的设计实例的GetMetaObject()返回。所以,我首先建议feature request

如果我是您的客户,我不会为了智能感知支持而在任何地方花费定义设计时间绑定。它需要更多思考来指定正确的绑定,而不是记住或查找并键入属性名称。

这是一个可能有效的想法。当然,我还没有对它进行测试,但通过一些研究,它可能会让你在那里。你似乎在知道,你在做什么:

查看Model<T>中静态DesignerProperties类的IsInDesignTool属性:

System.ComponentModel

可以在ViewModel中实现一种DesignerProperties.IsInDesignTool 方法here。这可能是一种返回内部模型(类型为T)的方法,而不是包装模型(Model)。不确定它是否能让你随处可见,但是考虑它可能是值得的。无论如何,这是一个有趣的特征......

最后的想法:通过发送代码片段来改善用户体验,并想出一种区分设计时绑定和运行时绑定的直观方法。也许是这样的:

if DesignMode do this, else do that

创建

的代码段
public abstract class ViewModelBase<T>
{
    public Model<T> Model { get; }

    // Maybe use compiler directives to throw exception if requested at runtime
    public T DesignModel { get; }
}

不知道,VS代码片段有多强大,因为我正在使用ReSharper,但是使用ReSharper,您可以使控件的DP变为d:Text="{Binding DesignModel.Name}" Text="{Binding Model.Name}" ,属性名称为变量{{1 }}。然后,IntelliSense将处理设计时绑定,并且如果您按Enter键,则会自动将属性名称复制到第二个绑定。

您可以输入一些快捷方式$ControlProp$,然后输入$PropName$,输入,pbind,这将触发IntelliSense,选择Text,输入。完成。至少很容易。

底线:我没有对你的问题的即插即用答案,但我的观点可能对某些灵感有益......至少我希望如此。