Motor-selection tutorial project












1














I made a tutorial project to help myself better understand how to use WPF and MVVM, but there are a couple of things I'm unsure about.



This is the tutorial I was using as a reference. I deviated from it a little to make it more interesting for myself.





  1. Is it a good idea to merge MainWindowResources.xaml with MainWindow.xaml or should I merge it with App.xaml? Why or why not? I have tried both and they both run fine (granted the project is extremely basic), but I'm very suspicious about them doing the same thing.


  2. Do you have any recommendations for naming conventions? I would like to know if there are naming conventions that most people would use in the context of MVVM; I'm pretty bad with naming if you leave me to my own devices.

  3. Do you have any other general recommendations/guidelines?


Summary:



The user is supposed to be able to get a motor by its ID and then save the motor as the current motor.



Project Hierarchy:



screenshot of the solution explorer



Enums:



namespace LearningWPF.Enums
{
public enum MotorStatus
{
Off = 0,
On = 1
}
}


.



namespace LearningWPF.Enums
{
public enum RotationalDirection
{
Clockwise = -1,
CounterClockwise = 1
}
}


Models:



using LearningWPF.Enums;

namespace LearningWPF.Models
{
public class Motor : ProtoModel
{
#region Fields

private MotorStatus _status;
private int _id;
private string _motorName;
private RotationalDirection _direction;

#endregion //Fields

#region Properties

public MotorStatus Status
{
get { return _status; }

//This set method will determine if the input value is the
//same as the current value -> if they are not the same, then
//it will change the current value to the input value and
//then it will notify the event handler that its value
//has been changed.
set
{
if (value != _status)
{
_status = value;
OnPropertyChanged("Status");
}
}
}
public int ID
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
OnPropertyChanged("ID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public RotationalDirection Direction
{
get { return _direction; }
set
{
if (value != _direction)
{
_direction = value;
OnPropertyChanged("Direction");
}
}
}

#endregion //Properties

#region Constructors

public Motor(int id)
{
_status = MotorStatus.On;
_id = id;
_motorName = string.Format($"TestMotor{id}");
_direction = RotationalDirection.CounterClockwise;
}

#endregion Constructors
}
}




using System;
using System.ComponentModel;
using System.Diagnostics;

namespace LearningWPF.Models
{
//Purpose: To provide base functionality common to all models.
public abstract class ProtoModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged members

/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>

//This property is used to notify that another property has
//changed.
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName"></param>

//This method is used to initiate the PropertyChanged event.
//Whenever a property is changed for whatever reason, you will
//want the class to notify subscribers to the
//PropertyChangedEventHandler that a property on this object
//has just been changed.
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);

if (this.PropertyChanged != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(this, e);
}
}

#endregion //INotifyPropertyChanged members

#region Debugging aides

/// <summary>
/// Warns the developer if this object does not have a
/// public property with the specified name. This method does not
/// exist in a release build.
/// </summary>

//This method is used during debugging to determine if the
//class has the public property with the name passed into
//the method.
[Conditional("DEBUG")]
[DebuggerStepThrough]
public virtual void VerifyPropertyName(string propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = String.Format($"Invalid property name: {propertyName}");

if (this.ThrowOnInvalidPropertyName)
{
throw new Exception(msg);
}
else
{
Debug.Fail(msg);
}
}
}

/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail()
/// when an invalid property name is passed to the VerifyPropertyName
/// method. The default value is false, but subclasses used by unit
/// tests override this property's getter to return true.
/// </summary>

//This is basically used only for unit testing so that an
//exception is thrown instead of a Debug.Fail().
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

#endregion //Debugging aides
}
}


ViewModels:



using LearningWPF.Models;
using System.Windows.Input;
using System.Windows;

namespace LearningWPF.ViewModels
{
public class MotorViewModel : ProtoModel
{
#region Fields

private int _motorId;
private string _motorName;
private Motor _currentMotor;
private ICommand _getMotorCommand;
private ICommand _saveMotorCommand;

#endregion //Fields

#region Properties

public int MotorID
{
get { return _motorId; }
set
{
if (value != _motorId)
{
_motorId = value;
OnPropertyChanged("MotorID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public Motor CurrentMotor
{
get { return _currentMotor; }
set
{
if (value != _currentMotor)
{
_currentMotor = value;
OnPropertyChanged("CurrentMotor");
}
}
}
public ICommand SaveMotorCommand
{
get
{
if (_saveMotorCommand == null)
{
_saveMotorCommand = new RelayCommand(
param => SaveMotor(),
param => (CurrentMotor != null)
);
}
return _saveMotorCommand;
}
}
public ICommand GetMotorCommand
{
get
{
if (_getMotorCommand == null)
{
_getMotorCommand = new RelayCommand(
param => GetMotor(),
param => MotorID > 0
);
}
return _getMotorCommand;
}
}

#endregion //Properties

#region Private Helpers

private void GetMotor()
{
_currentMotor = new Motor(_motorId);
_motorName = _currentMotor.MotorName;
string msg = string.Format($"You got {_motorName}.");
MessageBox.Show(msg);
}

private void SaveMotor()
{
string msg = string.Format($"You saved {_motorName}.");
MessageBox.Show(msg);
}

#endregion Private Helpers
}
}


Views (XAML):



<Window x:Class="LearningWPF.Views.MainWindow"
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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Views/ViewResources/MainWindowResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding}"/>
</Grid>
</Window>


Views (C#):



using System.Windows;

namespace LearningWPF.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

}
}
}


ViewResources:



<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:LearningWPF.Models"
xmlns:vm="clr-namespace:LearningWPF.ViewModels">

<DataTemplate DataType="{x:Type m:Motor}">
<Border BorderBrush="Black"
BorderThickness="1"
Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock Grid.Column="0"
Grid.Row="0"
Text="ID"
VerticalAlignment="Center"/>
<TextBox Grid.Column="1"
Grid.Row="0"
Text="{Binding ID}"/>

<TextBlock Grid.Column="0"
Grid.Row="1"
Text="Name"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="1"
Text="{Binding MotorName}" />

<TextBlock Grid.Column="0"
Grid.Row="2"
Text="Status"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="2"
Text="{Binding Status}" />
</Grid>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MotorViewModel}">
<DockPanel Margin="20">
<DockPanel DockPanel.Dock="Top">
<TextBlock Margin="10,2"
DockPanel.Dock="Left"
Text="Enter Motor ID"
VerticalAlignment="Center" />

