James Fassett
James Fassett

Reputation: 41054

Quickly expose class properties as bindable

I have a class that I am binding to my view model. It is basically a struct full of displayable strings for the UI:

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

Basically the DisplayVO wraps a bunch of properties that are bound to the UI. This works until one portion of the UI modifies a property (e.g. the user can edit the Description) so I want to update the UI with the new modifications.

So what I would normally do is implement the INotifyPropertyChanged interface and override each set method to broadcast PropertyChanged(this, new PropertyChangedEventArgs(info));

I'm feeling lazy - is there a way to have this done for all members of the class? In Flex I could do:

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

and magically all of the properties of DisplayVO would be wrapped to automatically broadcast changes without me having to write all of the boilerplate. Is there an equivalent for C# and WPF?

Upvotes: 2

Views: 190

Answers (3)

Caleb Vear
Caleb Vear

Reputation: 2647

You should check out NotifyPropertyWeaver http://github.com/SimonCropp/NotifyPropertyWeaver it runs a post build task which does exactly what you are after.

Upvotes: 2

Gayot Fow
Gayot Fow

Reputation: 8802

I use a Property Declaration snippet that calls OnPropertyChanged. It also populates some Attributes from the System.ComponentModel name space...

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

This snippet also uses the DebuggerStepThroughAttribute so that the debugger will not enter the getter and setter, but this should be removed if you don't want that effect...

<?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>

The Description Attribute is meant to be extracted and used for ToolTip text, but it can also provide some documentation value.

This snippet assumes that your base view model class has a method like this...

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

Upvotes: 1

saus
saus

Reputation: 2174

you could write a snippet that fills in the boilerplate. Here's one that I use ( I have a method, OnPropertyChanged() that broadcasts the event:

<?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>

then all you need to do is type obsprop TAB TAB {type} TAB TAB {propertyName} ENTER.

Upvotes: 1

Related Questions