我正在使用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); }
}
任何??
答案 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);