WPF exe 运行 与 Visual studio 中的 运行 相比非常慢
WPF exe running very slow compared to running in Visual studio
我已经使用 MVVM 模式在 WPF 中创建了一个应用程序。
应用程序在 Visual Studio 调试器中 运行 正常,但是当我 运行 来自 debug/release 文件夹的 exe 时,它变得非常慢。
这是我的 RelayCommand
class:
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
public RelayCommand(Action<object> execute) : this(execute, DefaultCanExecute)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
bool res = false;
if (canExecute != null)
{
res = canExecute(parameter);
}
return res;
}
public void Execute(object parameter)
{
execute(parameter);
}
private static bool DefaultCanExecute(object parameter)
{
return true;
}
}
如果我从 RelayCommand
class 中删除 CanExcecute()
方法,那么 exe 版本将正常运行。
谁能解释一下为什么会这样?它是针对 CanExecuteChanged
事件处理程序的吗?
您有两个选择:
- 不要使用
CommandManager.RequerySuggested
事件。
CommandManager
的当前实现将所有命令的重新查询作为 Dispatcher
操作和 DispatcherPriority.Background
排队。这意味着,只要您的应用程序空闲,CommandManager
就会调用您在 CommandManager
中注册的所有命令的 CanExecute()
方法。如果这些方法中的任何一个确实消耗了一些资源(比如使用数据库或读取文件),那么您可能会注意到应用程序的整体性能下降。
例如Prism 有自己的 ICommand
实现,无需订阅 CommandManager
的事件。这也很好用,但是当你想更新命令状态时,你必须明确地调用 RaiseCanExecuteChanged()
方法。这通常不是问题,因为您应该一次只对几个命令感兴趣,而不是对应用程序中的所有命令感兴趣。
- 不要在您的
CanExecute()
方法中使用任何重量级任务。
他们应该是这样的,又短又快:
public bool CanExecute()
{
return this.isIdle && this.someFlag && !this.CommandAbort.CanExecute();
}
我已经使用 MVVM 模式在 WPF 中创建了一个应用程序。
应用程序在 Visual Studio 调试器中 运行 正常,但是当我 运行 来自 debug/release 文件夹的 exe 时,它变得非常慢。
这是我的 RelayCommand
class:
public class RelayCommand : ICommand
{
private readonly Action<object> execute;
private readonly Predicate<object> canExecute;
public RelayCommand(Action<object> execute) : this(execute, DefaultCanExecute)
{
}
public RelayCommand(Action<object> execute, Predicate<object> canExecute)
{
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler CanExecuteChanged
{
add
{
CommandManager.RequerySuggested += value;
}
remove
{
CommandManager.RequerySuggested -= value;
}
}
[DebuggerStepThrough]
public bool CanExecute(object parameter)
{
bool res = false;
if (canExecute != null)
{
res = canExecute(parameter);
}
return res;
}
public void Execute(object parameter)
{
execute(parameter);
}
private static bool DefaultCanExecute(object parameter)
{
return true;
}
}
如果我从 RelayCommand
class 中删除 CanExcecute()
方法,那么 exe 版本将正常运行。
谁能解释一下为什么会这样?它是针对 CanExecuteChanged
事件处理程序的吗?
您有两个选择:
- 不要使用
CommandManager.RequerySuggested
事件。
CommandManager
的当前实现将所有命令的重新查询作为 Dispatcher
操作和 DispatcherPriority.Background
排队。这意味着,只要您的应用程序空闲,CommandManager
就会调用您在 CommandManager
中注册的所有命令的 CanExecute()
方法。如果这些方法中的任何一个确实消耗了一些资源(比如使用数据库或读取文件),那么您可能会注意到应用程序的整体性能下降。
例如Prism 有自己的 ICommand
实现,无需订阅 CommandManager
的事件。这也很好用,但是当你想更新命令状态时,你必须明确地调用 RaiseCanExecuteChanged()
方法。这通常不是问题,因为您应该一次只对几个命令感兴趣,而不是对应用程序中的所有命令感兴趣。
- 不要在您的
CanExecute()
方法中使用任何重量级任务。
他们应该是这样的,又短又快:
public bool CanExecute()
{
return this.isIdle && this.someFlag && !this.CommandAbort.CanExecute();
}