Task.Factory.StartNew and blocking UI

0

I have a problem. I'm in a WPF application and I want to do a SQL query in the background, all this I already have, the problem that at the time of making the "query", the UI is branded and I do not know why, if I'm doing it in another thread .

This code here works, but the UI calls me. On the other hand, if we erase the FOR and put a Thread.Sleep (5000), it works perfectly. I'm using NET4.0

    private void Buscar()
    {

        ShowMessage = "Buscando...";

        IsBusy = true;

        ShowProgressRing = true;

        Task.Factory.StartNew(() =>
        {

            //Thread.Sleep(5000); // Simulate SQL query

            Articulos = new ObservableCollection<Articulo>();

            for (var i = 0; i < 500; i++)
            {
                Articulos.Add(new Articulo
                {
                    Codigo = i.ToString(),
                    NombreDelArticulo = "PRODUCT NAME",
                    PrecioFinal = 1m
                });
            }

            IsBusy = false;

        }).ContinueWith(x =>
        {


        }, TaskScheduler.FromCurrentSynchronizationContext());

    }
    
asked by avechuche 27.08.2016 в 22:16
source

2 answers

1

I have tested your code in a WPF targeting NET Framework 4 project in VS 2015 update 4, and I do not know what you mean by "ticking" the UI, but what happens is that the user does not know that the search is over because no code is executed in the Continuation Action. So at the end of the search, everything continues the same and it seems that nothing has been done.

As you have coded it, the Continuation Action is executed in the thread of the UI when finishing the search, so there you can change the graphic elements, and at least you would have to show the found articles linking the collection Articles to a Graphic element such as a ListView or a GridView.

For example:

 private void Buscar()
    {

        ShowMessage = "Buscando...";

        IsBusy = true;

        ShowProgressRing = true;

        Task.Factory.StartNew(() =>
        {

            //Thread.Sleep(5000); // Simulate SQL query

            Articulos = new ObservableCollection<Articulo>();

            for (var i = 0; i < 500; i++)
            {
                Articulos.Add(new Articulo
                {
                    Codigo = i.ToString(),
                    NombreDelArticulo = "PRODUCT NAME",
                    PrecioFinal = 1m
                });
            }

            IsBusy = false;

        }).ContinueWith(x =>
        {

            MessageBox.Show("Búsqueda finalizada, pulse para ver los artículos encontrados");
            ArticulosLW.ItemsSource = Articulos;

        }, TaskScheduler.FromCurrentSynchronizationContext());

    }
    
answered by 13.09.2016 в 15:51
0

What is happening to you, is that you are modifying within a task, an object that did not create that task, in this case the object Articles, which must be a property of the Window object.

This is fixed, creating a task that creates an object like the one you need (in this case, an ObservableCollection and when it finishes, it returns it and urges it to the one you need to feed in. With async / await, it's very simple.

Here is your modified example:

private async void Buscar()
{

    ShowMessage = "Buscando...";

    IsBusy = true;

    ShowProgressRing = true;

    Articulos = await Task<ObservableCollection<Articulo>>.Run(() =>
    {

        //Thread.Sleep(5000); // Simulate SQL query

        var newArticulos = new ObservableCollection<Articulo>();

        for (var i = 0; i < 500; i++)
        {
            Articulos.Add(new Articulo
            {
                Codigo = i.ToString(),
                NombreDelArticulo = "PRODUCT NAME",
                PrecioFinal = 1m
            });
        }

        return newArticulos;

    });

    IsBusy = false;

    MessageBox.Show("Búsqueda finalizada, pulse para ver los artículos encontrados");
    ArticulosLW.ItemsSource = Articulos;


}
    
answered by 08.11.2016 в 00:30