In C#, code snippets (e.g., prop, ctor) auto-generate boilerplate code via double-pressing the Tab key. To view all snippets, navigate to VS → Tools → Code Snippet Manager → CSharp → VisualC#.
The following XML defines a custom propn snippet for generatnig properties with backing fields and property change notifications:
<?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 a property with a backing field and property change notification</Description>
<Author>Microsoft Corporation</Author>
<SnippetTypes>
<SnippetType>Expansion</SnippetType>
</SnippetTypes>
</Header>
<Snippet>
<Declarations>
<Literal>
<ID>type</ID>
<ToolTip>Property type</ToolTip>
<Default>int</Default>
</Literal>
<Literal>
<ID>propName</ID>
<ToolTip>Property name</ToolTip>
<Default>MyProperty</Default>
</Literal>
<Literal>
<ID>backingField</ID>
<ToolTip>Backing field for the property</ToolTip>
<Default>_myField</Default>
</Literal>
</Declarations>
<Code Language="csharp">
<![CDATA[private $type$ $backingField$;
public $type$ $propName$
{
get => $backingField$;
set
{
$backingField$ = value;
this.RaisePropertyChanged("$propName$");
}
}
$end$]]>
</Code>
</Snippet>
</CodeSnippet>
</CodeSnippets>
# 2. Folding to Definition in Visual Studio
To fold code to its definition (including `#region` blocks), use the shortcut `Ctrl+M+O`.
# 3. UI Design Essence
A picture is worth a thousand tables; a table is worth a thousand words. (A visual representation is more effective than text or tables.)
# 4. MVVM Design Pattern Explained
## 4.1 MVVM = Model-View-ViewModel
MVVM (Model-View-ViewModel) is a design pattern that separates an application into three core components:
## 4.2 Why Use MVVM?
- **Team Level**: Standardizes the development approach (consistent patterns and practices).
- **Architecture Level**: Ensures stability and decoupling (the "orange peel principle"—layers can be modified independently).
- **Code Level**: Improves readability, testability, and replaceability.
## 4.3 Components of MVVM
- **Model**: An abstraction of real-world objects (e.g., data models, business logic).
- **View**: The user interface (UI) rendered in XAML (or other UI frameworks).
- **ViewModel**: A "Model for the View"—exposes data (via properties) and actions (via commands) to the View.
### Communication Between ViewModel and View
- **Data Transfer**: ViewModel → View via properties (e.g., `DependencyProperty` for data binding).
- **Action Transfer**: View → ViewModel via commands (similar to methods or events, but more structured).
# 5. Typical MVVM Folder Structure
Common folders in an MVVM project include:
- `Models`: For data models and business logic.
- `Views`: For UI (XAML) files.
- `ViewModels`: For ViewModel classes.
- `Services`: For shared services (e.g., data access, logging).
# 6. Simple MVVM Implementation
### `NotificationObject` (ViewModel Base Class)
```csharp
/// <summary>
/// Base class for ViewModels, implementing property change notification.
/// </summary>
class NotificationObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
DelegateCommand (ICommand Implementation)
class DelegateCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return CanExecuteFunc?.Invoke(parameter) ?? true;
}
public void Execute(object parameter)
{
ExecuteAction?.Invoke(parameter);
}
public Action<object> ExecuteAction { get; set; }
public Func<object, bool> CanExecuteFunc { get; set; }
}
MainWindowViewModel (Concrete ViewModel)
class MainWindowViewModel : NotificationObject
{
private double _input1;
public double Input1
{
get => _input1;
set
{
_input1 = value;
RaisePropertyChanged(nameof(Input1));
}
}
private double _input2;
public double Input2
{
get => _input2;
set
{
_input2 = value;
RaisePropertyChanged(nameof(Input2));
}
}
private double _result;
public double Result
{
get => _result;
set
{
_result = value;
RaisePropertyChanged(nameof(Result));
}
}
public DelegateCommand AddCommand { get; }
public DelegateCommand SaveCommand { get; }
private void Add(object _) => Result = Input1 + Input2;
private void Save(object _)
{
var dialog = new SaveFileDialog();
dialog.ShowDialog();
}
public MainWindowViewModel()
{
AddCommand = new DelegateCommand { ExecuteAction = Add };
SaveCommand = new DelegateCommand { ExecuteAction = Save };
}
}
MainWindow (XAML View)
<Window x:Class="SimpleMvvmDemo.MainWindow"
xmlns="http://schemas.mircosoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SimpleMvvmDemo"
mc:Ignorable="d"
Title="MVVM Demo" Height="350" Width="350">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Button Content="Save" Grid.Row="0" Command="{Binding SaveCommand}"/>
<TextBox Grid.Row="1" Text="{Binding Input1}" Margin="10" Background="AliceBlue"
TextAlignment="Center" FontSize="24"/>
<TextBox Grid.Row="2" Text="{Binding Input2}" Margin="10" Background="AliceBlue"
TextAlignment="Center" FontSize="24"/>
<TextBox Grid.Row="3" Text="{Binding Result}" Margin="10" Background="AliceBlue"
TextAlignment="Center" FontSize="24"/>
<Button Content="Add" Grid.Row="4" Margin="10" Command="{Binding AddCommand}"/>
</Grid>
</Window>
Code-Behind (MainWindow.xaml.cs)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainWindowViewModel();
}
}