视图模型中的计时器

发布于 2024-10-08 08:54:07 字数 2965 浏览 0 评论 0原文

我在外部程序集中有服务类,我使用 MEF 将此类注入到视图模型类中。我需要从视图模型中每 3-4 秒调用一次服务方法。

我从服务中获取新数据作为字典。该字典绑定到视图中的列表框。我需要刷新视图中的数据列表框。

在我的解决方案中,我使用 DispatcherTimer,但我是 calibur.micto 以及 MVVM 和 WPF 的绝对初学者。我不知道什么是适合我的情况的解决方案。因此,如果有人有预付款,我将不胜感激。

我的解决方案在这里:

[Export("MainScreen", typeof(IMainViewModel))]
    public class MainViewModel : Screen, IMainViewModel
    {

        [Import]
        private Service _service;//import with MEF from external assembly
        [Import]
        private Connection _conn;//import with MEF from external assembly

        //this dictionary is bind to the listbox in view
        private MyObservableDictionary<string, User> _users = null;

        //temp dictionry
        private MyObservableDictionary<string, User> _freshUsers = null;

        private int _selectedUserIndex;

        private DispatcherTimer _dispatcherTimer;


        public Account Account{ get; set;}

        public int SelectedUsersIndex
        {
            get { return _selectedUserIndex; }
            set
            {
                _selectedUserIndex = value;
                NotifyOfPropertyChange("SelectedUsersIndex");
            }
        }



        public MainViewModel()
        {
            _dispatcherTimer = new DispatcherTimer();
            _dispatcherTimer.Tick += DispatcherTimer_Tick;
            _dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
            _dispatcherTimer.Start();
        }


        //I get every 3-4 sec from server new JSON data and I need update  with this data listbox in view
       private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
        {
            //server ping, call service method
            Account.Ping = _service.Ping(Account);

            //Refresh data in dictionary
            _freshUsers = _service.LoadUsers(Account);
            _users.Clear();
            SelectedUsersIndex = 1;

            foreach (var freshUser in _freshUsers)
            {
                _users.Add(freshUser);
            }

            //check if you have new messanges
            if (Account.Ping.Rp > 0)
            {
                //load new messanges
                for (int i = 0; i < Account.Ping.Rp; i++)
                {
                    #region load rp
                    try
                    {
                        Rp message = _service.LoadRp(Account);

                        if (message != null)
                        {
                            //show messages
                        }
                    }
                    catch (Exception exception)
                    {
                        if (exception.Message == "You haven&#8217;t any messanged")
                        {

                        }
                        throw exception;// how handle show this exception in view?
                    }
                    #endregion
                }
            }
        }
    }

I have service class in external assembly, I inject this class in view model class with MEF. I need call service method every 3-4 seconds from view model.

I get from service new data as Dictionary. This Dictionary is bind to listbox in view. And I need refresh with this data listbox in view.

In my solution I use DispatcherTimer, but I am absolute begginer in calibur.micto also MVVM and WPF. I don’t know what is a suitable solution in my case. So if someone have advance I will be gratefull.

My solution is here:

