## MVVM
![MVVM](../Pictures/05_01.%20MVVM.png)  
Базовая реализация:  
![Базовая реализация](../Pictures/05_02.%20Базовая%20реализация%20MVVM.png)  
## INotifyPropertyChanged
```cs
public class BindableBase : INotifyPropertyChanged
	{
		public event PropertyChangedEventHandler PropertyChanged;
		
		private string _sampleProperty1;
		public string SampleProperty1
		{
			get => _sampleProperty1;
			set
			{
				_sampleProperty1 = value;
				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SampleProperty1"));
			}
		}
		private int _sampleProperty2;
		public int SampleProperty2
		{
			get => _sampleProperty2;
			set
			{
				_sampleProperty2 = value;
				PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("_sampleProperty2"));
			}
		}
	}
```
  
```cs
public class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    void RaisePropertyChanged(string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    private string _sampleProperty1;
    public string SampleProperty1
    {
        get => _sampleProperty1;
        set
        {
            if (Equals(_sampleProperty1, value)) return;
            _sampleProperty1 = value;
            RaisePropertyChanged(nameof(SampleProperty1));
        }
    }
    private int _sampleProperty2;
    public int SampleProperty2
    {
        get => _sampleProperty2;
        set
        {
            if (Equals(_sampleProperty2, value)) return;
            _sampleProperty2 = value;
            RaisePropertyChanged(nameof(SampleProperty2));
        }
    }
}
```
  
```cs
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class BindableBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    private string _sampleProperty1;
    public string SampleProperty1
    {
        get => _sampleProperty1;
        set
        {
            if (Equals(_sampleProperty1, value)) return;
            _sampleProperty1 = value;
            RaisePropertyChanged();
        }
    }
    private int _sampleProperty2;
    public int SampleProperty2
    {
        get => _sampleProperty2;
        set
        {
            if (Equals(_sampleProperty2, value)) return;
            _sampleProperty2 = value;
            RaisePropertyChanged();
        }
    }
}
```
  
```cs
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class BindableBase : INotifyPropertyChanged
{
    /// <summary>
    ///     Multicast event for property change notifications.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;
    /// <summary>
    ///     Checks if a property already matches a desired value.  Sets the property and
    ///     notifies listeners only when necessary.
    /// </summary>
    /// <typeparam name="T">Type of the property.</typeparam>
    /// <param name="storage">Reference to a property with both getter and setter.</param>
    /// <param name="value">Desired value for the property.</param>
    /// <param name="propertyName">
    ///     Name of the property used to notify listeners.  This value is optional and can be provided automatically when invoked from compilers that support CallerMemberName.
    /// </param>
    /// <returns>
    ///     True if the value was changed, false if the existing value matched the desired value.
    /// </returns>
    public bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
    {
        if (Equals(storage, value)) return false;
        storage = value;
        RaisePropertyChanged(propertyName);
        return true;
    }
    [NotifyPropertyChangedInvocator]
    protected virtual void RaisePropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
```
  
