10

I found this code snippet for INotifyPropertyChanged

But it shows the code like this :

INotifyPropertyChanged

I would have this :

  1. for public : capital letter for the first letter + ...

  2. for private : underscore + small letter for the first letter + ...

How can I achieve this ?

Edit : Without having to type the public and the private fields

<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>notifyMethod</ID>
            <ToolTip>name of method to raise PropertyChanged event</ToolTip>
            <Default>NotifyPropertyChanged</Default>
        </Literal>
    </Declarations>
    <Code Language="csharp">
        <![CDATA[private $type$ _$property$;
            public $type$ $property$
            {
                get { return _$property$;}
                set 
                { 
                    if (value != _$property$)
                    {
                        _$property$ = value;
                        $notifyMethod$("$property$");
                    }
                }
            }
        $end$]]>
    </Code>
</Snippet>
Xaruth
  • 4,034
  • 3
  • 19
  • 26
Wassim AZIRAR
  • 10,823
  • 38
  • 121
  • 174
  • is this the same as this: http://code.msdn.microsoft.com/wpapps/WPF-INotifyPropertyChanged-8b63ad72? – NoviceProgrammer Oct 22 '13 at 09:51
  • Nope, this one : http://geekswithblogs.net/brians/archive/2010/07/27/inotifypropertychanged-with-less-typing-using-a-code-snippet.aspx – Wassim AZIRAR Oct 22 '13 at 09:52
  • 3
    http://stackoverflow.com/questions/164645/formatting-literal-parameters-of-a-c-sharp-code-snippet/164729#164729 – NoviceProgrammer Oct 22 '13 at 10:16
  • Related: We are using [PropertyChanged.Fody](http://www.nuget.org/packages/PropertyChanged.Fody/). It allows you to use auto properties with `INotifyPropertyChanged` which massively reduces the amount of code needed. – Carsten Nov 07 '13 at 14:43
  • 1
    @Aschratt hehe , just suggested Fody on a different answer :) – Noctis Nov 11 '13 at 13:08
  • @WassimAZIRAR I know this is an old question, and you may have long found an answer that is sufficient for your use case. However, my answer does provide the necessary modifications to your snippet that easily fulfills all of your requirements. – RLH Aug 19 '16 at 15:04

5 Answers5

16