<TextBox Margin="10,2"
Width="50"
VerticalAlignment="Center"
Text="{Binding Path=MotorID, UpdateSourceTrigger=PropertyChanged}"/>

<Button Content="Save Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=SaveMotorCommand}"
Width="100" />

<Button Content="Get Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=GetMotorCommand}"
IsDefault="True"
Width="100" />

<ContentControl Margin="10,20"
Content="{Binding Path=CurrentMotor}" />
</DockPanel>
</DockPanel>
</DataTemplate>
</ResourceDictionary>


App (XAML):



<Application x:Class="LearningWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Application.Resources>

</Application.Resources>
</Application>


App (C#):



using System.Windows;
using LearningWPF.ViewModels;
using LearningWPF.Views;

namespace LearningWPF
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

MainWindow startApp = new MainWindow();
MotorViewModel viewModel = new MotorViewModel();
startApp.DataContext = viewModel;
startApp.Show();
}
}
}


RelayCommand (idk where to put this):



using System;
using System.Windows.Input;
using System.Diagnostics;

namespace LearningWPF
{
/// <summary>
/// A command whose sole purpose is to relay its
/// functionality to other objects by invoking
/// delegates. The default return value for the
/// CanExecute method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields

//This is a method that will perform the
//requested action.
readonly Action<object> _execute;

//This is a method that will determine
//if _execute SHOULD execute.
readonly Predicate<object> _canExecute;

#endregion Fields

#region Constructors

/// <summary>
/// Creates a new command that can always
/// execute.
/// </summary>
/// <param name="execute">The execution logic.</param>

//This constructor should be used when you know
//absolutely positively that the delegate should
//execute.
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}

/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution stats logic.</param>

//This constructor should be used when you know which delegate you want
//to execute and when you have a different delegate to determine if
//your command should execute.
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
//if (execute != null)
//{
// _execute = execute;
//}
//else
//{
// throw new ArgumentNullException("execute");
//}

//The next line is equivalent to the above code.
_execute = execute ?? throw new ArgumentNullException("execute");
_canExecute = canExecute;
}

#endregion Constructors

#region ICommand Members

/// <summary>
/// Determines if the command is able to be executed.
/// </summary>
/// <param name="parameters">Input parameters for Predicate.</param>
/// <returns></returns>
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
//if (_canExecute == null)
//{
// return true;
//}
//else
//{
// return _canExecute(parameters);
//}

//The next line is equivalent to the above code.
return _canExecute == null ? true : _canExecute(parameters);
}

/// <summary>
/// This is used to notify that the CanExecute property has changed.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

/// <summary>
/// Executes the command.
/// </summary>
/// <param name="parameters">Input parameters for Action.</param>
public void Execute(object parameters)
{
_execute(parameters);
}

#endregion ICommand Members
}
}









share|improve this question




















  • 6




    You need to tell us the purpose of this project. I see it has something to do with motors etc. Describe please how this works, what it does and and and... A summary of this project should also be the title of your question.
    – t3chb0t
    yesterday










  • @t3chb0t Thanks for the comment. I added a summary to it before the Project Hierarchy section.
    – jcrizk
    16 hours ago
















1














I made a tutorial project to help myself better understand how to use WPF and MVVM, but there are a couple of things I'm unsure about.



This is the tutorial I was using as a reference. I deviated from it a little to make it more interesting for myself.





  1. Is it a good idea to merge MainWindowResources.xaml with MainWindow.xaml or should I merge it with App.xaml? Why or why not? I have tried both and they both run fine (granted the project is extremely basic), but I'm very suspicious about them doing the same thing.


  2. Do you have any recommendations for naming conventions? I would like to know if there are naming conventions that most people would use in the context of MVVM; I'm pretty bad with naming if you leave me to my own devices.

  3. Do you have any other general recommendations/guidelines?