[Export("MainScreen", typeof(IMainViewModel))]
    public class MainViewModel : Screen, IMainViewModel
    {

        [Import]
        private Service _service;//import with MEF from external assembly
        [Import]
        private Connection _conn;//import with MEF from external assembly

        //this dictionary is bind to the listbox in view
        private MyObservableDictionary<string, User> _users = null;

        //temp dictionry
        private MyObservableDictionary<string, User> _freshUsers = null;

        private int _selectedUserIndex;

        private DispatcherTimer _dispatcherTimer;


        public Account Account{ get; set;}

        public int SelectedUsersIndex
        {
            get { return _selectedUserIndex; }
            set
            {
                _selectedUserIndex = value;
                NotifyOfPropertyChange("SelectedUsersIndex");
            }
        }



        public MainViewModel()
        {
            _dispatcherTimer = new DispatcherTimer();
            _dispatcherTimer.Tick += DispatcherTimer_Tick;
            _dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
            _dispatcherTimer.Start();
        }


        //I get every 3-4 sec from server new JSON data and I need update  with this data listbox in view
       private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
        {
            //server ping, call service method
            Account.Ping = _service.Ping(Account);

            //Refresh data in dictionary
            _freshUsers = _service.LoadUsers(Account);
            _users.Clear();
            SelectedUsersIndex = 1;

            foreach (var freshUser in _freshUsers)
            {
                _users.Add(freshUser);
            }

            //check if you have new messanges
            if (Account.Ping.Rp > 0)
            {
                //load new messanges
                for (int i = 0; i < Account.Ping.Rp; i++)
                {
                    #region load rp
                    try
                    {
                        Rp message = _service.LoadRp(Account);

                        if (message != null)
                        {
                            //show messages
                        }
                    }
                    catch (Exception exception)
                    {
                        if (exception.Message == "You haven’t any messanged")
                        {

                        }
                        throw exception;// how handle show this exception in view?
                    }
                    #endregion
                }
            }
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

初见 2024-10-15 08:54:07

DispatcherTimer 正在您的 UI 线程上运行,因此当它运行您的检查时,您的 UI 可能会在 DispatcherTimer_Tick 消息运行时冻结。如果 DispatcherTimer_Tick 需要 2 秒才能运行,那么每 3 秒您就会将 UI 冻结 2 秒。用户不会喜欢这样。

所有服务调用都应该在非 UI 线程上完成,这样就不会锁定 UI,因此我建议使用计时器并执行如下操作:

public MainViewModel() 
{ 
   _stTimer = new System.Threading.Timer(Timer_Tick,null,3000,3000); 
   _dispatcher = Dispatcher.CurrentDispatcher;
} 

private void Timer_Tick(object sender)
{
   Account.Ping = _service.Ping(Account); 
   //Refresh data in dictionary 
   _freshUsers = _service.LoadUsers(Account); 
   _users.Clear(); 
   SelectedUsersIndex = 1; 

   foreach (var freshUser in _freshUsers) 
   { 
      _users.Add(freshUser); 
   } 

   for(int i=0;i<Account.Ping.Rp; i++)
   {
       //check if you have new messanges 
       if (Account.Ping.Rp > 0) 
       { 
           Rp message = _service.LoadRp(Account); 
           _messages.Add(message);
       } 
    }

    _dispatcher.BeginInvoke((Action)(()=>{OnPropertyChanged("Messages");}));
}

这里我们使用系统计时器来检查不同的线程,因此您的 UI 将不会受到任何处理的影响。当我们想要通知 UI 发生了更改时,我们可以使用 _dispatcher(我们在构造函数中创建的 UI 调度程序)来“BeginInvoke”UI 线程上的方法。

这将使您的应用程序显示得更快。一个好的经验法则是尽可能远离 Dispatcher 线程;仅当您使用 UI 执行某些操作时才使用它。所有其他处理都应该在后台线程上进行。

希望这有帮助

The DispatcherTimer is running on your UI thread so while it is running your check your UI will probably freeze while the DispatcherTimer_Tick message runs. If the DispatcherTimer_Tick takes 2 seconds to run then every 3 seconds you freeze the UI for 2 seconds. Users won't like that.

All service calls should be done on a non-UI thread so that you don't lock up the UI so I'd suggest using a timer and doing something like this:

public MainViewModel() 
{ 
   _stTimer = new System.Threading.Timer(Timer_Tick,null,3000,3000); 
   _dispatcher = Dispatcher.CurrentDispatcher;
} 

private void Timer_Tick(object sender)
{
   Account.Ping = _service.Ping(Account); 
   //Refresh data in dictionary 
   _freshUsers = _service.LoadUsers(Account); 
   _users.Clear(); 
   SelectedUsersIndex = 1; 

   foreach (var freshUser in _freshUsers) 
   { 
      _users.Add(freshUser); 
   } 

   for(int i=0;i<Account.Ping.Rp; i++)
   {
       //check if you have new messanges 
       if (Account.Ping.Rp > 0) 
       { 
           Rp message = _service.LoadRp(Account); 
           _messages.Add(message);
       } 
    }

    _dispatcher.BeginInvoke((Action)(()=>{OnPropertyChanged("Messages");}));
}

Here we're using a system timer to check for changes on a different thread, so your UI will be unaffected by any processing. When we want to notify the UI that a change has occured we can use the _dispatcher (the UI dispatcher we create in the constructor) to "BeginInvoke" a method on the UI thread.

This will make your app appear faster. A good rule of thumb is to keep off the Dispatcher thread as much as possible; only use it when you're doing something with the UI. All other processing should be on a background thread.

Hope this helps

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文