snippets can be written in xml and can be made for any language in vs

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>Notify Property Changed Method</Title>
    <Author>Akash</Author>
    <Shortcut>npcm</Shortcut>
    <Description>This method implements the OnPropertyChanged method and binds to the event handler</Description>
    <SnippetTypes>
      <SnippetType>SurroundsWith</SnippetType>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>

    <Code Language="CSharp">
      <![CDATA[#region Notify Property Changed Members
  public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if(handler!=null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }    
        #endregion]]>
    </Code>
  </Snippet>
</CodeSnippet>

this is the code to automatically generate the notify property changed method . all you need to do is to save this in a single file with the extension as snippet in your Documents/VisulaStudio(YourVersion)/Code Snippets/Visual C#/

that's it you are ready to use it ...

Now,observe the code snippet there is shortcut tag .. this tag references the tag that you should use in vs while writing to activate the snippet ..

here is the code for the property itself:

<?xml version="1.0" encoding="utf-8"?>
<CodeSnippet Format="1.0.0" xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <Header>
    <Title>Notifiable Property</Title>
    <Author>Akash</Author>
    <Shortcut>nprop</Shortcut>
    <Description>Property With in Built Property Changed method implementation.</Description>
    <SnippetTypes>
      <SnippetType>SurroundsWith</SnippetType>
      <SnippetType>Expansion</SnippetType>
    </SnippetTypes>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>Type</ID>
        <Default>string</Default>
      </Literal>
      <Literal>
        <ID>Property</ID>
        <Default>PlaceHolder</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp">
      <![CDATA[private $Type$ _$Property$;
        public $Type$ $Property$
        {
            get { return _$Property$; }
            set { 
               if(value!=null || value != _$Property$) _$Property$ = value;
               OnPropertyChanged("$Property$");
            }
        }]]>
    </Code>
  </Snippet>
</CodeSnippet>

in this particular snippet all you need to do is type nprop and press tab tab it generates the requied code .. you only need to enter the datatype and the name .. the rest is taken care of by the snippet itself ...

Though this i a better solution and greatly improves the coding speed, this is suitable for small projects only the viewmodelbase method is suitable for larger projects.

Akash Gutha
  • 601
  • 8
  • 21
  • 4
    Years later but definitely the best answer. No need for Resharper – Carol Jun 22 '15 at 16:40
  • null checks should only be done for reference types. – Cogent Nov 24 '16 at 10:41
  • @Cogent @Akash_Chowdary I updated it to use `default($Type$)` instead of `null` – dx_over_dt Feb 19 '18 at 03:39
  • 1
    Still, the field will start with capital letter. I think the author (and me too) would want the field with camelCase. In that scenario you are setting the field to have the CamelCase the same as the property just putting an _ before. – Luishg Jan 31 '19 at 22:13
7

I don't think this can be done with native code snippets feature provided by Visual Studio.

Personally I use Resharper which makes it possible. It can turn code I write like

public string Name { get; set; }

into

private string _name;
public string Name
{
    get { return _name; }
    set
    {
        if(value == _name)
            return;
        _name = value;
        OnPropertyChanged("Name");
    }
}

It even generates the OnPropertyChanged() method for you.

Gildor
  • 2,484
  • 23
  • 35
  • I have Resharper, but how you do that ? – Wassim AZIRAR Nov 13 '13 at 17:03
  • 2
    @Schneider This feature was introduced in Resharper 7. Just put your cursor on a property of a class which implements `INotifyPropertyChanged`, you should see the context action menu. See [here](http://blogs.jetbrains.com/dotnet/2012/07/inotifypropertychanged-support-in-resharper-7/) for details. – Gildor Nov 14 '13 at 04:01
  • I considered your answer, because it's the closest one to my question – Wassim AZIRAR Nov 14 '13 at 08:45
  • @Schneider Thanks! BTW Resharper can also generate the code using `[CallerMemberName]` for .NET 4.5 projects, which I don't think quite necessary since Resharper helps rename the string when you rename the property. – Gildor Nov 15 '13 at 01:10
  • for some reason, my Resharper doesn't catch that. My class derives from class that implements INPC. Version is 8.2.0.2160 – Alex Sorokoletov Oct 07 '14 at 01:55
  • This is **NOT** the answer to this question. no need for Resharper. **See the answer below from Akash for the solution**: http://stackoverflow.com/a/30919919/953684 – Sharky Sep 09 '15 at 07:28
  • @AlexSorokoletov, same for me. My resharper (8.2) also doesn't seem to catch that. Were you able to resolve the issue? – publicgk Feb 16 '16 at 05:03
  • @AlexSorokoletov - Annotate the method which implements the property change, [Annotations.NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){... } – shr May 25 '16 at 05:52
  • @publicgk - Annotate the method which implements the property change, [Annotations.NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null){... } – shr May 25 '16 at 06:31
4

It's surprising to me that the following suggestion hasn't been made. I took your initial snippet (from the originating author's page) and made the following modifications. You should be able to copy-and-paste this into your own snippet file.

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
    <CodeSnippet Format="1.0.0">
        <Header>
            <Title>propn</Title>
            <Shortcut>propn</Shortcut>
            <Description>Code snippet for property and backing field in class implementing INotifyPropertyChanged</Description>
            <Author>Brian Schroer, Modified by RLH</Author>
            <SnippetTypes>
                <SnippetType>Expansion</SnippetType>
            </SnippetTypes>
        </Header>
        <Snippet>
            <Declarations>
                <Literal>
                    <ID>type</ID>
                    <ToolTip>Property Type</ToolTip>
                    <Default>int</Default>
                </Literal>
                <Literal>
                    <ID>variable</ID>
                    <ToolTip>Underlying Variable</ToolTip>
                    <Default>_myProperty</Default>
                </Literal>
                <Literal>
                    <ID>property</ID>
                    <ToolTip>Property name</ToolTip>
                    <Default>MyProperty</Default>
                </Literal>
        <Literal>
          <ID>notifyMethod</ID>
          <ToolTip>name of method to raise PropertyChanged event</ToolTip>
          <Default>NotifyPropertyChanged</Default>
        </Literal>
      </Declarations>
            <Code Language="csharp"><![CDATA[private $type$ $variable$;
    public $type$ $property$
    {
        get { return $variable$;}
        set 
    { 
        if (value != $variable$)
        {
            $variable$ = value;
            PropertyChanged(this, new PropertyChangedEventArgs("$property$"));
        }
    }
    }
    $end$]]>
            </Code>
        </Snippet>
    </CodeSnippet>
</CodeSnippets>

What's Changed

First, I added a new literal variable. This creates a new, updatable item that you can tab from within the snippet. The variable name is defaulted to _propertyName which, as you can see, is a lowercase name. Note, unlike the original snippet, the underscore was being hardcoded before the PropertyName literal. In my code, I've split out the variable name from the property name.

I chose not to hardcode the underscore in my snippet so that if others use this code, they are at liberty to choose a different style of variable name. However, by way of the default, I am hinting at using the underscore.

If you want to force the underscore, then change the default variable value to propertyName. Then, everywhere variable is referenced, place the _ character before the reference.

RLH
  • 15,230
  • 22
  • 98
  • 182
2

Unfortunately, this is not possible using code snippets.

What you require would have to transform $property$ or some other literal. Even if you split the property name into 2 parts (first letter and the rest), you would have to make the letter upper case (or the other way - lower case).

Snippets offer only very limited number of transformation functions - precisely 3 for C# and not one of them can give the required result. See Code Snippet Functions on MSDN. This is true for all versions of Visual Studio up to 2013.

Szymon
  • 42,577
  • 16
  • 96
  • 114
1

I'm going to give you the answer you don't want to hear: You shouldn't need to do this at all. Your model should have the (full or auto) properties, and then your ViewModel properties should just have a getter and a setter that returns _model.MyProperty.

Also, you may want to look into CallerMemberName to get rid of that pesky magic string. I'll post some examples if you want me to.


For example, I have a DealsUser model class (note how internal logic like generating the email address if it was never explicitly set, is done here):

public class DealsUser : IDealsUser
{
    public DealsUser() : this("GUEST")
    {
    }

    public DealsUser(string username)
    {
        this.Username = username;
        this.IsAdministrator = false;
        this.IsPlanModerator = false;
        this.IsPlanner = false;
    }

    public string Username { get; set; }

    public bool IsAdministrator { get; set; }

    public bool IsPlanModerator { get; set; }

    public bool IsPlanner { get; set; }

    private string _emailAddress;
    public string EmailAddress
    {
        get
        {
            return _emailAddress ?? string.Format(
                "{0}@mycompany.co.za", this.Username);
        }
        set
        {
            _emailAddress = value;
        }
    }

    public override string ToString()
    {
        return this.Username;
    }

And I have a BaseViewModel class with the following event and protected methods (note how we use CallerMemberName to eliminate magic strings):

#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    var eventHandler = this.PropertyChanged;
    if (eventHandler != null)
    {
        eventHandler(this, new PropertyChangedEventArgs(propertyName));
    }
}

protected bool SetProperty<T>(ref T storage, T value,
    [CallerMemberName] string propertyName = null)
{
    if (object.Equals(storage, value))
    {
        return false;
    }

    storage = value;
    this.OnPropertyChanged(propertyName);
    return true;
}

protected bool SetModelProperty<T>(T storage, T value, Action setter,
    [CallerMemberName] string propertyName = null)
{
    if (object.Equals(storage, value))
    {
        return false;
    }

    setter();
    this.OnPropertyChanged(propertyName);
    return true;
}

#endregion

I then inherit from BaseViewModel, I dependency inject the model into my constructor, and I try to keep my ViewModel as lean as possible. Note that I have to use SetModelProperty instead of SetProperty, because you cannot pass a property (e.g. _dealsUser.Username) into a lamba function as a reference variable. Also note that IsPlanner and IsPlanModerator contain extra logic that updates related notifying properties when they change:

public class DealsUserVM : BaseViewModel
{
    private readonly IDealsUser _dealsUser;

    public DealsUserVM()
        : this(new DealsUser())
    {
        // Empty ctor
    }

    public DealsUserVM(IDealsUser dealsUser)
    {
        _dealsUser = dealsUser;
    }

    public IDealsUser Model
    {
        get
        {
            return _dealsUser;
        }
    }

    public string Username
    {
        get { return _dealsUser.Username; }
        set
        {
            SetModelProperty(_dealsUser.Username, value,
                () => { _dealsUser.Username = value; });
        }
    }

    public bool IsAdministrator
    {
        get { return _dealsUser.IsAdministrator; }
        set
        {
            SetModelProperty(_dealsUser.IsAdministrator, value,
                () => { _dealsUser.IsAdministrator = value; });
        }
    }

    public bool IsPlanModerator
    {
        get { return _dealsUser.IsPlanModerator; }
        set
        {
            // If IsPlanModerator has changed (and was updated as a result)
            if (SetModelProperty(_dealsUser.IsPlanModerator, value,
                () => { _dealsUser.IsPlanModerator = value; }))
            {
                // If IsPlanModerator is now TRUE
                if (value)
                {
                    this.IsPlanner = true;
                }
            }
        }
    }

    public bool IsPlanner
    {
        get { return _dealsUser.IsPlanner; }
        set
        {
            // If IsPlanner has changed (and was updated as a result)
            if (SetModelProperty(_dealsUser.IsPlanner, value,
                    () => { _dealsUser.IsPlanner = value; }))
            {
                // If IsPlanner is now FALSE
                if (!value)
                {
                    this.IsPlanModerator = false;
                }
            }
        }
    }

    public string EmailAddress
    {
        get { return _dealsUser.EmailAddress; }
        set
        {
            SetModelProperty(_dealsUser.EmailAddress, value,
                () => { _dealsUser.EmailAddress = value; });
        }
    }

    public override string ToString()
    {
        return _dealsUser.ToString();
    }
}

Hope this helps :-)

Riegardt Steyn
  • 5,431
  • 2
  • 34
  • 49