【问题标题】:Quickly expose class properties as bindable快速将类属性公开为可绑定
【发布时间】:2012-07-20 14:24:26
【问题描述】:

我有一个绑定到我的视图模型的类。它基本上是一个充满 UI 可显示字符串的结构:

class DisplayVO
{
    public string Title { get; set; }
    public string Description { get; set; }
    // ... about a dozen more properties 
}

基本上,DisplayVO 包装了一堆绑定到 UI 的属性。这一直有效,直到 UI 的一部分修改了属性(例如,用户可以编辑 Description),所以我想用新的修改来更新 UI。

所以我通常会做的是实现INotifyPropertyChanged 接口并覆盖每个set 方法来广播PropertyChanged(this, new PropertyChangedEventArgs(info));

我感觉很懒 - 有没有办法让班级的所有成员都这样做?在 Flex 中我可以做到:

[Bindable]
public class DisplayVO
{
    private var Title:String;
    private var Description:String;
}

神奇地,DisplayVO 的所有属性都将被包装以自动广播更改,而无需我编写所有样板文件。是否有 C# 和 WPF 的等价物?

【问题讨论】:

标签: c# wpf mvvm


【解决方案1】:

您应该查看 NotifyPropertyWeaver http://github.com/SimonCropp/NotifyPropertyWeaver 它运行一个构建后任务,该任务完全符合您的要求。

【讨论】:

  • 我不一定喜欢它是后期构建,但它与我所追求的最接近,因此足以作为复选标记。实际上,我只是手动编写了样板。在初始化后实际上只有少数属性发生了变异(并且需要重新绘制 UI),所以我现在可以忍受代码膨胀。
【解决方案2】:

您可以编写一个 sn-p 来填充样板文件。这是我使用的一个(我有一个广播事件的方法 OnPropertyChanged():

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>ObservableProperty</Title>
    <Author>Scott Austen</Author>
    <Shortcut>#ObsProp</Shortcut>
    <Description>Inserts property definition with private backing field, calling RaisePropertyChanged</Description>
    <SnippetTypes>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>Type</ID>
        <Default>Type</Default>
      </Literal>
      <Literal>
        <ID>PropertyName</ID>
        <Default>P</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp">
      <![CDATA[public $Type$ $PropertyName$
      {
        get { return _$PropertyName$; }
        set
        {
          _$PropertyName$ = value;          
          OnPropertyChanged("$PropertyName$");
        }
      }

      private $Type$ _$PropertyName$;]]>
    </Code>
  </Snippet>
</CodeSnippet>

那么你需要做的就是输入obsprop TAB TAB {type} TAB TAB {propertyName} ENTER.

【讨论】:

  • 不过,这是一个非常粗制滥造的实现,即使该属性甚至可能没有像事件名称那样更改,也会触发该事件。
  • 我还没有发现这是一个问题。除了轻微的性能提升之外,检查更改还有什么好处?
  • 该事件仅在它应该时触发,按照自己的方式进行操作就像触发下载的事件,即使下载尚未完成,它在语义上是不正确的,并且可以给想要使用该活动的人带来麻烦。
  • 我明白你的意思,但我只使用 propertychanged 事件来允许绑定到 wpf 控件 - 可能发生的最坏情况是 ui 被刷新太多次。顺便说一句(尽管这不能证明我的观点)我发布的方式是微软建议为绑定实现属性更改通知的方式:msdn.microsoft.com/en-us/library/ms743695.aspx
  • 我从来没有看过那篇文章,我通常推荐that one,它会按照我的预期完成。
【解决方案3】:

我使用调用 OnPropertyChanged 的​​属性声明 sn-p。它还从 System.ComponentModel 命名空间填充一些属性...

 Description: a brief phrase about what the property does
 DisplayName: how the property should be labelled 
 DefaultValue: the initial value of the property

这个sn-p也使用了DebuggerStepThroughAttribute,这样调试器就不会进入getter和setter了,但是如果你不想要那个效果,这个应该去掉……

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>Full property declaration</Title>
            <Shortcut>propfull</Shortcut>
            <Description>Code snippet for property and backing field</Description>
            <Author>GJV</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property type</ToolTip>
                    <Default>string</Default>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>
                <Literal>
                    <ID>field</ID>
            <ToolTip>The variable backing this property</ToolTip>
                    <Default>myProperty</Default>
                </Literal>
                <Literal>
                    <ID>desc</ID>
                    <ToolTip>What the property is about</ToolTip>
                    <Default>My description...</Default>
                </Literal>
                <Literal>
                    <ID>dispname</ID>
                    <ToolTip>Column header</ToolTip>
                    <Default>DisplayName</Default>
                </Literal>
                <Literal>
                    <ID>defaultvalue</ID>
                    <ToolTip>Default value</ToolTip>
                    <Default>""</Default>
                </Literal>
            </Declarations>
            <Code Language="csharp">
        <![CDATA[private $type$ $field$;
    [Description("$desc$"), DisplayName("$dispname$"), DefaultValue($defaultvalue$)]
    public $type$ $property$
    {
            [DebuggerStepThrough]get{return $field$;}
            [DebuggerStepThrough]set
            {
                if(value!=$field$)
                {
                    $field$ = value;
                    OnPropertyChanged("$property$");
                }
            }
    }
    $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

描述属性旨在被提取并用于工具提示文本,但它也可以提供一些文档价值。

这个 sn-p 假设你的基础视图模型类有这样的方法......

protected void OnPropertyChanged(string propertyName)
{
    if(PropertyChanged!=null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多