Summary:



The user is supposed to be able to get a motor by its ID and then save the motor as the current motor.



Project Hierarchy:



screenshot of the solution explorer



Enums:



namespace LearningWPF.Enums
{
public enum MotorStatus
{
Off = 0,
On = 1
}
}


.



namespace LearningWPF.Enums
{
public enum RotationalDirection
{
Clockwise = -1,
CounterClockwise = 1
}
}


Models:



using LearningWPF.Enums;

namespace LearningWPF.Models
{
public class Motor : ProtoModel
{
#region Fields

private MotorStatus _status;
private int _id;
private string _motorName;
private RotationalDirection _direction;

#endregion //Fields

#region Properties

public MotorStatus Status
{
get { return _status; }

//This set method will determine if the input value is the
//same as the current value -> if they are not the same, then
//it will change the current value to the input value and
//then it will notify the event handler that its value
//has been changed.
set
{
if (value != _status)
{
_status = value;
OnPropertyChanged("Status");
}
}
}
public int ID
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
OnPropertyChanged("ID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public RotationalDirection Direction
{
get { return _direction; }
set
{
if (value != _direction)
{
_direction = value;
OnPropertyChanged("Direction");
}
}
}

#endregion //Properties

#region Constructors

public Motor(int id)
{
_status = MotorStatus.On;
_id = id;
_motorName = string.Format($"TestMotor{id}");
_direction = RotationalDirection.CounterClockwise;
}

#endregion Constructors
}
}




using System;
using System.ComponentModel;
using System.Diagnostics;

namespace LearningWPF.Models
{
//Purpose: To provide base functionality common to all models.
public abstract class ProtoModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged members

/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>

//This property is used to notify that another property has
//changed.
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName"></param>

//This method is used to initiate the PropertyChanged event.
//Whenever a property is changed for whatever reason, you will
//want the class to notify subscribers to the
//PropertyChangedEventHandler that a property on this object
//has just been changed.
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);

if (this.PropertyChanged != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(this, e);
}
}

#endregion //INotifyPropertyChanged members

#region Debugging aides

/// <summary>
/// Warns the developer if this object does not have a
/// public property with the specified name. This method does not
/// exist in a release build.
/// </summary>

//This method is used during debugging to determine if the
//class has the public property with the name passed into
//the method.
[Conditional("DEBUG")]
[DebuggerStepThrough]
public virtual void VerifyPropertyName(string propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = String.Format($"Invalid property name: {propertyName}");

if (this.ThrowOnInvalidPropertyName)
{
throw new Exception(msg);
}
else
{
Debug.Fail(msg);
}
}
}

/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail()
/// when an invalid property name is passed to the VerifyPropertyName
/// method. The default value is false, but subclasses used by unit
/// tests override this property's getter to return true.
/// </summary>

//This is basically used only for unit testing so that an
//exception is thrown instead of a Debug.Fail().
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

#endregion //Debugging aides
}
}


ViewModels:



using LearningWPF.Models;
using System.Windows.Input;
using System.Windows;

namespace LearningWPF.ViewModels
{
public class MotorViewModel : ProtoModel
{
#region Fields

private int _motorId;
private string _motorName;
private Motor _currentMotor;
private ICommand _getMotorCommand;
private ICommand _saveMotorCommand;

#endregion //Fields

#region Properties

public int MotorID
{
get { return _motorId; }
set
{
if (value != _motorId)
{
_motorId = value;
OnPropertyChanged("MotorID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public Motor CurrentMotor
{
get { return _currentMotor; }
set
{
if (value != _currentMotor)
{
_currentMotor = value;
OnPropertyChanged("CurrentMotor");
}
}
}
public ICommand SaveMotorCommand
{
get
{
if (_saveMotorCommand == null)
{
_saveMotorCommand = new RelayCommand(
param => SaveMotor(),
param => (CurrentMotor != null)
);
}
return _saveMotorCommand;
}
}
public ICommand GetMotorCommand
{
get
{
if (_getMotorCommand == null)
{
_getMotorCommand = new RelayCommand(
param => GetMotor(),
param => MotorID > 0
);
}
return _getMotorCommand;
}
}

#endregion //Properties

#region Private Helpers

private void GetMotor()
{
_currentMotor = new Motor(_motorId);
_motorName = _currentMotor.MotorName;
string msg = string.Format($"You got {_motorName}.");
MessageBox.Show(msg);
}

private void SaveMotor()
{
string msg = string.Format($"You saved {_motorName}.");
MessageBox.Show(msg);
}

#endregion Private Helpers
}
}


Views (XAML):



<Window x:Class="LearningWPF.Views.MainWindow"
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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Views/ViewResources/MainWindowResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding}"/>
</Grid>
</Window>


Views (C#):



using System.Windows;

namespace LearningWPF.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

}
}
}


ViewResources:



<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:LearningWPF.Models"
xmlns:vm="clr-namespace:LearningWPF.ViewModels">

<DataTemplate DataType="{x:Type m:Motor}">
<Border BorderBrush="Black"
BorderThickness="1"
Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock Grid.Column="0"
Grid.Row="0"
Text="ID"
VerticalAlignment="Center"/>
<TextBox Grid.Column="1"
Grid.Row="0"
Text="{Binding ID}"/>

<TextBlock Grid.Column="0"
Grid.Row="1"
Text="Name"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="1"
Text="{Binding MotorName}" />

<TextBlock Grid.Column="0"
Grid.Row="2"
Text="Status"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="2"
Text="{Binding Status}" />
</Grid>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MotorViewModel}">
<DockPanel Margin="20">
<DockPanel DockPanel.Dock="Top">
<TextBlock Margin="10,2"
DockPanel.Dock="Left"
Text="Enter Motor ID"
VerticalAlignment="Center" />

