-1

I have a code part where I call some XML data from a server. Sometimes there is an error with the network or the server itself. So I need some error handling. For that I installed the AwesomeFonts.WPF and created a simple

    <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>

That should show a loading animation of a spinning icon. Now I wanted to do something like

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

Now I know of the dispatching problems of WPF and tried already something like this

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

or something like this

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

On this one I really get the Panel visible, but the animation stopped.
And I wanted to let a timer run, so that I can shorten the timeout of the server. I wanted to do something more like:
1. Show animation
2. Start timer
3. Call the server
4. Count to 10
5. If I dont get the answer until 10, then show an error message, else show the result
6. Hide the waiting animation.

Has someone an idea how to achieve this?

Marcel Grüger
  • 885
  • 1
  • 9
  • 25
  • 2
    Make your `GetProductList()` async, preferably by using an async webrequest (HttpClient), second choice using Task.Run(). – H H Oct 30 '17 at 15:16

1 Answers1

2

You should execute the GetProductList method on a background thread.

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;
}

That's the important part because the UI thread cannot both process input event and execute your method at the same time.

You might also start a timer if you want to. Something like this:

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;
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Yes, but only because we don't know about GetProductList(). If it was able to take a CancellationToken the whole Timer piece could be dropped. Task.Run() is also a stop gap. – H H Oct 31 '17 at 07:56
  • The solution worked really good. I should look once again in this whole task await thing... still havn't completly understood it till now. – Marcel Grüger Nov 02 '17 at 10:21