如何保证,视图模型属性更改它再次值之前已经绑定的看法? [英] How to ensure, ViewModel property is bound already on view before changing it value again?

查看:134
本文介绍了如何保证,视图模型属性更改它再次值之前已经绑定的看法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有是继案例:
视图模型有一个对象,它的变化非常快。 (通过不同的线程)

There is following case: ViewModel has an object which changes very fast. (via different threads)

查看通过 NotifyPropertyChanged 界面,但它似乎它的工作原理减缓和查看之前绑定新的价值和借鉴它,然后它改变多次因此错过一些值。

View gets informed via NotifyPropertyChanged interface but it seems it works to slow and before View bind new value and draw it then it changes more times therefore It misses some values.

我也试图绑定查看来排队,然后视图模型排队这和<$ C 。$ C>查看可通过出队吸取

I also tried to bind View to queue then ViewModel could Enqueue it and View could draw via dequeueing.

不幸的是另外一个问题出现了: RaisePropertyChanged(()=>之后;队列); 查看未告知,它被改变。

Unfortunately another problem occurred: after RaisePropertyChanged(() => queue); View is not informed that it was changed.

在这种情况下,在 INotifyPropertyChanged的接口的实现并没有奏效。

In such case the implementation of the INotifyPropertyChanged interface did not worked.

你有什么想法?

示例代码视图模型

public class ExamplaryViewModel
{
    public ExamplaryViewModel()
    {
        Messenger.Default.Register<NotificationMessage<Message>>(this, m => ProcessNotificationMessage(m.Content));
    }    

    public void ProcessNotificationMessage(Message message)
    {   
        MessageOftenBeingChanged = message;
        RaisePropertyChanged(() => MessageOftenBeingChanged );
    }
}



查看结合 MessageOftenBeingChanged

另一种选择是在意见建议准备快照:

Another option would be to prepare snapshot as was suggested in comments:

public void ProcessNotificationMessage(Message message)
{
    Messages.Enqueue(message);
    RaisePropertyChanged(() => Messages);
}



查看

<controls:RichTextBoxMonitor Messages="{Binding Messages} 

控制

public class BindableRichTextBox : RichTextBox
{

    public static readonly DependencyProperty MessagesProperty = DependencyProperty.Register("Messages",
     typeof(ConcurrentQueue<Message>), typeof(BindableRichTextBox ), new FrameworkPropertyMetadata(null, OnQueueChangedChanged));


    public ConcurrentQueue<Message> CyclicMessages
    {
        get { return (ConcurrentQueue<Message>)GetValue(MessagesProperty ); }

        set { SetValue(MessagesProperty , value); }

但随后,不幸的是, RaisePropertyChanged()方法不会触发的变化发生了。

but then, unfortunately the RaisePropertyChanged() method does not trigger that changes happened.

我计划在事件控制 OnQueueChangedChanged 尝试出队,只是画的项目,如段落新的内联。

I planned in control in event OnQueueChangedChanged try dequeueing and just draw items as new Inlines for Paragraph.

推荐答案

您可以实现生产者 - 消费者

看这简化版本。


  • RunProducer 仅用于测试,你的情况 ProcessNotificationMessage 将以类似的方式工作。

  • RunConsumer 是不断检查新邮件的方法和集消息有一些延迟,否则用户将无法读取它。

  • 这概念只是一个快速的证明,但你可以通过提供一个方法 ShowNextMessage 和<$ C更好地落实它,例如$ C> IsMessageAvailable ,然后即可显示一个新的消息,并要求它时,认为可以决定。这将是一个更好的设计。即使用户可以隐藏一些消息的速度,然后,你只需要绑定 ShowNextMessage 点击事件。

  • 完整的源代码

  • RunProducer is only for tests, in your case ProcessNotificationMessage will work in a similar way.
  • RunConsumer is a method which constantly checks for new messages and sets Message with some delay, otherwise a user wouldn't be able to read it.
  • It's just a quick proof of concept, but you could implement it better, for example by providing a methods ShowNextMessage and IsMessageAvailable, then the view could decide when is ready to display a new message and request for it. It would be a better design. Even a user could hide some messages faster then, you'd need only to bind ShowNextMessage to Click event.
  • Full source code

public class MyViewModel : INotifyPropertyChanged
{
    public ConcurrentQueue<string> Queue { get; set; }

    #region Message

    private string _message;

    public string Message
    {
        get
        {
            return _message;
        }
        set
        {
            if (_message != value)
            {
                _message = value;
                OnPropertyChanged();
            }
        }
    }
    #endregion

    public MyViewModel()
    {
        Queue = new ConcurrentQueue<string>();
        RunProducer();
        RunConsumer();
    }

    public void RunProducer()
    {
        Task.Run(() =>
        {
            int i = 0;
            while (true)
            {
                if (Queue.Count < 10)
                    Queue.Enqueue("TestTest " + (i++).ToString());
                else
                    Task.Delay(500).Wait();
            }
        });
    }

    public void RunConsumer()
    {
        Task.Run(() =>
        {
            while (true)
            {
                if (Queue.Count > 0)
                {
                    string msg = "";
                    if (Queue.TryDequeue(out msg))
                        Message = msg;
                }
                else
                {
                    Task.Delay(500).Wait();
                }

                Task.Delay(100).Wait();
            }
        });
    }

    #region INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion
}


在空队列的情况下,你可以使用 ManualResetMonitor ,以避免不必要的迭代。

In case of empty queue you could use ManualResetMonitor to avoid unnecessary iterations.

说明你的代码:结果
。如果集合可再改结合的目的,你应该只<$使用C $ C>的ObservableCollection< T> (或者一些工具 INotifyCollectionChanged ),因为它跟踪的变化和不重装所有的东西。

Remarks to your code:
If a collection can be changed then for binding purpose you should use only ObservableCollection<T> (or something that implements INotifyCollectionChanged), because it tracks changes and doesn't reload everything.

然而,在你的代码的整体结合应该被刷新(如你通知整个集合已更改),但我认为这个机制是聪明的,如果检查引用是否相等如果这样的话没有发生刷新。大概HAX将其设置为和背部会刷新: - )

However in your code a whole binding should be refreshed (as you notified that whole collection has been changed), but I think this mechanism is smarter and checks if references are equal, if so then no refresh occurs. Probably a hax to set it to null and back would refresh it :-).

这篇关于如何保证,视图模型属性更改它再次值之前已经绑定的看法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