<TextBox Margin="10,2"
Width="50"
VerticalAlignment="Center"
Text="{Binding Path=MotorID, UpdateSourceTrigger=PropertyChanged}"/>

<Button Content="Save Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=SaveMotorCommand}"
Width="100" />

<Button Content="Get Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=GetMotorCommand}"
IsDefault="True"
Width="100" />

<ContentControl Margin="10,20"
Content="{Binding Path=CurrentMotor}" />
</DockPanel>
</DockPanel>
</DataTemplate>
</ResourceDictionary>


App (XAML):



<Application x:Class="LearningWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Application.Resources>

</Application.Resources>
</Application>


App (C#):



using System.Windows;
using LearningWPF.ViewModels;
using LearningWPF.Views;

namespace LearningWPF
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

MainWindow startApp = new MainWindow();
MotorViewModel viewModel = new MotorViewModel();
startApp.DataContext = viewModel;
startApp.Show();
}
}
}


RelayCommand (idk where to put this):



using System;
using System.Windows.Input;
using System.Diagnostics;

namespace LearningWPF
{
/// <summary>
/// A command whose sole purpose is to relay its
/// functionality to other objects by invoking
/// delegates. The default return value for the
/// CanExecute method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields

//This is a method that will perform the
//requested action.
readonly Action<object> _execute;

//This is a method that will determine
//if _execute SHOULD execute.
readonly Predicate<object> _canExecute;

#endregion Fields

#region Constructors

/// <summary>
/// Creates a new command that can always
/// execute.
/// </summary>
/// <param name="execute">The execution logic.</param>

//This constructor should be used when you know
//absolutely positively that the delegate should
//execute.
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}

/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution stats logic.</param>

//This constructor should be used when you know which delegate you want
//to execute and when you have a different delegate to determine if
//your command should execute.
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
//if (execute != null)
//{
// _execute = execute;
//}
//else
//{
// throw new ArgumentNullException("execute");
//}

//The next line is equivalent to the above code.
_execute = execute ?? throw new ArgumentNullException("execute");
_canExecute = canExecute;
}

#endregion Constructors

#region ICommand Members

/// <summary>
/// Determines if the command is able to be executed.
/// </summary>
/// <param name="parameters">Input parameters for Predicate.</param>
/// <returns></returns>
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
//if (_canExecute == null)
//{
// return true;
//}
//else
//{
// return _canExecute(parameters);
//}

//The next line is equivalent to the above code.
return _canExecute == null ? true : _canExecute(parameters);
}

/// <summary>
/// This is used to notify that the CanExecute property has changed.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

/// <summary>
/// Executes the command.
/// </summary>
/// <param name="parameters">Input parameters for Action.</param>
public void Execute(object parameters)
{
_execute(parameters);
}

#endregion ICommand Members
}
}









share|improve this question




















  • 6




    You need to tell us the purpose of this project. I see it has something to do with motors etc. Describe please how this works, what it does and and and... A summary of this project should also be the title of your question.
    – t3chb0t
    yesterday










  • @t3chb0t Thanks for the comment. I added a summary to it before the Project Hierarchy section.
    – jcrizk
    16 hours ago














1












1








1


1





I made a tutorial project to help myself better understand how to use WPF and MVVM, but there are a couple of things I'm unsure about.



This is the tutorial I was using as a reference. I deviated from it a little to make it more interesting for myself.





  1. Is it a good idea to merge MainWindowResources.xaml with MainWindow.xaml or should I merge it with App.xaml? Why or why not? I have tried both and they both run fine (granted the project is extremely basic), but I'm very suspicious about them doing the same thing.


  2. Do you have any recommendations for naming conventions? I would like to know if there are naming conventions that most people would use in the context of MVVM; I'm pretty bad with naming if you leave me to my own devices.

  3. Do you have any other general recommendations/guidelines?


Summary:



The user is supposed to be able to get a motor by its ID and then save the motor as the current motor.



Project Hierarchy:



screenshot of the solution explorer



Enums:



namespace LearningWPF.Enums
{
public enum MotorStatus
{
Off = 0,
On = 1
}
}


.



namespace LearningWPF.Enums
{
public enum RotationalDirection
{
Clockwise = -1,
CounterClockwise = 1
}
}


Models:



using LearningWPF.Enums;

