Change Property Command

Many applications requires history support (undo/redo). I found class ChangPropertyCommand very helpful for such tasks, because it allows you to specify any property of the object to be changed, so you don’t need to write many classes.

public class ChangePropertyCommand : Command
{

    private var Target_;
    private var NewValue_;
    private var OldValue_;
    private string PropertyName_;
    public ChangePropertyCommand(object Target, string PropertyName, object Value)
    {
        Target_ = Target;
        NewValue_ = Value;
        PropertyName_ = PropertyName;
        OldValue_ = GetValue();
    }

    public override void Execute()
    {
        base.Execute();
        SetValue(NewValue_);
    }

    public override void UnExecute()
    {
        base.UnExecute();
        SetValue(OldValue_);
    }

    private void SetValue(object Value)
    {
        object tmp = Target_;
        var type = Target_.GetType();
        string[] paths = PropertyName_.Split(".");
        PropertyInfo prop = type.GetProperty(paths(0));
        for (int i = 0; i <= paths.Length - 2; i++) {
            prop = type.GetProperty(paths(i));
            tmp = prop.GetValue(tmp, null);
            type = tmp.GetType;
        }
        prop = type.GetProperty(paths(paths.Length - 1));
        prop.SetValue(tmp, Value, null);
    }

    private object GetValue()
    {
        object ret = Target_;
        var type = Target_.GetType();
        string[] paths = PropertyName_.Split(".");
        foreach (string path in paths) {
            var prop = type.GetProperty(path);
            ret = prop.GetValue(ret, null);
            if (ret != null) {
                type = ret.GetType;
            }
        }
        return ret;
    }
}
Imports System.Reflection

Public Class ChangePropertyCommand
    Inherits Command

    Private Target_
    Private NewValue_
    Private OldValue_
    Private PropertyName_ As String
    Sub New(ByVal Target As Object, ByVal PropertyName As String, ByVal Value As Object)
        Target_ = Target
        NewValue_ = Value
        PropertyName_ = PropertyName
        OldValue_ = GetValue()
    End Sub

    Public Overrides Sub Execute()
        MyBase.Execute()
        SetValue(NewValue_)
    End Sub

    Public Overrides Sub UnExecute()
        MyBase.UnExecute()
        SetValue(OldValue_)
    End Sub

    Private Sub SetValue(ByVal Value As Object)
        Dim tmp As Object = Target_
        Dim type = Target_.GetType()
        Dim paths As String() = PropertyName_.Split(".")
        Dim prop As PropertyInfo = type.GetProperty(paths(0))
        For i As Integer = 0 To paths.Length - 2
            prop = type.GetProperty(paths(i))
            tmp = prop.GetValue(tmp, Nothing)
            type = tmp.GetType
        Next
        prop = type.GetProperty(paths(paths.Length - 1))
        prop.SetValue(tmp, Value, Nothing)
    End Sub

    Private Function GetValue() As Object
        Dim ret As Object = Target_
        Dim type = Target_.GetType()
        Dim paths As String() = PropertyName_.Split(".")
        For Each path As String In paths
            Dim prop = type.GetProperty(path)
            ret = prop.GetValue(ret, Nothing)
            If ret IsNot Nothing Then
                type = ret.GetType
            End If
        Next
        Return ret
    End Function

End Class

Here some example of using this class:

ChangePropertyCommand width = new ChangePropertyCommand(CurrentElement, "Width", Current.Width);
ChangePropertyCommand height = new ChangePropertyCommand(CurrentElement, "Height", Current.Height);
Dim width As New ChangePropertyCommand(CurrentElement, "Width", Current.Width)
Dim height As New ChangePropertyCommand(CurrentElement, "Height", Current.Height)

As you can see, this code creates two commands, they will change properties Width and Height of the CurrentElement object, by values from Current object.
Often, Execute and Unexecute methods are not called directly, but called by History class.