漫长的过程,绑定更新和 UI 冻结
Long process, binding update and UI frozen
我的 WPF/C# 程序使用在特定序列中调用的不同方法。
每个方法都绑定到UI,经过很长的过程才显示一些数据。
我正在使用调度程序,因为被调用的方法在另一个线程中。
我还想在不冻结 UI 的情况下执行此过程,例如能够取消该过程并自由替换 window。
我的问题是 UI 根本没有更新(进度条,计算步骤)并且取消按钮直到计算结束才起作用。
事实上,o不知道如何立即取消一般序列,即使挂起的长过程没有完成。
我不是 100% 确定使用正确的方法,有没有人有更好的解决方案或任何建议?
例如
public void CalculationCommand()
{
var bkw = new BackgroundWorker()
bkw.DoWork += Work;
bkw.RunWorkerAsync(Dispatcher.CurrentDispatcher);
}
public void Work(object sender, DoWorkEventArgs e)
{
var dispatcher = e.Argument as Dispatcher;
var dispatcherPriority = DispatcherPriority.Background;
Action action;
action = () =>
{
UpdateStatut(StatutsInformation.Pending);
};
dispatcher.BeginInvoke(action, dispatcherPriority);
ViewModel1 viewModel1 = null;
action = () =>
{
UpdateProgress(10, "Sampling calculations");
viewModel1 = Application.GetEchantillonnage();//Long process
};
dispatcher.BeginInvoke(action, dispatcherPriority);
List<double> lengthList = null;
action = () =>
{
UpdateProgress(20, "Length calculations");
lengthList = AlgorithmLibrary.LengthCalculations(viewModel1);//Long process
};
dispatcher.BeginInvoke(action, dispatcherPriority);
ViewModel2 viewModel2 = null;
action = () =>
{
UpdateProgress(30, "Engine calculations");
viewModel2 = Application.GetEngine();//Long process
AlgorithmLibrary.EngineCalculations(viewModel2);//Long process
var FilteredLength = AlgorithmLibrary.LengthFilter(lengthList);//Long process
}; dispatcher.BeginInvoke(action, dispatcherPriority);
///... Others actions executed incrementing the progress value to 100%
action = () =>
{
UpdateStatut(StatutsInformation.Finished);
};
dispatcher.BeginInvoke(action, dispatcherPriority);
}
private void UpdateStatut(StatutsInformation statutInformation)
{
ViewModelLoading.StatutInformation = statutInformation;
}
private void UpdateProgress(int value, string label)
{
ViewModelLoading.Progress = value;
ViewModelLoading.Step = label;
}
谢谢
在方法 Work
中,您正在后台线程上执行。每次调用 dispatcher.BeginInvoke
时,传递给此方法的 action 将在 UI 线程[=23] 上执行=]。看看你现在在做什么?再看看这段代码
// Here, we are on a background thread
action = () =>
{
// This action is NOT executing yet! We are just defining it.
UpdateProgress(10, "Sampling calculations");
// This is going to execute on the thread that executes this action!
viewModel1 = Application.GetEchantillonnage();//Long process
};
// here, we are still on the background thread, but we are telling the
// dispatcher to marshall the action onto the UI thread to execute it!
dispatcher.BeginInvoke(action, dispatcherPriority);
您正在 UI 线程上进行长时间的 运行 工作:/
不过,解决方法很简单。只需将您的工作拉出来并将其保存在后台线程中即可。这是相同的代码,但按预期工作(除非您的代码中出现其他问题)
action = () => UpdateProgress(10, "Sampling calculations");
dispatcher.BeginInvoke(action, dispatcherPriority);
viewModel1 = Application.GetEchantillonnage();//Long process
您的代码不断进入后台线程以在 UI 线程上执行长 运行 任务。 Dispatcher.BeginInvoke 将委托编组回 UI 线程。
试试这个:
private void RunOnUI(Action uiAction, DispatcherPriority dispatcherPriority = DispatcherPriority.Background)
{
dispatcher.BeginInvoke(uiAction, dispatcherPriority);
}
public void Work(object sender, DoWorkEventArgs e)
{
var dispatcher = e.Argument as Dispatcher;
var dispatcherPriority = DispatcherPriority.Background;
Action action;
runOnUI(() =>
{
UpdateStatut(StatutsInformation.Pending);
});
ViewModel1 viewModel1 = null;
RunOnUI(() =>
{
UpdateProgress(10, "Sampling calculations");
});
viewModel1 = Application.GetEchantillonnage();//Long process
List<double> lengthList = null;
RunOnUI(() =>
{
UpdateProgress(20, "Length calculations");
});
lengthList = AlgorithmLibrary.LengthCalculations(viewModel1);//Long process
ViewModel2 viewModel2 = null;
RunOnUI(() =>
{
UpdateProgress(30, "Engine calculations");
};
viewModel2 = Application.GetEngine();//Long process
AlgorithmLibrary.EngineCalculations(viewModel2);//Long process
var FilteredLength = AlgorithmLibrary.LengthFilter(lengthList);//Long process
///... Others actions executed incrementing the progress value to 100%
RunOnUI(() =>
{
UpdateStatut(StatutsInformation.Finished);
});
}
我的 WPF/C# 程序使用在特定序列中调用的不同方法。 每个方法都绑定到UI,经过很长的过程才显示一些数据。 我正在使用调度程序,因为被调用的方法在另一个线程中。 我还想在不冻结 UI 的情况下执行此过程,例如能够取消该过程并自由替换 window。
我的问题是 UI 根本没有更新(进度条,计算步骤)并且取消按钮直到计算结束才起作用。 事实上,o不知道如何立即取消一般序列,即使挂起的长过程没有完成。
我不是 100% 确定使用正确的方法,有没有人有更好的解决方案或任何建议?
例如
public void CalculationCommand()
{
var bkw = new BackgroundWorker()
bkw.DoWork += Work;
bkw.RunWorkerAsync(Dispatcher.CurrentDispatcher);
}
public void Work(object sender, DoWorkEventArgs e)
{
var dispatcher = e.Argument as Dispatcher;
var dispatcherPriority = DispatcherPriority.Background;
Action action;
action = () =>
{
UpdateStatut(StatutsInformation.Pending);
};
dispatcher.BeginInvoke(action, dispatcherPriority);
ViewModel1 viewModel1 = null;
action = () =>
{
UpdateProgress(10, "Sampling calculations");
viewModel1 = Application.GetEchantillonnage();//Long process
};
dispatcher.BeginInvoke(action, dispatcherPriority);
List<double> lengthList = null;
action = () =>
{
UpdateProgress(20, "Length calculations");
lengthList = AlgorithmLibrary.LengthCalculations(viewModel1);//Long process
};
dispatcher.BeginInvoke(action, dispatcherPriority);
ViewModel2 viewModel2 = null;
action = () =>
{
UpdateProgress(30, "Engine calculations");
viewModel2 = Application.GetEngine();//Long process
AlgorithmLibrary.EngineCalculations(viewModel2);//Long process
var FilteredLength = AlgorithmLibrary.LengthFilter(lengthList);//Long process
}; dispatcher.BeginInvoke(action, dispatcherPriority);
///... Others actions executed incrementing the progress value to 100%
action = () =>
{
UpdateStatut(StatutsInformation.Finished);
};
dispatcher.BeginInvoke(action, dispatcherPriority);
}
private void UpdateStatut(StatutsInformation statutInformation)
{
ViewModelLoading.StatutInformation = statutInformation;
}
private void UpdateProgress(int value, string label)
{
ViewModelLoading.Progress = value;
ViewModelLoading.Step = label;
}
谢谢
在方法 Work
中,您正在后台线程上执行。每次调用 dispatcher.BeginInvoke
时,传递给此方法的 action 将在 UI 线程[=23] 上执行=]。看看你现在在做什么?再看看这段代码
// Here, we are on a background thread
action = () =>
{
// This action is NOT executing yet! We are just defining it.
UpdateProgress(10, "Sampling calculations");
// This is going to execute on the thread that executes this action!
viewModel1 = Application.GetEchantillonnage();//Long process
};
// here, we are still on the background thread, but we are telling the
// dispatcher to marshall the action onto the UI thread to execute it!
dispatcher.BeginInvoke(action, dispatcherPriority);
您正在 UI 线程上进行长时间的 运行 工作:/
不过,解决方法很简单。只需将您的工作拉出来并将其保存在后台线程中即可。这是相同的代码,但按预期工作(除非您的代码中出现其他问题)
action = () => UpdateProgress(10, "Sampling calculations");
dispatcher.BeginInvoke(action, dispatcherPriority);
viewModel1 = Application.GetEchantillonnage();//Long process
您的代码不断进入后台线程以在 UI 线程上执行长 运行 任务。 Dispatcher.BeginInvoke 将委托编组回 UI 线程。
试试这个:
private void RunOnUI(Action uiAction, DispatcherPriority dispatcherPriority = DispatcherPriority.Background)
{
dispatcher.BeginInvoke(uiAction, dispatcherPriority);
}
public void Work(object sender, DoWorkEventArgs e)
{
var dispatcher = e.Argument as Dispatcher;
var dispatcherPriority = DispatcherPriority.Background;
Action action;
runOnUI(() =>
{
UpdateStatut(StatutsInformation.Pending);
});
ViewModel1 viewModel1 = null;
RunOnUI(() =>
{
UpdateProgress(10, "Sampling calculations");
});
viewModel1 = Application.GetEchantillonnage();//Long process
List<double> lengthList = null;
RunOnUI(() =>
{
UpdateProgress(20, "Length calculations");
});
lengthList = AlgorithmLibrary.LengthCalculations(viewModel1);//Long process
ViewModel2 viewModel2 = null;
RunOnUI(() =>
{
UpdateProgress(30, "Engine calculations");
};
viewModel2 = Application.GetEngine();//Long process
AlgorithmLibrary.EngineCalculations(viewModel2);//Long process
var FilteredLength = AlgorithmLibrary.LengthFilter(lengthList);//Long process
///... Others actions executed incrementing the progress value to 100%
RunOnUI(() =>
{
UpdateStatut(StatutsInformation.Finished);
});
}