namespace LearningWPF.Models
{
public class Motor : ProtoModel
{
#region Fields

private MotorStatus _status;
private int _id;
private string _motorName;
private RotationalDirection _direction;

#endregion //Fields

#region Properties

public MotorStatus Status
{
get { return _status; }

//This set method will determine if the input value is the
//same as the current value -> if they are not the same, then
//it will change the current value to the input value and
//then it will notify the event handler that its value
//has been changed.
set
{
if (value != _status)
{
_status = value;
OnPropertyChanged("Status");
}
}
}
public int ID
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
OnPropertyChanged("ID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public RotationalDirection Direction
{
get { return _direction; }
set
{
if (value != _direction)
{
_direction = value;
OnPropertyChanged("Direction");
}
}
}

#endregion //Properties

#region Constructors

public Motor(int id)
{
_status = MotorStatus.On;
_id = id;
_motorName = string.Format($"TestMotor{id}");
_direction = RotationalDirection.CounterClockwise;
}

#endregion Constructors
}
}




using System;
using System.ComponentModel;
using System.Diagnostics;

namespace LearningWPF.Models
{
//Purpose: To provide base functionality common to all models.
public abstract class ProtoModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged members

/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>

//This property is used to notify that another property has
//changed.
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName"></param>

//This method is used to initiate the PropertyChanged event.
//Whenever a property is changed for whatever reason, you will
//want the class to notify subscribers to the
//PropertyChangedEventHandler that a property on this object
//has just been changed.
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);

if (this.PropertyChanged != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(this, e);
}
}

#endregion //INotifyPropertyChanged members

#region Debugging aides

/// <summary>
/// Warns the developer if this object does not have a
/// public property with the specified name. This method does not
/// exist in a release build.
/// </summary>

//This method is used during debugging to determine if the
//class has the public property with the name passed into
//the method.
[Conditional("DEBUG")]
[DebuggerStepThrough]
public virtual void VerifyPropertyName(string propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = String.Format($"Invalid property name: {propertyName}");

if (this.ThrowOnInvalidPropertyName)
{
throw new Exception(msg);
}
else
{
Debug.Fail(msg);
}
}
}

/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail()
/// when an invalid property name is passed to the VerifyPropertyName
/// method. The default value is false, but subclasses used by unit
/// tests override this property's getter to return true.
/// </summary>

//This is basically used only for unit testing so that an
//exception is thrown instead of a Debug.Fail().
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

#endregion //Debugging aides
}
}


ViewModels:



using LearningWPF.Models;
using System.Windows.Input;
using System.Windows;

namespace LearningWPF.ViewModels
{
public class MotorViewModel : ProtoModel
{
#region Fields

private int _motorId;
private string _motorName;
private Motor _currentMotor;
private ICommand _getMotorCommand;
private ICommand _saveMotorCommand;

#endregion //Fields

#region Properties

public int MotorID
{
get { return _motorId; }
set
{
if (value != _motorId)
{
_motorId = value;
OnPropertyChanged("MotorID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public Motor CurrentMotor
{
get { return _currentMotor; }
set
{
if (value != _currentMotor)
{
_currentMotor = value;
OnPropertyChanged("CurrentMotor");
}
}
}
public ICommand SaveMotorCommand
{
get
{
if (_saveMotorCommand == null)
{
_saveMotorCommand = new RelayCommand(
param => SaveMotor(),
param => (CurrentMotor != null)
);
}
return _saveMotorCommand;
}
}
public ICommand GetMotorCommand
{
get
{
if (_getMotorCommand == null)
{
_getMotorCommand = new RelayCommand(
param => GetMotor(),
param => MotorID > 0
);
}
return _getMotorCommand;
}
}

#endregion //Properties

#region Private Helpers

private void GetMotor()
{
_currentMotor = new Motor(_motorId);
_motorName = _currentMotor.MotorName;
string msg = string.Format($"You got {_motorName}.");
MessageBox.Show(msg);
}

private void SaveMotor()
{
string msg = string.Format($"You saved {_motorName}.");
MessageBox.Show(msg);
}

#endregion Private Helpers
}
}


Views (XAML):



<Window x:Class="LearningWPF.Views.MainWindow"
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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Views/ViewResources/MainWindowResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding}"/>
</Grid>
</Window>


Views (C#):



using System.Windows;

namespace LearningWPF.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

}
}
}


ViewResources:



<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:LearningWPF.Models"
xmlns:vm="clr-namespace:LearningWPF.ViewModels">

<DataTemplate DataType="{x:Type m:Motor}">
<Border BorderBrush="Black"
BorderThickness="1"
Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock Grid.Column="0"
Grid.Row="0"
Text="ID"
VerticalAlignment="Center"/>
<TextBox Grid.Column="1"
Grid.Row="0"
Text="{Binding ID}"/>

<TextBlock Grid.Column="0"
Grid.Row="1"
Text="Name"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="1"
Text="{Binding MotorName}" />

<TextBlock Grid.Column="0"
Grid.Row="2"
Text="Status"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="2"
Text="{Binding Status}" />
</Grid>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MotorViewModel}">
<DockPanel Margin="20">
<DockPanel DockPanel.Dock="Top">
<TextBlock Margin="10,2"
DockPanel.Dock="Left"
Text="Enter Motor ID"
VerticalAlignment="Center" />

