C# WPF - 按钮单击的长时间操作
Posted
技术标签:
【中文标题】C# WPF - 按钮单击的长时间操作【英文标题】:C# WPF - Long Operation On Button Click 【发布时间】:2015-10-08 20:13:51 【问题描述】:我有Button
,它在点击时调用另一个方法。
另一种方法执行可能需要很长时间的操作...
所以我想创建一个Label
,它出现在操作开始并告诉用户等待,操作完成后,Label
会消失。唯一的问题是,因为Button
是一个UI
元素(这就是我认为的原因),所以在Button
点击内更改Label
的调用只有在Button
点击之后才会激活完成...(所以基本上Label
在点击之前是不可见的,并且在点击期间无法更改,所以它保持这种状态)。
这是我的代码:
private void SearchButtonActions()
UI.InvokeA(() => lstFiles.ItemsSource = FDItems);
bool SearchAndListing = false;
//UI.InvokeA(() => lblWait.Height = double.NaN);
//UI.InvokeA(() => lblWait.Visibility = Visibility.Visible);
//UI.InvokeA(() => lblWait.Content = "Search Started...");
int index = cbTypes.SelectedIndex;
string selecteditem = cbSearchOption.SelectedItem.ToString();
SearchAndListing = FD.Search(index, selecteditem);
FDItems = new ObservableCollection<Item>(FD.Items);
//UI.InvokeA(() => lblWait.Height = 0);
//UI.InvokeA(() => lblWait.Visibility = Visibility.Hidden);
//UI.InvokeA(() => lblWait.Content = "Search Ended.");
if (SearchAndListing)
UI.InvokeA(() => lstFiles.ItemsSource = FDItems);
UI.InvokeA(() => lblCount.Content = string.Format("Items: 0", FDItems.Count));
我说的是改变lblWait
的方法...
顺便说一句:UI.Invoke
- 是Dispatcher.Current.InvokeAsync(Action)
的快捷方式
我尝试过使用Tasks
、BackGroundWorker
,并将UI.Invoke
更改为Invoke
(synchronically
而不是asynchronically
),但都没有成功...
有人可以帮忙吗?
【问题讨论】:
使用 task.run 和进度条 【参考方案1】:-
单击按钮后立即显示“请稍候标签”。
执行你的长操作:
FD.Search(index, selecteditem);
in async Task.Run()
长操作完成后使用ContinueWith()
隐藏标签。
private void SearchButtonActions()
lblWait.Visibility = Visibility.Visible;
Task.Run(() =>
return FD.Search(index, selecteditem);
).ContinueWith((Task<bool> task) =>
Dispatcher.Invoke(() =>
FDItems = new ObservableCollection<Item>(FD.Items));
lblWait.Visibility = Visibility.Hidden;
);
);
如果您需要 ContinueWith()
块中某处的 FD.Search()
的结果,请使用 task.Result
检索它。
【讨论】:
“System.InvalidOperationException”类型的异常发生在 WindowsBase.dll 中,但未在用户代码中处理附加信息:调用线程无法访问此对象,因为不同的线程拥有它。 该异常只是意味着您必须使用调度程序来调用引发异常的方法。 UI 线程拥有所有 WPF 控件。任务在不同的线程上运行。 我修复了这个异常,但我遇到了另一个问题......我认为由于某种原因,第二个甚至第一个任务没有被执行,因为标签显示但随后它卡住了......甚至如果在操作的情况下它非常快......(它应该在操作完成后停留)...... @David47 嗯,好的。有什么办法可以让我看看你的项目吗?我认为这可能是一个简单的问题,我只是没有了解所有上下文。 你有Skype吗?我们可以在那里进行私人聊天,我可以向您发送您需要的任何内容...(加我 dudushnaider)【参考方案2】:我之前遇到过这个问题,直到现在才考虑过。
您的论点是正确的,UI 线程当前正在运行 Click 方法,因此它很忙,不会运行其他任何东西。
即使在使用调度程序时,它仍在执行 click 方法,因此 ui 线程会弹出下一个委托以仅在完成后运行。
所以这行不通:
lbl.Visibility = Visibility.Visible;
Thread.Sleep(3000);
这是行不通的:
Dispatcher.Invoke(() => lbl.Visibility = Visibility.Visible);
Dispatcher.Invoke(() => Thread.Sleep(3000));
可行的是从后台线程调度 ui 操作。
XAML:
<StackPanel>
<Button Click="Button_Click" Content="Click"/>
<Label x:Name="lbl" Content="Label" Visibility="Hidden" Foreground="Red" FontSize="22" HorizontalAlignment="Center"/>
</StackPanel>
CS:
private async void Button_Click(object sender, RoutedEventArgs e)
await Dispatcher.InvokeAsync(() =>
Debug.WriteLine("Visibility");
lbl.Visibility = Visibility.Visible;
);
await Task.Run(() =>
return Dispatcher.InvokeAsync(() => Thread.Sleep(3000));
);
仅供参考:您可能想知道为什么我不使用调度程序将 Visibility 值传播到 UI 线程。这是因为每个 DispatcherObject(我们从 DispatcherObject 派生的 DependencyObject)都将执行传播到它关联的 Dispatcher。
【讨论】:
我已尝试按照您在此处告诉我的方式对其进行修改...但效果不佳...如何向您展示新代码? (这里说太长了……) 你能在谷歌文档上与我分享吗? eranotz50@gmail.com 明天会看到,晚安 我会将文档发送到您的邮箱 如果有其他人想看这里的链接: docs.google.com/document/d/…以上是关于C# WPF - 按钮单击的长时间操作的主要内容,如果未能解决你的问题,请参考以下文章