我正在使用Xamarin.forms
(PCL
),我需要每隔几秒钟刷新/更新内容页面及其数据。数据是从API
中的viewmodel
检索的。
是否有任何方法或处理程序可以定期在Get Api
内定期调用page.xaml.cs
,例如:
methodRunPeriodically()
{
userdata = await UserService.GetUserasync(_UserViewModel.EmployeeId);
}
答案 0 :(得分:9)
Xamarin.Forms有一个用于启动计时器的API,您可能会发现它对此有用,记录为here。
Device.StartTimer (TimeSpan.FromSeconds(10), () => {
// If you want to update UI, make sure its on the on the main thread.
// Otherwise, you can remove the BeginInvokeOnMainThread
Device.BeginInvokeOnMainThread(() => methodRunPeriodically());
return shouldRunAgain;
});
答案 1 :(得分:7)
根据上述问题中的代码,您可以确保:
您的userdata对象实现IPropertyChange,如下所示:
//Other usings skipped for brevity
...
...
using System.ComponentModel;
using System.Runtime.CompilerServices;
// This is a simple user class that
// implements the IPropertyChange interface.
public class DemoUser : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private string userName = string.Empty;
private string phoneNumber = string.Empty;
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public DemoUser()
{
}
public string Id { get; set; }
public string UserName
{
get
{
return this.userName;
}
set
{
if (value != this.userName)
{
this.userName = value;
NotifyPropertyChanged();
}
}
}
public string PhoneNumber
{
get
{
return this.phoneNumber;
}
set
{
if (value != this.phoneNumber)
{
this.phoneNumber = value;
NotifyPropertyChanged();
}
}
}
}
在您的ContentPage中,您尝试以下操作(我稍微修改了上面的其他代码):
public class UserPage : ContentPage
{
private DemoUser demoUser;
private int intervalInSeconds;
public UserPage()
{
//Assuming this is a XAML Page....
InitializeComponent();
}
public UserPage(DemoUser demoUser, int intervalInSeconds = 10) : this()
{
this.demoUser = demoUser;
this.intervalInSeconds = intervalInSeconds;
this.BindingContext = this.demoUser;
Device.StartTimer(TimeSpan.FromSeconds(this.intervalInSeconds), () =>
{
Device.BeginInvokeOnMainThread(() => refreshDemoUser());
return true;
});
}
private async void refreshDemoUser()
{
this.demoUser = await getDemoUserById(this.demoUser.Id);
}
}
答案 2 :(得分:2)
您应该将UI绑定到ViewModel中的属性,然后适当地设置这些属性。调用OnPropertyChanged()
将触发Xamarin.Forms根据绑定属性更新UI。如下所示:
//Code in Page
public class MyPage : ContentPage
{
public MyPage()
{
var entry = new Entry();
BindingContext = new MyViewModel();
entry.SetBinding<MyViewModel>(Entry.TextProperty, vm=>vm.EntryText);
Content = entry;
}
}
//Code in ViewModel
public class MyViewModel() : INotifyPropertyChanged
{
public MyViewModel()
{
Task.Factory.StartNew(()=> methodRunPeriodically());
}
string entryText;
public string EntryText
{
get { return entryText; }
set
{
if(entryText == value)
return;
entryText = value;
OnPropertyChanged();
}
}
bool shouldRun = true;
async Task methodRunPeriodically()
{
while(shouldRun)
{
userdata = await UserService.GetUserasync(_UserViewModel.EmployeeId);
EntryText = userdata.FirstName;
await Task.Delay(5000); //Run this every 5 seconds
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
在这种模式中,我们开始了一个长期运行的任务,它将在一个循环中运行。它每隔5秒刷新一次userData
,然后设置EntryText
属性。在我们的ViewModel中EntryText
属性的setter中,我们调用OnPropertyChanged()
,这将导致Xamarin.Forms更新UI。调用OnPropertyChanged()
会触发Xamarin.Forms将线程上下文从后台任务切换到UI线程,然后再返回后台任务。
我没有在XAML中写这个,但绑定几乎相同,除了条目如下:
<Entry Text={Binding EntryText}/>
@therealjohn答案也很好。您可以使用它代替我的while循环,如下所示:
bool shouldRun = true;
methodRunPeriodically()
{
Device.StartTimer(TimeSpan.FromSeconds(5), () =>
{
userdata = await UserService.GetUserasync(_UserViewModel.EmployeeId);
EntryText = userdata.FirstName;
return shouldRun;
});
}
答案 3 :(得分:1)
您可以执行以下操作,以便在10秒后运行任务。在true
中返回Device.StartTimer
将确保Timer
继续运行。此外,您希望确保在主线程上调用方法来更新UI:
public MyConstructor()
{
StartTimer();
}
private void StartTimer()
{
Device.StartTimer(System.TimeSpan.FromSeconds(10), () =>
{
Device.BeginInvokeOnMainThread(UpdateUserDataAsync);
return true;
});
}
private async void UpdateUserDataAsync()
{
userdata = await UserService.GetUserasync(_UserViewModel.EmployeeId);
}
如果您的API没有公开您可以订阅的EventHandler
,那么您需要按照上面示例中的说明进行操作。
答案 4 :(得分:0)
每秒更新一次UI:
Device.StartTimer(TimeSpan.FromMilliseconds(1000), loop2);
bool loop2()
{
Device.BeginInvokeOnMainThread(() => updateUI());
return true;
}
或:
Device.StartTimer(TimeSpan.FromMilliseconds(1000), loop2);
bool loop2()
{
Device.BeginInvokeOnMainThread(() => {
updateUI();
//more stuff;
});
return true;
}