<TextBox Margin="10,2"
Width="50"
VerticalAlignment="Center"
Text="{Binding Path=MotorID, UpdateSourceTrigger=PropertyChanged}"/>

<Button Content="Save Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=SaveMotorCommand}"
Width="100" />

<Button Content="Get Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=GetMotorCommand}"
IsDefault="True"
Width="100" />

<ContentControl Margin="10,20"
Content="{Binding Path=CurrentMotor}" />
</DockPanel>
</DockPanel>
</DataTemplate>
</ResourceDictionary>


App (XAML):



<Application x:Class="LearningWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Application.Resources>

</Application.Resources>
</Application>


App (C#):



using System.Windows;
using LearningWPF.ViewModels;
using LearningWPF.Views;

namespace LearningWPF
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

MainWindow startApp = new MainWindow();
MotorViewModel viewModel = new MotorViewModel();
startApp.DataContext = viewModel;
startApp.Show();
}
}
}


RelayCommand (idk where to put this):



using System;
using System.Windows.Input;
using System.Diagnostics;

namespace LearningWPF
{
/// <summary>
/// A command whose sole purpose is to relay its
/// functionality to other objects by invoking
/// delegates. The default return value for the
/// CanExecute method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields

//This is a method that will perform the
//requested action.
readonly Action<object> _execute;

//This is a method that will determine
//if _execute SHOULD execute.
readonly Predicate<object> _canExecute;

#endregion Fields

#region Constructors

/// <summary>
/// Creates a new command that can always
/// execute.
/// </summary>
/// <param name="execute">The execution logic.</param>

//This constructor should be used when you know
//absolutely positively that the delegate should
//execute.
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}

/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution stats logic.</param>

//This constructor should be used when you know which delegate you want
//to execute and when you have a different delegate to determine if
//your command should execute.
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
//if (execute != null)
//{
// _execute = execute;
//}
//else
//{
// throw new ArgumentNullException("execute");
//}

//The next line is equivalent to the above code.
_execute = execute ?? throw new ArgumentNullException("execute");
_canExecute = canExecute;
}

#endregion Constructors

#region ICommand Members

/// <summary>
/// Determines if the command is able to be executed.
/// </summary>
/// <param name="parameters">Input parameters for Predicate.</param>
/// <returns></returns>
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
//if (_canExecute == null)
//{
// return true;
//}
//else
//{
// return _canExecute(parameters);
//}

//The next line is equivalent to the above code.
return _canExecute == null ? true : _canExecute(parameters);
}

/// <summary>
/// This is used to notify that the CanExecute property has changed.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

/// <summary>
/// Executes the command.
/// </summary>
/// <param name="parameters">Input parameters for Action.</param>
public void Execute(object parameters)
{
_execute(parameters);
}

#endregion ICommand Members
}
}









share|improve this question















I made a tutorial project to help myself better understand how to use WPF and MVVM, but there are a couple of things I'm unsure about.



This is the tutorial I was using as a reference. I deviated from it a little to make it more interesting for myself.





  1. Is it a good idea to merge MainWindowResources.xaml with MainWindow.xaml or should I merge it with App.xaml? Why or why not? I have tried both and they both run fine (granted the project is extremely basic), but I'm very suspicious about them doing the same thing.


  2. Do you have any recommendations for naming conventions? I would like to know if there are naming conventions that most people would use in the context of MVVM; I'm pretty bad with naming if you leave me to my own devices.

  3. Do you have any other general recommendations/guidelines?


Summary:



The user is supposed to be able to get a motor by its ID and then save the motor as the current motor.



Project Hierarchy:



screenshot of the solution explorer



Enums:



namespace LearningWPF.Enums
{
public enum MotorStatus
{
Off = 0,
On = 1
}
}


.



namespace LearningWPF.Enums
{
public enum RotationalDirection
{
Clockwise = -1,
CounterClockwise = 1
}
}


Models:



using LearningWPF.Enums;

