Suggestions for this tutorial project












0














So 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?


Thanks in advance if you happen to read or answer!



Project Hiearchy:



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



























    0














    So 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?


    Thanks in advance if you happen to read or answer!



    Project Hiearchy:



    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

























      0












      0








      0


      1





      So 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?


      Thanks in advance if you happen to read or answer!



      Project Hiearchy:



      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













      So 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?


      Thanks in advance if you happen to read or answer!



      Project Hiearchy:



      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










      asked 2 hours ago









      jcrizk

      1157




      1157



























          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%2fsuggestions-for-this-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%2fsuggestions-for-this-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

          Morgemoulin

          Scott Moir

          Souastre