【问题标题】:Again UI thread and a timer [duplicate]再次 UI 线程和一个计时器 [重复]
【发布时间】:2017-10-30 23:49:43
【问题描述】:

我有一个代码部分,我从服务器调用一些 XML 数据。有时网络或服务器本身存在错误。所以我需要一些错误处理。 为此,我安装了 AwesomeFonts.WPF 并创建了一个简单的

    <StackPanel Name="ErrorPanel" Height="200" Width="300" Visibility="Hidden" Canvas.Top="440" Canvas.Left="810" Panel.ZIndex="9999">
        <fa:ImageAwesome Icon="Spinner" Spin="True" Height="100" Width="100" />
        <TextBlock Text="data loading..." />
    </StackPanel>

这应该显示一个旋转图标的加载动画。现在我想做类似的事情

ErrorPanel.Visibility = Visibility.Visible;
mainPznItem.SubPzns = Communication.GetProductList(tempPznList);
ErrorPanel.Visibility = Visibility.Hidden;

现在我知道了 WPF 的调度问题,并且已经尝试过类似的方法

Application.Current.Dispatcher.Invoke(() => { ErrorPanel.Visibility = Visibility.Visible; });

或类似的东西

Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new 
ThreadStart(delegate
{
    ErrorPanel.Visibility = Visibility.Visible;
}));

在这个上,我确实可以看到面板,但动画停止了。
我想让一个计时器运行,这样我就可以缩短服务器的超时时间。我想做更多类似的事情:
1。显示动画
2。启动计时器
3。调用服务器
4。数到 10
5。如果我直到 10 点才得到答案,则显示错误消息,否则显示结果
6。隐藏等待动画。

有人知道如何实现这一点吗?

【问题讨论】:

  • 使您的GetProductList() 异步,最好使用异步网络请求 (HttpClient),其次选择使用 Task.Run()。

标签: c# wpf ui-thread


【解决方案1】:

您应该在后台线程上执行GetProductList 方法。

async void Click(object sender, RoutedEventArgs e)
{
    ErrorPanel.Visibility = Visibility.Visible;
    var products = await Task.Run(() => Communication.GetProductList(tempPznList));
    mainPznItem.SubPzns = products;
    ErrorPanel.Visibility = Visibility.Hidden;
}

这是重要的部分,因为 UI 线程不能同时处理输入事件和执行您的方法。

如果你愿意,你也可以启动一个计时器。像这样的:

DispatcherTimer _timer;
bool cancelled;

async void Click()
{
    if (_timer != null)
    {
        _timer.Stop();
        _timer.Dispose();
    }

    ErrorPanel.Visibility = Visibility.Visible;

    _timer = new DispatcherTimer();
    _timer.Interval = TimeSpan.FromSeconds(10);
    _timer.Tick += _timer_Tick;
    _timer.Start();

    var products = await Task.Run(() => Communication.GetProductList(tempPznList));
    _timer.Stop();
    if (!cancelled)
    {
        mainPznItem.SubPzns = products;
        ErrorPanel.Visibility = Visibility.Hidden;
    }
}

private void _timer_Tick(object sender, EventArgs e)
{
    MessageBox.Show("error...");

    _timer.Tick -= _timer_Tick;
    _timer.Stop();
    cancelled = true;
    ErrorPanel.Visibility = Visibility.Hidden;
}

【讨论】:

  • 是的,但这只是因为我们不知道 GetProductList()。如果它能够获取 CancellationToken,则可以丢弃整个 Timer 片段。 Task.Run() 也是一个权宜之计。
  • 该解决方案非常有效。我应该再看一遍这整个任务等待的东西......直到现在还没有完全理解它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-13
  • 1970-01-01
  • 2021-11-11
  • 2020-01-02
  • 1970-01-01
相关资源
最近更新 更多