namespace LearningWPF.Models
{
public class Motor : ProtoModel
{
#region Fields

private MotorStatus _status;
private int _id;
private string _motorName;
private RotationalDirection _direction;

#endregion //Fields

#region Properties

public MotorStatus Status
{
get { return _status; }

//This set method will determine if the input value is the
//same as the current value -> if they are not the same, then
//it will change the current value to the input value and
//then it will notify the event handler that its value
//has been changed.
set
{
if (value != _status)
{
_status = value;
OnPropertyChanged("Status");
}
}
}
public int ID
{
get { return _id; }
set
{
if (value != _id)
{
_id = value;
OnPropertyChanged("ID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public RotationalDirection Direction
{
get { return _direction; }
set
{
if (value != _direction)
{
_direction = value;
OnPropertyChanged("Direction");
}
}
}

#endregion //Properties

#region Constructors

public Motor(int id)
{
_status = MotorStatus.On;
_id = id;
_motorName = string.Format($"TestMotor{id}");
_direction = RotationalDirection.CounterClockwise;
}

#endregion Constructors
}
}




using System;
using System.ComponentModel;
using System.Diagnostics;

namespace LearningWPF.Models
{
//Purpose: To provide base functionality common to all models.
public abstract class ProtoModel : INotifyPropertyChanged
{
#region INotifyPropertyChanged members

/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>

//This property is used to notify that another property has
//changed.
public event PropertyChangedEventHandler PropertyChanged;

/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
/// <param name="propertyName"></param>

//This method is used to initiate the PropertyChanged event.
//Whenever a property is changed for whatever reason, you will
//want the class to notify subscribers to the
//PropertyChangedEventHandler that a property on this object
//has just been changed.
protected virtual void OnPropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);

if (this.PropertyChanged != null)
{
PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName);
this.PropertyChanged(this, e);
}
}

#endregion //INotifyPropertyChanged members

#region Debugging aides

/// <summary>
/// Warns the developer if this object does not have a
/// public property with the specified name. This method does not
/// exist in a release build.
/// </summary>

//This method is used during debugging to determine if the
//class has the public property with the name passed into
//the method.
[Conditional("DEBUG")]
[DebuggerStepThrough]
public virtual void VerifyPropertyName(string propertyName)
{
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = String.Format($"Invalid property name: {propertyName}");

if (this.ThrowOnInvalidPropertyName)
{
throw new Exception(msg);
}
else
{
Debug.Fail(msg);
}
}
}

/// <summary>
/// Returns whether an exception is thrown, or if a Debug.Fail()
/// when an invalid property name is passed to the VerifyPropertyName
/// method. The default value is false, but subclasses used by unit
/// tests override this property's getter to return true.
/// </summary>

//This is basically used only for unit testing so that an
//exception is thrown instead of a Debug.Fail().
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

#endregion //Debugging aides
}
}


ViewModels:



using LearningWPF.Models;
using System.Windows.Input;
using System.Windows;

namespace LearningWPF.ViewModels
{
public class MotorViewModel : ProtoModel
{
#region Fields

private int _motorId;
private string _motorName;
private Motor _currentMotor;
private ICommand _getMotorCommand;
private ICommand _saveMotorCommand;

#endregion //Fields

#region Properties

public int MotorID
{
get { return _motorId; }
set
{
if (value != _motorId)
{
_motorId = value;
OnPropertyChanged("MotorID");
}
}
}
public string MotorName
{
get { return _motorName; }
set
{
if (value != _motorName)
{
_motorName = value;
OnPropertyChanged("MotorName");
}
}
}
public Motor CurrentMotor
{
get { return _currentMotor; }
set
{
if (value != _currentMotor)
{
_currentMotor = value;
OnPropertyChanged("CurrentMotor");
}
}
}
public ICommand SaveMotorCommand
{
get
{
if (_saveMotorCommand == null)
{
_saveMotorCommand = new RelayCommand(
param => SaveMotor(),
param => (CurrentMotor != null)
);
}
return _saveMotorCommand;
}
}
public ICommand GetMotorCommand
{
get
{
if (_getMotorCommand == null)
{
_getMotorCommand = new RelayCommand(
param => GetMotor(),
param => MotorID > 0
);
}
return _getMotorCommand;
}
}

#endregion //Properties

#region Private Helpers

private void GetMotor()
{
_currentMotor = new Motor(_motorId);
_motorName = _currentMotor.MotorName;
string msg = string.Format($"You got {_motorName}.");
MessageBox.Show(msg);
}

private void SaveMotor()
{
string msg = string.Format($"You saved {_motorName}.");
MessageBox.Show(msg);
}

#endregion Private Helpers
}
}


Views (XAML):



<Window x:Class="LearningWPF.Views.MainWindow"
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"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">

<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Views/ViewResources/MainWindowResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<ContentControl Content="{Binding}"/>
</Grid>
</Window>


Views (C#):



using System.Windows;

namespace LearningWPF.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();

}
}
}


ViewResources:



<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:m="clr-namespace:LearningWPF.Models"
xmlns:vm="clr-namespace:LearningWPF.ViewModels">

<DataTemplate DataType="{x:Type m:Motor}">
<Border BorderBrush="Black"
BorderThickness="1"
Padding="20">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock Grid.Column="0"
Grid.Row="0"
Text="ID"
VerticalAlignment="Center"/>
<TextBox Grid.Column="1"
Grid.Row="0"
Text="{Binding ID}"/>

<TextBlock Grid.Column="0"
Grid.Row="1"
Text="Name"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="1"
Text="{Binding MotorName}" />

<TextBlock Grid.Column="0"
Grid.Row="2"
Text="Status"
VerticalAlignment="Center" />
<TextBox Grid.Column="1"
Grid.Row="2"
Text="{Binding Status}" />
</Grid>
</Border>
</DataTemplate>
<DataTemplate DataType="{x:Type vm:MotorViewModel}">
<DockPanel Margin="20">
<DockPanel DockPanel.Dock="Top">
<TextBlock Margin="10,2"
DockPanel.Dock="Left"
Text="Enter Motor ID"
VerticalAlignment="Center" />