```cs
public class Bindable : BindableBase
{
    private string _sampleProperty1;
    public string SampleProperty1
    {
        get => _sampleProperty1;
        set => SetProperty(ref _sampleProperty1, value);
    }
    
    private int _sampleProperty2;
    public int SampleProperty2
    {
        get => _sampleProperty2;
        set => SetProperty(ref _sampleProperty2, value);
    }
}
```
![MVVM](../Pictures/05_03.%20MVVM.png)  
## PRISM
![PRISM](../Pictures/05_04.%20PRISM.png)  
## WPF NET CORE
XAML → CODE BEHIND → DICTIONARY → USER CONTROL→ CUSTOM CONTROL
## XAML
```xml
<Window x:Class="DataMiner.View.StartView"
	xmlns="http://schemas.microsoft.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:designViewModel="clr-namespace:DataMiner.DesignViewModel"
	xmlns:view="clr-namespace:DataMiner.View"
	xmlns:userControls="clr-namespace:DT.DataMiner.FlowChart.UserControls;assembly=DT.DataMiner.FlowChart"
	xmlns:controls1="clr-namespace:DT.DataMiner.FlowChart.Controls;assembly=DT.DataMiner.FlowChart"
	mc:Ignorable="d"
	Icon="../Resources/Images/magnet.png" MinHeight="300" MinWidth="600"
	Style="{StaticResource WindowStyle}"
	FontFamily="{StaticResource LatoRegular}"
	Title="DATA MINER V.0.1"  Height="450" Width="1200"
	d:DataContext="{x:Static designViewModel:DesignStartViewModel.Instance}">   
	<Window.InputBindings>
		<KeyBinding Key="Delete" Command="{Binding RemoveSelectedCommand}"/>
		<KeyBinding Key="A" Modifiers="Control" Command="{Binding SelectAllItemsCommand}"/>
	</Window.InputBindings>
	<Grid>
		<Grid.RowDefinitions>
			<RowDefinition Height="Auto"/>
			<RowDefinition/>
		</Grid.RowDefinitions>
		<Grid.ColumnDefinitions>
			<ColumnDefinition Width="Auto" MinWidth="50"/>
			<ColumnDefinition Width="Auto"/>
			<ColumnDefinition/>
		</Grid.ColumnDefinitions>
		<userControls:DiagramControl Grid.Column="2" Grid.Row="1"/>
		<Grid Grid.Column="0" Grid.Row="1">
		<StackPanel>
			<view:ToolBoxControlView DataContext="{Binding OpcControlViewModel}" Width="120"/>
			<view:ToolBoxControlView DataContext="{Binding FirstControlViewModel}" Width="120"/>
			<view:ToolBoxControlView DataContext="{Binding SecondControlViewModel}" Width="120"/>
			</StackPanel>
		</Grid>
		<Separator VerticalAlignment="Stretch" Width="5" Background="Transparent" Grid.Column="1" Grid.Row="1"/>
		<controls1:BlueprintToolbar Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"/>
		</Grid>
</Window>
```
#### XAML конструктор
![XAML конструктор](../Pictures/05_05.%20XAML%20конструктор.png)  
## CODE BEHIND
```cs
using System.Windows;
namespace DataMiner.View
{
    /// <summary>
    /// Логика взаимодействия для MainWindow.xaml
    /// </summary>
    public partial class StartView : Window
    {
        public StartView()
        {
            InitializeComponent();
        }
    }
}
```
## Словари ресурсов
```xml
<ResourceDictionary  x:Class="Themes.Metro.Dark.Themes.VS2012.WindowStyle"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:converters="clr-namespace:Themes.Metro.Dark.Converters"
	xmlns:vs2012="clr-namespace:Themes.Metro.Dark.Themes.VS2012">
	<ResourceDictionary.MergedDictionaries>
		<ResourceDictionary Source="../MetroTheme/Theme.Colors.New.xaml"/>
	</ResourceDictionary.MergedDictionaries>
	<SolidColorBrush x:Key="TitleBarBackgroundBrush" Color="#FF282828" />
	<SolidColorBrush x:Key="WindowBorderBrush" Color="#007ACC" />
	<SolidColorBrush x:Key="WindowBorderBrushInactive" Color="#999999" />
	<SolidColorBrush x:Key="WindowStatusForeground" Color="#FFFFFF" />
	<SolidColorBrush x:Key="WindowStatusForegroundInactive" Color="#FFFFFF" />
…
</ResourceDictionary>
```
## UserControl
```xml
<UserControl x:Class="DataMiner.View.OpcServerView"
	xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
	xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
	xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
	xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
	xmlns:local="clr-namespace:DataMiner.View"
	mc:Ignorable="d"
	d:DesignHeight="60" d:DesignWidth="150">
	<Grid>
	</Grid>
</UserControl>
```
## CustomControl
```cs
/// <summary>
/// 
/// </summary>
public class Connector : Control
{
    #region ctor

    static Connector()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(Connector), new FrameworkPropertyMetadata(typeof(Connector)));
    }

    #endregion
}
```
## DependencyProperty
```cs
#region ConnectorOrientation DependencyProperty

/// <summary>
/// 
/// </summary>
public ConnectorOrientation ConnectorOrientation
{
    get => (ConnectorOrientation)GetValue(ConnectorOrientationProperty);
    set => SetValue(ConnectorOrientationProperty, value);
}

/// <summary>
/// 
/// </summary>
public static readonly DependencyProperty ConnectorOrientationProperty = DependencyProperty.Register(nameof(ConnectorOrientation), typeof(ConnectorOrientation), typeof(Connector));

#endregion
```
## Themes\Generic.xaml
```xml
 <!-- Connector Style -->
	<Style TargetType="{x:Type s:Connector}">
		<Setter Property="Width" Value="10" />
		<Setter Property="Height" Value="10" />
		…
		<Setter Property="Template">
			<Setter.Value>
				<ControlTemplate TargetType="{x:Type s:Connector}">
					<Grid x:Name="PART_Grid" RenderTransformOrigin="0.5 0.5">
						<!-- transparent extra space makes connector easier to hit -->
						<Rectangle Fill="Transparent" Margin="-2" />
						<Border x:Name="PART_Data" Width="10" Height="10" CornerRadius="0 5 5 0" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}"/>
						<Path x:Name="PART_Event" Fill="{TemplateBinding Background}" Stroke="{TemplateBinding BorderBrush}" StrokeThickness="{TemplateBinding BorderThickness}" Data="M0 0 H5 L10 5 L5 10 H0Z" />
			<Grid.RenderTransform>
				<RotateTransform x:Name="PART_RotateTransform" Angle="180" />
				</Grid.RenderTransform>
			</Grid>
			<ControlTemplate.Triggers>
				<DataTrigger Value="Left" Binding="{Binding Path=ConnectorOrientation, Mode=OneTime}">
					<Setter TargetName="PART_Grid" Property="RenderTransform">
						<Setter.Value><RotateTransform Angle="180" /></Setter.Value>
					</Setter>
				</DataTrigger>
				</ControlTemplate.Triggers>
			</ControlTemplate>
			</Setter.Value>
		</Setter>
	</Style>
```
