How to Asynchronously Load Data in a View Model?

1 Answer 2063 Views
Docking
Justin
Top achievements
Rank 2
Iron
Justin asked on 06 Dec 2021, 08:26 PM | edited on 06 Dec 2021, 08:29 PM

Hi. I'm trying to asynchronously load data in a ViewModel when the ViewModel is created. Today I am using Catel in my application for MVVM functionality. If the Control is of type Catel.UserControl then an overridden method InitializeAsync is automatically called when the control loads allowing me to async load data.

However, I am migrating this application to use Telerik Docking. For docking to work I need the controls to be of type RadPane or RadDocumentPane. Making this modification breaks Catel's InitializeAsync functionality. So I'm left searching for the best way to asynchronously load data in aTelerik RadPane/RadDocumentPane.

I might have found a working solution, but I wanted to check if there's a better way to do this. The solution I found is to add an interaction trigger that fires an async command on the RadPanes 'Loaded' event. https://newbedev.com/calling-async-method-to-load-data-in-constructor-of-viewmodel-has-a-warning

Edit: I should note that I'm using the Telerik DockingPrism7 sample.

Current XAML with Catel:

<catel:UserControl xmlns:catel="http://schemas.catelproject.com">
    <Grid>
        <telerik:RadGridView ItemsSource="{Binding Model}" />
    </Grid>
</catel:UserControl>

 

ViewModel:

public class ObjectViewModel : Catel.MVVM.ViewModelBase
{
    /// <summary>
    /// Create model and get all tenants.
    /// </summary>
    /// <param name="tenantBL"></param>
    /// <param name="security"></param>
    public ObjectViewModel(BL bl) : base()
    {
    }

    /// <summary>
    /// Initialize control. Automatically called if Control is of type Catel.UserControl.
    /// </summary>
    /// <returns>Task</returns>
    protected override async Task InitializeAsync()
    {
        await base.InitializeAsync();

        await LoadDataFromBL();
    }

    /// <summary>
    /// Load all data from the business logic.
    /// </summary>
    /// <returns>Task</returns>
    private async Task LoadDataFromBL()
    {
        await DoSomething();
    }
}

1 Answer, 1 is accepted

Sort by
1
Dilyan Traykov
Telerik team
answered on 09 Dec 2021, 10:19 AM

Hi Justin,

Thank you for the provided code snippets.

I'm not very familiar with the Catel platform, however, would it not be possible to use a UserControl as the content of the RadPane/RadDocumentPane and have the same InitializeAsync logic invoked?

Otherwise, I see nothing wrong with executing the async command in the panes' Loaded event. If you find it more convenient, you can use the EventToCommandBehavior helper class to bind the event to the command.

I hope you find this information helpful. Please let me know if any further questions or concerns arise.

Regards,
Dilyan Traykov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

Justin
Top achievements
Rank 2
Iron
commented on 09 Dec 2021, 07:25 PM

Dilyan, thanks for the comment. I tried making the control of type catel:UserControl, but L55 at DockingActivePaneSyncBehavior.cs gives me an error since the control is not of type RadPane.

I also tried to put the catel:UserControl in the RadDocumentPane, but that throws an exception when creating the view. XAML for this is below.

<telerik:RadDocumentPane>
    <catel:UserControl></catel:UserControl>
</telerik:RadDocumentPane>

 

would it not be possible to use a UserControl as the content of the RadPane/RadDocumentPane

How do I accomplish this? It's almost as if I need to create a factory where I can pass any type of control and the factory will create a new RadDocumentPane and add it to the dock.

Dilyan Traykov
Telerik team
commented on 14 Dec 2021, 02:00 PM

Hi Justin,
My idea was precisely to place the UserControl as the content of the pane as you shared in the code snippet above.
Can you please specify what exception is thrown in this case?
If possible, please share a small sample project which demonstrates your setup and requirement and I will gladly try to suggest a viable solution tailored to your particular scenario.
Justin
Top achievements
Rank 2
Iron
commented on 15 Dec 2021, 04:52 PM

Thanks for the reply.

I have attached an example. The example is based on the Telerik sample from github: xaml-sdk/Docking/DockingPrism7 at master · telerik/xaml-sdk (github.com)

Changes:

  • Added the nuget package for Catel
  • Made XAML modification as noted above in `NewControlView`

To load the view click the 'New Control' button. Then the exception occurs.

 

Note: I might have found a way around this using a factory to create RadDocumentPane's. In the case that what I am trying to do is not achievable.

 

Exception:

System.Windows.Markup.XamlParseException: ''The invocation of the constructor on type 'Catel.Windows.Controls.UserControl' that matches the specified binding constraints threw an exception.' Line number '14' and line position '10'.'

Inner Exception:

NotSupportedException: The view model of the view 'UserControl' could not be resolved. Make sure to customize the IViewModelLocator or register the view and view model manually.

 

 

 

Dilyan Traykov
Telerik team
commented on 20 Dec 2021, 10:31 AM

Hello Justin,

The reason for this exception is that with the current setup a generic UserControl is defined (which does not have a specific class name) and thus, the ViewModelLocator does not know which viewmodel to use.

What I can suggest is to extract the view which the RadDocumentPane will use in a separate user control, for example, NewUserControlView, and create a separate viewmodel for it - NewUserControlViewModel.

There may be a cleaner approach for achieving this, and you can forward your inquiry to the Catel repository to get alternative suggestions. You may also find this article helpful: Introduction to the nested user controls problem.

Nonetheless, I've attached the modified project using my previous suggestion to prove such a setup is possible. I do hope you find this a good starting point for achieving the desired result.

Justin
Top achievements
Rank 2
Iron
commented on 20 Dec 2021, 02:11 PM

Dilyan, thanks for digging into this for me. I should be able to take this and run with it to get a working solution.
Dilyan Traykov
Telerik team
commented on 21 Dec 2021, 04:39 PM

I'm glad to hear that you found this helpful. Do let me know if I can further assist you with anything else.
Tags
Docking
Asked by
Justin
Top achievements
Rank 2
Iron
Answers by
Dilyan Traykov
Telerik team
Share this question
or