刷新Windows应用商店中的数据(MVVM模式)

时间:2014-01-05 12:17:57

标签: c# mvvm windows-8 windows-store

我正在使用C#/ xaml开发一个带有MVVM模式的Windows 8商店应用程序。 我想在我提出this的搜索后每隔30秒自动刷新一个页面,但是如何将其实现到MVVM页面?

编辑:截至查理的回答,我想出了这个:

    var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
            var period = TimeSpan.FromSeconds(30);

            var timer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
             {

                await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                 {
                     RefreshOrdersList();
                 });
             }, period);

但VS编译器会标记出错误'在dispatcher.RunAsync()函数下:"' await'运算符只能在异步lambda表达式中使用"。当我删除' await'关键字应用程序运行时带有警告说"因为没有等待此调用,当前方法的执行在呼叫完成之前继续,请考虑应用“等待”#39;操作员调用结果"。

RefreshOrdersList函数 - 从WCF服务中获取所有订单和详细信息:

     private async void RefreshOrdersList()
    {

        var orders = await proxy.GetAllOrdersAsync();

        IList<OrderCart> orderModel = new List<OrderCart>();
        foreach (var order in orders)
        {
            OrderCart oc = new OrderCart { Id = order.Id, FullPrice = Convert.ToDouble(order.Total), TableId = order.TableId, IsDone = false, OrderTime = (DateTime)order.StartOrderTime };
            order.OrderDetails = await proxy.GetOrderDetailsByOrderIdAsync(order.Id);
            oc.OrderCartItems = new ObservableCollection<OrderCartItem>();
            foreach (var orderDetail in order.OrderDetails)
            {
                var course = await proxy.GetCourseByIdAsync(orderDetail.CourseId);
                OrderCartItem oci = new OrderCartItem { Quantity = orderDetail.Amount, Course = new Course(course) };
                oc.OrderCartItems.Add(oci);
            }
            orderModel.Add(oc);
        }

        var sortOrder = orderModel.OrderByDescending(x => x.Id);

        Items = new ObservableCollection<OrderCartViewModel>(sortOrder.
                                                                    Select(o => new OrderCartViewModel(o))
                                                                    .ToList());

项目属性:

       public ObservableCollection<OrderCartViewModel> Items
    {
        get { return _items; }

        private set { SetProperty(ref _items, value); }
    }

任何??

2 个答案:

答案 0 :(得分:1)

在UI类型(控件等)上找到调度程序,它的工作是同步到UI线程,因此您只能在视图中找到它。

是否有任何理由需要重新加载整个视图?

如果您正在使用MVVM模式,则可以在viewmodel中异步完成工作,然后按照惯例更新属性。

e.g。

class SomeViewModel
{
    IEnumerable<Results> Results { get; set; } // Obviously this would actually need to raise PropertyChanged from INotifyPropertyChanged in order to refresh any bindings

    public SomeViewModel()
    {
        var period = TimeSpan.FromMinutes(1);

        var timer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
        {
             // do your query/work here
             DoSomeWorkAsync();
        }, 
        period);
    }

    void DoSomeWorkAsync()
    {
        // Get the data
        someService.GetResults((result) => { Results = result.Data; });
    }
}

绑定系统将负责UI更新。我假设您只想转到数据源(可能是一个Web服务?)并且每30秒获得一次新结果,您需要的不仅仅是数据/绑定更新吗?

免责声明:未对此进行测试,您还需要了解线程池工作项中抛出的异常并正确处理

编辑:回答您关于绑定系统的问题

WPF / RT / SL绑定系统查找实现某些接口的数据源 - 其中一个是INotifyPropertyChanged。只要您绑定的数据源实现了这一点(在这种情况下,您的数据源是viewmodel),并且当它发生更改时为属性引发PropertyChanged事件,绑定系统将知道刷新

我在Visual Studio中有一个代码片段(实际上是Resharper,因为它工作得更好)为我写了属性 - 我认为VS中包含一个但它应该看起来像这样:

private int _someInt;
public int SomeInt
{
    get { return _someInt; }
    set 
    {
        if(_someInt != value)
        {
            _someInt = value;
            // Helper function in the class which checks to see if propertychanged has any subscribers
            OnPropertyChanged("_someInt"); 
        }
    }
}

注意:使用表达式代替“魔术字符串”或使用新的语言功能,可以更好地实现此功能。如果您使用的是最新的c#版本,则添加CallerMemberName属性意味着您无需指定属性名称

编辑2:好的,完整的示例可能如下所示

public class SomeViewModel : INotifyPropertyChanged
{
    #region Properties (that support INotifyPropertyChanged)

    private IEnumerable<Result> _results;
    public IEnumerable<Result> Results
    {
        get
        {
            return _results;
        }
        set
        {
            if (value != _results)
            {
                _results = value;
                OnPropertyChanged("Results");
            }
        }
    }

    #endregion

    // A reference to the service that will get some data
    private IDataService _dataService;

    public SomeViewModel(IDataService dataService)
    {
        _dataService = dataService;

        var period = TimeSpan.FromMinutes(1);

        var timer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
        {
            // do your query/work here
            GetData();
        },
        period);
    }

    #region Data fetch method

    /// <summary>
    /// Method to get some data - waits on a service to return some results
    /// </summary>
    void GetData()
    {
        // Get the data
        _dataService.GetResults((result) => 
        { 
            // Try this instead
            Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.Invoke(() => {
            Results = result.Data; }
        });
    }

    #endregion

    #region INotifyPropertyChanged

    // Note: usually most MVVM frameworks have a base class which implements the INPC interface for you (such as PropertyChangedBase in Caliburn Micro)
    // so it might be worth fishing around in your framework for it if you are using one.. If you aren't using a framework then you are a braver man than me
    // start using one now!

    /// <summary>
    /// The property changed event
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// The helper function to raise the event
    /// </summary>
    /// <param name="propertyName">Name of the property that changed (to tell the binding system which control to update on screen based on bindings)</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

编辑:更新上面的代码。如果您仍然无法掌握调度员,请告诉我

答案 1 :(得分:1)

只需添加'async'关键字var timer = ThreadPoolTimer.CreatePeriodicTimer( async (source)=>,并且未检测到任何错误或警告:

   var dispatcher = CoreApplication.MainView.CoreWindow.Dispatcher;
        var period = TimeSpan.FromSeconds(30);

        var timer = ThreadPoolTimer.CreatePeriodicTimer( async (source) =>
         {

            await dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
             {
                 RefreshOrdersList();
             });
         }, period);