<TextBox Margin="10,2"
Width="50"
VerticalAlignment="Center"
Text="{Binding Path=MotorID, UpdateSourceTrigger=PropertyChanged}"/>

<Button Content="Save Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=SaveMotorCommand}"
Width="100" />

<Button Content="Get Motor"
DockPanel.Dock="Right"
Margin="10,2"
VerticalAlignment="Center"
Command="{Binding Path=GetMotorCommand}"
IsDefault="True"
Width="100" />

<ContentControl Margin="10,20"
Content="{Binding Path=CurrentMotor}" />
</DockPanel>
</DockPanel>
</DataTemplate>
</ResourceDictionary>


App (XAML):



<Application x:Class="LearningWPF.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Application.Resources>

</Application.Resources>
</Application>


App (C#):



using System.Windows;
using LearningWPF.ViewModels;
using LearningWPF.Views;

namespace LearningWPF
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);

MainWindow startApp = new MainWindow();
MotorViewModel viewModel = new MotorViewModel();
startApp.DataContext = viewModel;
startApp.Show();
}
}
}


RelayCommand (idk where to put this):



using System;
using System.Windows.Input;
using System.Diagnostics;

namespace LearningWPF
{
/// <summary>
/// A command whose sole purpose is to relay its
/// functionality to other objects by invoking
/// delegates. The default return value for the
/// CanExecute method is 'true'.
/// </summary>
public class RelayCommand : ICommand
{
#region Fields

//This is a method that will perform the
//requested action.
readonly Action<object> _execute;

//This is a method that will determine
//if _execute SHOULD execute.
readonly Predicate<object> _canExecute;

#endregion Fields

#region Constructors

/// <summary>
/// Creates a new command that can always
/// execute.
/// </summary>
/// <param name="execute">The execution logic.</param>

//This constructor should be used when you know
//absolutely positively that the delegate should
//execute.
public RelayCommand(Action<object> execute)
: this(execute, null)
{
}

/// <summary>
/// Creates a new command.
/// </summary>
/// <param name="execute">The execution logic.</param>
/// <param name="canExecute">The execution stats logic.</param>

//This constructor should be used when you know which delegate you want
//to execute and when you have a different delegate to determine if
//your command should execute.
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
//if (execute != null)
//{
// _execute = execute;
//}
//else
//{
// throw new ArgumentNullException("execute");
//}

//The next line is equivalent to the above code.
_execute = execute ?? throw new ArgumentNullException("execute");
_canExecute = canExecute;
}

#endregion Constructors

#region ICommand Members

/// <summary>
/// Determines if the command is able to be executed.
/// </summary>
/// <param name="parameters">Input parameters for Predicate.</param>
/// <returns></returns>
[DebuggerStepThrough]
public bool CanExecute(object parameters)
{
//if (_canExecute == null)
//{
// return true;
//}
//else
//{
// return _canExecute(parameters);
//}

//The next line is equivalent to the above code.
return _canExecute == null ? true : _canExecute(parameters);
}

/// <summary>
/// This is used to notify that the CanExecute property has changed.
/// </summary>
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}

/// <summary>
/// Executes the command.
/// </summary>
/// <param name="parameters">Input parameters for Action.</param>
public void Execute(object parameters)
{
_execute(parameters);
}

#endregion ICommand Members
}
}






c# wpf mvvm xaml






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 5 mins ago









Jamal

30.3k11116226




30.3k11116226










asked yesterday









jcrizk

1237




1237








  • 6




    You need to tell us the purpose of this project. I see it has something to do with motors etc. Describe please how this works, what it does and and and... A summary of this project should also be the title of your question.
    – t3chb0t
    yesterday










  • @t3chb0t Thanks for the comment. I added a summary to it before the Project Hierarchy section.
    – jcrizk
    16 hours ago














  • 6




    You need to tell us the purpose of this project. I see it has something to do with motors etc. Describe please how this works, what it does and and and... A summary of this project should also be the title of your question.
    – t3chb0t
    yesterday










  • @t3chb0t Thanks for the comment. I added a summary to it before the Project Hierarchy section.
    – jcrizk
    16 hours ago








6




6




You need to tell us the purpose of this project. I see it has something to do with motors etc. Describe please how this works, what it does and and and... A summary of this project should also be the title of your question.
– t3chb0t
yesterday




You need to tell us the purpose of this project. I see it has something to do with motors etc. Describe please how this works, what it does and and and... A summary of this project should also be the title of your question.
– t3chb0t
yesterday












@t3chb0t Thanks for the comment. I added a summary to it before the Project Hierarchy section.
– jcrizk
16 hours ago




@t3chb0t Thanks for the comment. I added a summary to it before the Project Hierarchy section.
– jcrizk
16 hours ago















active

oldest

votes











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














draft saved

draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210624%2fmotor-selection-tutorial-project%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown






























active

oldest

votes













active

oldest

votes









active

oldest

votes






active

oldest

votes
















draft saved

draft discarded




















































Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • Please be sure to answer the question. Provide details and share your research!

But avoid



  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f210624%2fmotor-selection-tutorial-project%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Create new schema in PostgreSQL using DBeaver

Deepest pit of an array with Javascript: test on Codility

Costa Masnaga