MVVM 命令 属性 堆栈跟踪
MVVM Command property stacktrace
我想知道在我的 ApplicationCommand 中使用以下模式执行了哪个 属性 命令,知道吗?今天日志总是显示 ApplicationCommand.Execute(),对跟踪用户操作不是很有用。
Class 声明:
public class MyViewModel
{
public ICommand BlinkCommand { get; set; }
public ICommand CheckCommand { get; set; }
public MyViewModel()
{
BlinkCommand = new ApplicationCommand(() => DoBlink());
CheckCommand = new ApplicationCommand(() => DoCheck());
}
...
}
我的所有命令的应用程序命令实现:
public class ApplicationCommand : RelayCommand
{
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + this);
base.Execute();
Log.Info("Finished to execute the command " + this);
}
}
使用1个命令=1class,没问题。使用这种方式,似乎在WWW上被广泛使用,我不知道如何进行:(
预先感谢您的帮助
您尝试调用 GetType() 了吗?
public class ApplicationCommand : RelayCommand
{
public ApplicationCommand(Expression<Func<ICommand>> property,Action<T> execute, string logName = "")
{
// ...
this.logName = logName;
}
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + GetTypeName(this.GetType()) + "." + GetPropertyPath(property));
base.Execute();
Log.Info("Finished to execute the command " + GetTypeName(this.GetType()) + "." + GetPropertyPath(property));
}
}
private string GetPropertyPath(LambdaExpression propertyPath, bool acceptsFields = false)
{
Stack<MemberInfo> properties = GetPropertyPathStack(propertyPath, acceptsFields);
return string.Join(".", properties.Select(p => p.Name));
}
private Stack<MemberInfo> GetPropertyPathStack(LambdaExpression propertyPath, bool acceptFields = false)
{
MemberExpression member = propertyPath.Body as MemberExpression;
Stack<MemberInfo> properties = new Stack<MemberInfo>();
while(member != null)
{
if (member.Member is PropertyInfo || (acceptFields && member.Member is FieldInfo))
{
properties.Push(member.Member);
if (member.Expression is MemberExpression)
{
member = member.Expression as MemberExpression;
}
else
{
ConstantExpression constant = member.Expression as ConstantExpression;
member = null;
}
}
else
{
member = null;
}
}
return properties;
}
private string GetTypeName(Type type)
{
if (type.IsGenericType)
{
return GetGenericTypeName(type);
}
else
{
return type.FullName;
}
}
private string GetGenericTypeName(Type type)
{
Type[] genericArguments = type.GetGenericArguments();
string argumentNames = string.Join(", ", genericArguments.Select(GetTypeName));
return string.Format("{0}<{1}>", type.GetBaseName(), argumentNames);
}
希望这会对您有所帮助或启发您寻求更好的解决方案。
用法:
BlinkCommand = new ApplicationCommand(() => BlinkCommand, () => DoBlink());
您可以将额外的实例字符串添加到您在构造实例时传递的 ApplicationCommand,并在调用执行时记录该字符串。
public class ApplicationCommand : RelayCommand
{
private string logName;
public ApplicationCommand(Action<T> execute, string logName = "")
{
// ...
this.logName = logName;
}
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + this.logName);
base.Execute();
Log.Info("Finished to execute the command " + this.logName);
}
}
使用它:
BlinkCommand = new ApplicationCommand(() => DoBlink(), "Blink");
您应该像这样重构您的 ApplicationCommand
:
public class ApplicationCommand : RelayCommand
{
string commandName;
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + commandName);
base.Execute();
Log.Info("Finished to execute the command " + commandName);
}
public static void SetCommand(MyViewModel vm,
Expression<Func<MyViewModel,ICommand>> commandSelector,
Action action){
var me = commandSelector.Body as MemberExpression;
if(me == null) throw new ArgumentException("Invalid command selector!");
var newCommand = new ApplicationCommand(action);
newCommand.commandName = me.Member.Name;
vm.GetType()
.GetProperty(newCommand.commandName)
.SetValue(vm, newCommand, null);
}
}
//then use it like this
public MyViewModel()
{
ApplicationCommand.SetCommand(this, e => e.BlinkCommand, () => DoBlink());
ApplicationCommand.SetCommand(this, e => e.CheckCommand, () => DoCheck());
}
我知道这是为了调试目的,所以我们应该打印 属性 名称,然后使用上面的方法更好。
我想知道在我的 ApplicationCommand 中使用以下模式执行了哪个 属性 命令,知道吗?今天日志总是显示 ApplicationCommand.Execute(),对跟踪用户操作不是很有用。
Class 声明:
public class MyViewModel { public ICommand BlinkCommand { get; set; } public ICommand CheckCommand { get; set; } public MyViewModel() { BlinkCommand = new ApplicationCommand(() => DoBlink()); CheckCommand = new ApplicationCommand(() => DoCheck()); } ... }
我的所有命令的应用程序命令实现:
public class ApplicationCommand : RelayCommand
{
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + this);
base.Execute();
Log.Info("Finished to execute the command " + this);
}
}
使用1个命令=1class,没问题。使用这种方式,似乎在WWW上被广泛使用,我不知道如何进行:(
预先感谢您的帮助
您尝试调用 GetType() 了吗?
public class ApplicationCommand : RelayCommand
{
public ApplicationCommand(Expression<Func<ICommand>> property,Action<T> execute, string logName = "")
{
// ...
this.logName = logName;
}
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + GetTypeName(this.GetType()) + "." + GetPropertyPath(property));
base.Execute();
Log.Info("Finished to execute the command " + GetTypeName(this.GetType()) + "." + GetPropertyPath(property));
}
}
private string GetPropertyPath(LambdaExpression propertyPath, bool acceptsFields = false)
{
Stack<MemberInfo> properties = GetPropertyPathStack(propertyPath, acceptsFields);
return string.Join(".", properties.Select(p => p.Name));
}
private Stack<MemberInfo> GetPropertyPathStack(LambdaExpression propertyPath, bool acceptFields = false)
{
MemberExpression member = propertyPath.Body as MemberExpression;
Stack<MemberInfo> properties = new Stack<MemberInfo>();
while(member != null)
{
if (member.Member is PropertyInfo || (acceptFields && member.Member is FieldInfo))
{
properties.Push(member.Member);
if (member.Expression is MemberExpression)
{
member = member.Expression as MemberExpression;
}
else
{
ConstantExpression constant = member.Expression as ConstantExpression;
member = null;
}
}
else
{
member = null;
}
}
return properties;
}
private string GetTypeName(Type type)
{
if (type.IsGenericType)
{
return GetGenericTypeName(type);
}
else
{
return type.FullName;
}
}
private string GetGenericTypeName(Type type)
{
Type[] genericArguments = type.GetGenericArguments();
string argumentNames = string.Join(", ", genericArguments.Select(GetTypeName));
return string.Format("{0}<{1}>", type.GetBaseName(), argumentNames);
}
希望这会对您有所帮助或启发您寻求更好的解决方案。
用法:
BlinkCommand = new ApplicationCommand(() => BlinkCommand, () => DoBlink());
您可以将额外的实例字符串添加到您在构造实例时传递的 ApplicationCommand,并在调用执行时记录该字符串。
public class ApplicationCommand : RelayCommand
{
private string logName;
public ApplicationCommand(Action<T> execute, string logName = "")
{
// ...
this.logName = logName;
}
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + this.logName);
base.Execute();
Log.Info("Finished to execute the command " + this.logName);
}
}
使用它:
BlinkCommand = new ApplicationCommand(() => DoBlink(), "Blink");
您应该像这样重构您的 ApplicationCommand
:
public class ApplicationCommand : RelayCommand
{
string commandName;
public void Execute()
{
// No try-catch, I never code bugs ;o)
Log.Info("Prepare to execute the command " + commandName);
base.Execute();
Log.Info("Finished to execute the command " + commandName);
}
public static void SetCommand(MyViewModel vm,
Expression<Func<MyViewModel,ICommand>> commandSelector,
Action action){
var me = commandSelector.Body as MemberExpression;
if(me == null) throw new ArgumentException("Invalid command selector!");
var newCommand = new ApplicationCommand(action);
newCommand.commandName = me.Member.Name;
vm.GetType()
.GetProperty(newCommand.commandName)
.SetValue(vm, newCommand, null);
}
}
//then use it like this
public MyViewModel()
{
ApplicationCommand.SetCommand(this, e => e.BlinkCommand, () => DoBlink());
ApplicationCommand.SetCommand(this, e => e.CheckCommand, () => DoCheck());
}
我知道这是为了调试目的,所以我们应该打印 属性 名称,然后使用上面的方法更好。