Frage

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>
War es hilfreich?

Lösung 2

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.

Andere Tipps

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.

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.

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.

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 :-)

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top