1

This is the first time I have to ask in this forum. I am developing my first WPF application that takes data from ASYNC methods to display whith a spinner while it is working.

I had no problems doing one (called CheckServices() that fills data in Labels, TextBlocks....), but I had an error doing a second method (called FillDataGrid(() that fills data in a DataGrid).

I come from web applications and I am not sure if I am doing it like in Ajax calls that I usually do.

My MainView:

public MainViewController()
{            
    InitializeComponent();
    InitializeElements();
    FillDataGrid(() =>
    {
        return new ItemService().ReadItemsByUser(SessionData.UserCertificate.User.DNI);
    });                
    CheckServices();
    Title = SessionData.AppData.AppName + " v" + SessionData.AppData.AppVersion;
    Show();            
}

This is the Method that works well:

async private void CheckServices()
{
    //Show spinner
    icoWorking.Visibility = Visibility.Visible;
    List<ServiceModel> services =//From other method
    Task<List<ServiceModel>> task = Task.Run(()=> {                
        foreach (ServiceModel ser in services)
        {
            //A proccess                
        }
        return services;
    });
    services = await task;
    // A process to asign data to view elements

    //Hide spinner
    icoWorking.Visibility = Visibility.Hidden;
}

This is the method that brokes the app:

async private void FillDataGrid(Func<List<ItemRepositoryDTO>> p)
{
    List<RepositoryModel> list = null;
    //Show spinner
    icoWorking.Visibility = Visibility.Visible;
    List<ItemRepositoryDTO> items = p();
    if (items != null)
    {  
        Task<List<RepositoryModel>> task = Task.Run(() =>
        {
            List<RepositoryModel> listAux = new List<RepositoryModel>();
            //A proccess with "items"
            return listAux;
        });

        list = await task;
       //Problematic sentence ****
        dgRepositoryItems.ItemsSource = list;
       //*****

    }
    //Hide spinner
    icoWorking.Visibility = Visibility.Hidden;
}

If I comment "the problematic sentence", it works well, else the error comes when the method ends (not when items are asigned to the DataGrid). If I dont use async methods it works well but the spinner do not show. Tried Task.WaitAll(t)/Task.WhenAll(t) + t.Result in MainWindow but that method always break the app without going througth "catch".

The XAML looks like this:

<DataGrid  CanUserAddRows="False" CanUserDeleteRows="False" CanUserReorderColumns="False" CanUserSortColumns="False" ItemsSource="{Binding RepositoryModel}"  x:Name="dgRepositoryItems" AutoGenerateColumns="False" BorderBrush="{x:Null}"  Margin="0,60,0,41" Background="#FFECECEC">
    <DataGrid.Resources>
        <Style TargetType="{x:Type DataGridColumnHeader}">
            <Setter Property="Background" Value="#FF50B262"/>
            <Setter Property="Foreground" Value="White"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
        </Style>
    </DataGrid.Resources>
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Nombre" IsReadOnly="True" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <StackPanel  Orientation="Horizontal">
                        <StackPanel.Resources>
                            <Style TargetType="{x:Type TextBlock}">
                                <Setter Property="Margin" Value="5,0,0,0"/>
                            </Style>
                        </StackPanel.Resources>
                        <fa:ImageAwesome Visibility="{Binding ShowRootPath}" VerticalAlignment="Bottom" Height="14" Icon="ArrowCircleOutlineRight" Foreground="Black"  />
                        <TextBlock Text="{Binding GridTab}" />
                        <fa:ImageAwesome VerticalAlignment="Bottom" Height="14" Icon="{Binding IconPath}" Foreground="Gray"  />
                        <TextBlock Text="{Binding Name}" />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <DataGridTextColumn IsReadOnly="True" Width="*" Header="Repositorio" Binding="{Binding Repository}" />
        <DataGridTemplateColumn Header="Estado" IsReadOnly="True" Width="*">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <StackPanel  Orientation="Horizontal">
                        <StackPanel.Resources>
                            <Style TargetType="{x:Type TextBlock}">
                                <Setter Property="Margin" Value="5,0,0,0"/>
                            </Style>
                        </StackPanel.Resources>
                        <fa:ImageAwesome VerticalAlignment="Bottom" Height="14" Icon="{Binding IconState}" Foreground="{Binding IconStateColor}"  />
                        <TextBlock Text="{Binding State}" />
                    </StackPanel>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Can someone tell me what I am doing wrong and a simple example that how should it be to do the same?

Thanks in advance

UPDATE

The problem seems to be other different thing: In the Task that prepares data to be inserted in the DataGrid, I was filling a field with class SolidColorBrush. It seems cannot be created in other thread than in the UI one. Solved using Brush instead SolidColorBrush. I found the solution here

Blockquote

D.E.P.
  • 11
  • 3
  • You can begin fixing things by not writing `void` async methods. You cannot await them and you will not get exceptions. Also they run in fire-and-forget manner which may not be what you always want (or ever want). – Crowcoder Feb 22 '18 at 11:45
  • 3
    Possible duplicate of [The calling thread cannot access this object because a different thread owns it](https://stackoverflow.com/questions/9732709/the-calling-thread-cannot-access-this-object-because-a-different-thread-owns-it) – Grx70 Feb 22 '18 at 12:00
  • what is the error message? – Marc Feb 22 '18 at 12:25
  • Changed the code using `Dispatcher.Invoke` but still breaks. Also changed MainWindow code to asign the source to datagrid in main thread using `Task t=Task.Run(FillDataGrid(....))..; Task.WhenAll(t); dgRepositoryItems.ItemsSource = t.Result;` and the Method Show() fails: "You must create DependencySource on the same thread as DependencyObject." – D.E.P. Feb 22 '18 at 13:42
  • Why if a method is working well, the other with the same system is not? – D.E.P. Feb 22 '18 at 13:48
  • @D.E.P. Application.Current.Dispatcher.Invoke – Rekshino Feb 22 '18 at 15:51
  • Hi again Thanks for your answers. I found the problem and it is about creating a class `SolidColorBrush` in a non UI thread to fill the icon `` After comment that XAML line, it works like it should (not with the best practices but it works). More info here: https://stackoverflow.com/questions/7865514/must-create-dependencysource-on-same-thread-as-dependencyobject – D.E.P. Feb 22 '18 at 16:06

0 Answers0