代码之家  ›  专栏  ›  技术社区  ›  touseefbsb

多个视图通过多个线程之间的双向数据绑定共享相同的数据

  •  2
  • touseefbsb  · 技术社区  · 7 年前

    uwp应用程序(MVVM架构)我有一个 主视图 其中有一个集合 视图模型 ,用于绑定到上的网格视图 主视图 每个项目都有一个 文本框 带双向数据绑定 描述 类的属性 注释 .

    每个GridView项的文本框的XAML。

    <TextBlock Text="{x:Bind Description,Mode=TwoWay}"
    

    用于绑定到GridView的项源的集合属性。

    public ObservableCollection<Note> Notes { get; }
    

    这是课堂 注释

    public class Note : Observable
    {
        private string _description;
        public string Description
        {
            get => _description;
            set => Set(ref _description, value, nameof(Description));
        }        
    }
    

    这个 可观察的 类用于双向数据绑定帮助。

    public class Observable : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        protected void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
        {
            if (Equals(storage, value))
            {
                return;
            }
    
            storage = value;
            OnPropertyChanged(propertyName);
        }
    
        protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
    

    现在一切正常运行这一点工作得很好,当我改变文本框中的文本,它也改变了描述的值。

    第二视图

    现在我有了一个功能,其中每个GridView项都有一个 按钮 在里面打开便条 新窗口 . 而这个新窗口只有一个文本框,所以现在辅助视图和打开该视图的GridView项使用的是 注释 .

    辅助视图中的此文本框还具有与 描述 笔记中的

    问题

    我想要的是,无论是在GridView中的文本框还是在次视图中的文本框被编辑,说明的值都必须在这两个文本框之间保持同步,这就是为什么我试图用相同的注释对象以两种方式绑定它们,因此相同 描述 对象绑定到这两个对象。

    我预料到的错误是 编组线程错误 ,所以每当我试图更改任何文本框的值时,它都试图更新其他视图(另一个线程)上的UI,这当然是不允许的。

    我知道corediptcher

    我已经知道uwp用于安全跨线程通信的调度器特性,我已经有了它的所有设置,如果我从一个正常的方法使用它,我可以很容易地将它用于跨线程UI更新,它完全可以工作。但我的问题是:

    protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\
    

    当它试图调用 属性更改 我试图在调度员中包装以下行:

    OnPropertyChanged(propertyName);
    

    但是 使化 接口不允许我有一个返回任务的set<gt;方法,它只需要返回一个对象,这是我被卡住的地方,我不知道如何在这种情况下使用调度器,请告诉我,如果有更好的方法可以做到这一点,似乎这种方法可能不那么有效。 谢谢。

    2 回复  |  直到 7 年前
        1
  •  5
  •   Martin Zikmund    7 年前

    在这种情况下,最好的解决方案是 INotifyPropertyChanged 每个窗口的实例,并使用类似于 EventHub 在mvvmlight中,它发布消息,表示基础模型已更改,所有相关方应更新其实例。

    另一种选择是创建一个基础模型类,它维护一个 InotifyProperty已更改 每个UI线程的实例(因此 Dictionary<Dispatcher, YourModelClass> . 现在家长会订阅 PropertyChanged 每个子实例的事件,一旦它执行,将使用适当的 Dispatcher .

    还有一个非常有趣的实用程序类 ViewSpecificBindableClass 作者:Marian Dolinsk_½ on his GitHub 这可能是一个解决方案,它允许您在多个视图中拥有“单个”类,并知道多个调度器。我还没试过,但看起来很有希望。

        2
  •  1
  •   touseefbsb    7 年前

    所以我最终不得不采取完全不同的方法集中 文本更改的事件 主视图文本框和第二个视图上的文本框。

    我基本上把主页上的文本框传递给了第二页(第二视图),然后订阅了它的textChanged事件。我还订阅了第二个视图上的TextBox的TextChanged事件,然后借助于Reverse 调度员 我可以在两个窗口之间同步文本,没有任何问题。

    注意:始终确保在辅助窗口关闭时取消订阅事件,以防止内存泄漏。

    private async void PipBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        string text = PipBox.Text;
        await CoreApplication.MainView.Dispatcher.AwaitableRunAsync(() =>
        {
            if (parentBox.Text != text)
                parentBox.Text = text;
        });
    }
    private async void ParentBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        string text = parentBox.Text;
        // the awaitablerunasync extension method comes from "Windows Community Toolkit".
        await _viewLifetimeControl.Dispatcher.AwaitableRunAsync(() =>
        {
            if (ViewModel.MyNote.Description != text)
                ViewModel.MyNote.Description = text;
        });
    }
    

    请注意,两个文本框上仍然有双向数据绑定,并且不会导致任何异常,因为我使用的是 注释 对于这两种观点。

    <TextBox Text="{x:Bind ViewModel.MyNote.Description, Mode=TwoWay}"
                     x:Name="PipBox"/>
    

    但因为我有 双向数据绑定 在这两个文本框中,这就是我可以轻松地使两个note实例保持同步以及在不同的线程上保持同步的方法。

    我将保留Github回购,以防它可以帮助其他任何人: https://github.com/touseefbsb/MultiWindowBindingSync

    特别感谢 马丁齐克蒙德 他帮助我找到了这个解决方案。

    推荐文章