每隔几秒自动刷新或更新内容页面

时间:2017-01-10 17:22:48

标签: c# xamarin xamarin.forms

我正在使用Xamarin.formsPCL),我需要每隔几秒钟刷新/更新内容页面及其数据。数据是从API中的viewmodel检索的。

是否有任何方法或处理程序可以定期在Get Api内定期调用page.xaml.cs,例如:

methodRunPeriodically()
{
 userdata = await UserService.GetUserasync(_UserViewModel.EmployeeId);
}

5 个答案:

答案 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)

根据上述问题中的代码,您可以确保:

  1. 您的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();
                }
            }
        }
    }
    
  2. 在您的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;
    });
}

您可以使用原始iOSAndroid上的Device.StartTimer查看Forms源代码的功能。

答案 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;
        }