我有一个与这里类似的问题:WPF MVVM Light: Command.RaiseCanExecuteChanged() doesn't work,使用带有WPF的命令,并且直到我单击屏幕上的某个位置,GUI才能工作。我不使用MVVM Light。
我通过调用ExternalDLL.Start()调用外部DLL来执行某些操作,并调用GetStatus()来了解操作是否开始。如果返回正确的状态,则更改实际操作,并且必须激活GUI上的按钮。
在我单击某处之前,该按钮不会激活自己。
我检查了线程,但似乎它在同一线程上,我尝试使用Application.Current.Dispatcher.BeginInvoke
将其放在GUI线程中,但是它也没有起作用。
这是我的代码:
private async void StartScanCommand_Executed(object sender, ExecutedRoutedEventArgs e)
{
ExternalDLL.Start();
WaitForStarting();
}
private async void WaitForStarting()
{
Waiting();
Stopwatch chrono = new Stopwatch();
chrono.Start();
bool started = false;
while (chrono.ElapsedMilliseconds < 20000)
{
if (ExternalDLL.GetStatus() != ExternalDLL.Status.Started)
{
await Task.Delay(100);
}
else
{
started = true;
chrono.Stop();
StartedAction();
break;
}
}
if (!started)
{
MessageBox.Show("Error");
}
}
Waiting()
方法调用将激活GUI中的按钮并开始工作。但是StartedAction()
也必须激活一个按钮,并且不起作用。
以下是开始执行的代码:
private void StartedAction()
{
_actualAction = ActualAction.DoingAction;
}
这是按钮的可以执行的方法:
private void SomeButtonCommand_CanExecute(object sender,
CanExecuteRoutedEventArgs e)
{
e.CanExecute = _actualAction == ActualAction.DoingAction;
}
我在做什么错了?
答案 0 :(得分:1)
问题很简单,当ActualAction
值更改时,绑定的命令的CanExecute状态不会重新评估。
致电CommandManager.InvalidateRequerySuggested()
强制进行重新评估。
private void StartedAction()
{
_actualAction = ActualAction.DoingAction;
CommandManager.InvalidateRequerySuggested();
}
答案 1 :(得分:-1)
您正在UI线程上进行后台工作。不要在那里做,在另一个线程中做,并使用轮询,事件或其他回调方法来更新UI(在UI线程上)。
例如,您可以这样做:
Task.Run(() => { OtherDll.DoWork(); };
这将启动外部线程上的其他工作。
如果您需要更多控制权,则可以将其他dll的功能全部包装在一个线程中。
Public Class OtherDLLThread
{
Thread _internalThread;
public OtherDLLThread()
{
_internalThread = new Thread(ThreadMainLoop);
}
public void ThreadMainLoop()
{
OtherDLL.DoWork();
}
public static void Start()
{
_internalThread.Start();
}
}
像这样使用它:
OtherDLLThread other = new OtherDLLThread();
other.Start();
这是将代码添加到UI线程的另一个功能:
/// <summary>
/// Runs the action on UI thread.
/// </summary>
/// <param name="action">The action.</param>
public static void RunOnUIThread(Action action)
{
try
{
if (Application.Current != null)
Application.Current.Dispatcher.Invoke(action);
}
catch (Exception ee)
{
_logger.Fatal("UI Thread Code Crashed. Action detail: " + action.Method, ee);
//SystemManager.Instance.SendErrorEmailToCsaTeam("Kiosk Application Crashed", "UI Thread Code Crashed. Action detail: " + action.Method);
throw;
}
}
像这样使用它:
RunOnUITHread(() => lblStatus.Text = "Working...");