Implementing Periodic Process in UWP, MVVM

1

I'm building an small App that gather data from website. and I managed to gather data.

Following picture depicts what my app does.

enter image description here

when I click the button "시작", my App get html of the specific page, and get data from it. This works are done in ViewModel class, and I bind the result data to ViewPage, observing mvvm pattern I think.

Following source code shows logic that I wrote for my program.

public class MainPageViewModel : Observable
{

    public SiseDataList dataList { get; set; } = new SiseDataList();

    public MainPageViewModel()
    {
         ButtonClick = new RelayCommand(Click);
    }

    public async void Click()
    {
        // ... omitted .. 
        foreach (var i in tmp_list) 
        {
            if (dataList.Count == 0)
            {
                dataList.Add(i);
            }
            else if (dataList.Last().date < i.date)
            {
                dataList.Add(i);
            }
        }

        OnPropertyChanged("data");
    }
    public RelayCommand ButtonClick { get; set; }
}

I bind data_list data to viewPage, GridView.

Now, I think I can say what I want to implement.

If I click "시작" button of my App, I want to execute Click function every 20 seconds.

Luckily, I could easily find the document about periodic work in UWP. Link: create-a-periodic-work-item

So, I tried to implement that functionality, but I failed.
First I tried the following:

public MainPageViewModel()
{
     ButtonClick = new RelayCommand(Regist);
}

public async void Regist()
{
    TimeSpan period = TimeSpan.FromSeconds(60);

    ThreadPoolTimer PeriodicTimer = ThreadPoolTimer.CreatePeriodicTimer(async (source) =>
    {
        Dispatcher.RunAsync(CoreDispatcherPriority.High,
            () =>
            {
                // UI components can be accessed within this scope.
                Click();
            });

    }, period);

}

public async void Click() //...omitted.. 

I put Click() function in Dispatcher, because I think Click() function call OnPropertyChanged() from INotifyPropertyChanged interface.
but the Intellisense tells me, It can't find any Dispatcher name in context.
So I just right clicked on it and clicked refactoring menu, and then, That sentence becomes System.ServiceModel.Dispatcher.RunAsync...
but It does not work. I found CoreDispatcher class in documents so I used it. I wrote CoreDispatcher.RunAsync(....), But It is not a static class I can't use that syntax.

I googled and I tried Window.Current.Dispatcher.RunAsync(....) but it return exception "Windows.UI.Xaml.Windows.Current.get returns null".

finally, I tried following code.

 TimeSpan period = TimeSpan.FromSeconds(60);

 ThreadPoolTimer PeriodicTimer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
 {
     Click();
 }, period);

But program crashed while executing Click function add element at dataList List, I think other thread(kind of UI thread...?) is watching or holding that list as I bind it to view Page. And It returns exception "Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)."

How can I periodically execute a specific function in UWP?

c#
mvvm
uwp
scheduled-tasks
asked on Stack Overflow Oct 7, 2018 by Jeong Yo Han • edited Oct 7, 2018 by Martin Zikmund

1 Answer

2

You need to use Dispatcher of the application (which matches the main window's dispatcher):

Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
        CoreDispatcherPriority.High,
        () =>
        {
            // UI components can be accessed within this scope.
            Click();
        });

The reason your approach did not work is that it is not possible to call Window.Current.Dispatcher from non-UI thread, as Window.Current is only accessible on UI thread. However Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher can be accessed from anywhere.

answered on Stack Overflow Oct 7, 2018 by Martin Zikmund • edited Oct 7, 2018 by Martin Zikmund

User contributions licensed under CC BY-SA 3.0