0
votes

I am currently building an UWP application which should control several jobs, where each job could be updated from a background thread. Currently, I am using an ObservableCollection in a static "Core-Class" in which all jobs are stored (see question 1). This list is bound using a property in the view model of my view:

        public ObservableCollection<JobBase> Jobs
        {
            get
            {
                 return Core.Jobs;
            }
            set
            {
                Core.Jobs = value;
            }
        }

The list view's ItemsSource is bound to this property in my view model. I am using a custom ListView.ItemTemplate which uses a DataTemplate linked to my Job-class to display the information for each job:

<ListView
    x:Name="JobsListView"
    Grid.Row="1"
    ItemsSource="{x:Bind ViewModel.Jobs, Mode=OneWay}"
    SelectionMode="Single"
    IsItemClickEnabled="True"
    SelectedItem="{x:Bind ViewModel.RunningJob, Mode=TwoWay}">
        <ListView.ItemTemplate>
            <DataTemplate x:DataType="lib:JobBase">
                <Grid Margin="0,12,0,12" Height="52">
                    [...]
                    <TextBlock FontSize="12" Text="{x:Bind Progress, Mode=OneWay}" Margin="4,0,0,0" />
                    [...]
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

Some thoughts about this construct:

1) I think using an ObservableCollection in my static "background" Core-Class is not beautiful. I could change this to a normal List and do a cast to an ObservableCollection in the property of my list view. However, I will need some events when new jobs are added (or old ones deleted) in order to update my ObservableCollection which is bound the to the ListView. Is this the preferred implementation?

2) As soon as the progress of a certain job is updated (from within a background thread), I cannot show those updates in the list view. Even if I implement events for this, I have no clue how to update the binding of a certain item within my list view?

3) I could implement the INotifyPropertyChanged interface in my Job class, but I think this would not be a beautiful implementation either. In addition, I am raising exceptions as I cannot update my GUI from a background thread?

As you see, I am looking for a "professional" implementation on this issue. Therefore, I would prefer a solution which uses bindings and avoids a complete reloading of the whole job list if only a single item is updated.

I am really looking forward for your implementation tips :-)

1

1 Answers

0
votes

You should not be replacing the instance of the object being bound to ItemsSource. Instead, you'll need to modify the contents of the list. You can replace the ItemsSource if you choose, but this can lead to serious heap fragmentation and performance problems.

To update the UI thread, use CoreDispatcher.RunAsync to get back on the UI thread from a thread that could potentially be in the background https://docs.microsoft.com/en-us/uwp/api/windows.ui.core.coredispatcher.runasync?view=winrt-18362

await _coreDispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
    this.Bindings.Update();
});

If you need to just update one item at a time, ObservableCollection could be ideal, especially when the List includes objects which implement INotifyPropertyChanged. If instead you prefer to update several objects at once you'd set the binding to OneTime then use Bindings.Update() to update all the bindings in the ListView at once. This documentation can help to provide more info about optimizing your ListView. https://docs.microsoft.com/en-us/windows/uwp/debug-test-perf/optimize-gridview-and-listview

ObservableCollection isn't necessary. There are other mechanisms of data binding if you prefer. For more on data bindings, see https://docs.microsoft.com/en-us/windows/uwp/data-binding/data-binding-in-depth