luk*_*szk 5 c# data-binding wpf mvvm
有以下情况:
 ViewModel有一个变化非常快的对象.(通过不同的线程)
View通过NotifyPropertyChanged接口获取通知但似乎它有效减慢并且在View绑定新值并绘制之前它会更改次数因此它会错过某些值.
我也尝试绑定View到队列,然后ViewModel可以Enqueue,并View可以通过出队绘制.
不幸的是,发生了另一个问题:之后RaisePropertyChanged(() => queue); View没有被告知它被改变了.
在这种情况下,INotifyPropertyChanged接口的实现不起作用.
你有什么主意吗?
示例代码ViewModel:
public class ExamplaryViewModel
{
    public ExamplaryViewModel()
    {
        Messenger.Default.Register<NotificationMessage<Message>>(this, m => ProcessNotificationMessage(m.Content));
    }    
    public void ProcessNotificationMessage(Message message)
    {   
        MessageOftenBeingChanged = message;
        RaisePropertyChanged(() => MessageOftenBeingChanged );
    }
}
View绑定到MessageOftenBeingChanged.
另一种选择是按照评论中的建议准备快照:
public void ProcessNotificationMessage(Message message)
{
    Messages.Enqueue(message);
    RaisePropertyChanged(() => Messages);
}
View:
<controls:RichTextBoxMonitor Messages="{Binding Messages} 
Control:
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()方法不会触发发生的变化.
我计划在事件中控制OnQueueChangedChanged出队,并将项目作为段落的新内联绘制.
您可以实现生产者-消费者。
看看这个简化版本。
RunProducer仅用于测试,在您的情况下ProcessNotificationMessage将以类似的方式工作。RunConsumer是一种不断检查新消息并设置Message一些延迟的方法,否则用户将无法阅读它。ShowNextMessage和IsMessageAvailable,然后视图可以决定何时准备好显示新消息并请求它。这将是一个更好的设计。即使用户可以更快地隐藏一些消息,您只需要绑定ShowNextMessage到Click事件即可。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来避免不必要的迭代。
对代码的备注:
如果可以更改集合,那么出于绑定目的,您应该仅使用ObservableCollection<T>(或实现的东西INotifyCollectionChanged),因为它跟踪更改并且不会重新加载所有内容。
然而,在您的代码中,应该刷新整个绑定(因为您通知整个集合已更改),但我认为这种机制更智能,它会检查引用是否相等,如果相等则不会发生刷新。可能是一个恶作剧,将其设置为null和返回会刷新它:-)。
| 归档时间: | 
 | 
| 查看次数: | 500 次 | 
| 最近记录: |