亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Caliburn Micro MVVM:處理從一個 View/ViewModel 到另一個

Caliburn Micro MVVM:處理從一個 View/ViewModel 到另一個

C#
幕布斯6054654 2021-10-24 19:33:55
我創建了一個 wpf 項目(使用 caliburn micro 和 MVVM 模式,沒有代碼隱藏),其中包含 2 個視圖模型及其相關視圖:ShellView.xaml 和 ShellViewModel.csOtherView.xaml 和 OtherViewModel.csShellView 包含:ContentControl 指的是OtherView/OtherViewModel。一個 TextBox,其中包含所謂的“目標文本”。OtherView 包含一個 StackPanel,其中包含:接受來自用戶的文本(作為“源文本”)的 TextBox。在鼠標右鍵單擊事件上將源文本復制到目標的按鈕。我的問題:如何將 OtherView/ViewModel 中的源文本復制到 ShellView/ViewModel 中的目標文本?任何最佳實踐?ShellViewModel 可以從源文本框捕獲 PropertyChange 事件嗎?如何反向復制(從目標到源)?在此先感謝您,如果需要,請隨時修改下面的代碼。ShellView.xaml<UserControl    x:Class="CmMultipleViewModelView.Views.ShellView"    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"    d:DesignHeight="450"    d:DesignWidth="800"    mc:Ignorable="d">    <Grid Width="800" Height="450">        <Grid.ColumnDefinitions>            <ColumnDefinition Width="*" />            <ColumnDefinition Width="*" />        </Grid.ColumnDefinitions>        <ContentControl            x:Name="ActiveItem"            Grid.Column="0"            HorizontalAlignment="Center"            VerticalAlignment="Center" />        <TextBox            x:Name="TargetText"            Grid.Column="1"            Width="80"            HorizontalAlignment="Center"            VerticalAlignment="Center" />    </Grid></UserControl>ShellViewModel.cspublic class ShellViewModel : Conductor<object>{    public ShellViewModel()    {        DisplayName = "Shell Window";        var otherVM = new OtherViewModel();        ActivateItem(otherVM);    }    public string DisplayName { get; set; }    private string _targetText = "Target";    public string TargetText    {        get => _targetText;        set        {            _targetText = value;             NotifyOfPropertyChange(() => TargetText);        }    }}
查看完整描述

1 回答

?
繁華開滿天機

TA貢獻1816條經驗 獲得超4個贊

正如其他人所說,正確的方法是使用事件聚合器。


如果您在 Caliburn.Micro 中使用 SimpleContainer,那么在您的 OnConfigure 覆蓋中,您將輸入:


_container.Singleton<IEventAggregator>();

當您第一次訪問它時,這將創建一個 IEventAggregator 的實例?,F在,您可以選擇如何訪問它。通過注入構造函數或使用 IoC.GetInstance 方法。


如果要注入,則需要修改視圖模型:


public class ShellViewModel : Conductor<object>, IHandle<string>

{

    private readonly IEventAggregator _eventAggregator;


    public ShellViewModel(IEventAggregator eventagg, OtherViewModel otherVM)

    {

        _eventAggregator = eventagg;

        _eventAggregator.Subscribe(this);

        ActivateItem(otherVM);

    }


    public void Handle(string message)

    {

        TargetText = message;

    }

}


public class OtherViewModel : Screen

{

    private readonly IEventAggregator _eventAggregator;


    public OtherViewModel(IEventAggregator eventagg)

    {

        _eventAggregator = eventagg;

    }


    public void CopyText()

    {

        _eventAggregator.PublishOnUIThread(SourceText);

    }

}

在 Bootstrapper 中,您需要注冊兩個視圖模型:


_container.Singleton<ShellViewModel>();

_container.PerRequest<OtherViewModel>(); // Or Singleton if there'll only ever be one

那么,這一切是為了什么?


在您的 ShellViewModel 中,我們告訴它為字符串實現 IHandle 接口。


IHandle<string>

每當觸發字符串事件時,ShellViewModel 都會調用具有相同簽名的 Handle 方法。如果您只想處理特定類型,則創建一個新類來保存您的復制文本并將處理程序從字符串更改為您的類型。


IHandle<string>


IHandle<yourtype>

當事件聚合器接收到字符串事件時,它將調用任何偵聽器的 Handle 方法。在你的情況下處理(字符串消息)。如果更改 IHandle 類型,則還需要將 Handle 方法更改為相同類型。


public void Handle(string message)

{

    TargetText = message;

}

這會將 TargetText 設置為您在事件中觸發的任何字符串值。


我們有一個 IEventAggregator 的實例,這是一個單例對象,所以它被引用的任何地方都應該是相同的。我們已修改您的 ShellViewModel 構造函數以接受 IEventAggregator 對象和您的 OtherViewModel 的實例。


一旦我們在本地存儲了對事件聚合器的引用,我們就調用:


_eventAggregator.Subscribe(this);

這告訴事件聚合器我們對將由我們在類上定義的 IHandle 處理的任何事件感興趣(只要它們處理不同的類型,您就可以有多個)。


與 OtherViewModel 有點不同,我們再次將 IEventAggregator 添加到構造函數,以便我們可以在啟動時注入它,但這次我們不訂閱任何事件,因為 OtherViewModel 只觸發一個事件。


在您的 CopyText 方法中,您將調用:


_eventAggregator.PublishOnUIThread(SourceText);

這會在事件聚合器上引發事件。然后將其傳播到使用 Handle 方法處理它的 ShellViewModel。


只要您在 Bootstrapper 的 SimpleContainer 實例中注冊您的視圖模型和事件聚合器,Caliburn.Micro 就會知道在創建 VM 實例時將哪些項目注入到構造函數中。


流程如下:


ShellViewModel 訂閱字符串事件


_eventAggregator.Subscribe(this);


用戶在 SourceText 中鍵入一些文本用戶按鼠標右鍵,這會調用:


CopyText()

其中調用:


_eventAggregator.PublishOnUIThread(SourceText);

然后事件聚合器檢查所有具有 IHandle 接口的訂閱視圖模型,然后調用:


Handle(string message)

每一個。


在您的情況下,這會將 TargetText 設置為消息:


TargetText = message;

為文字墻道歉!


有一種更簡單的方法是讓您的 ShellViewModel 訂閱 OtherViewModel 上的 PropertyChanged 事件:


otherVM.PropertyChange += OtherVMPropertyChanged;

然后在處理程序中,您必須查找 SourceText 屬性的通知并更新目標文本。一個更簡單的解決方案,但意味著您將緊密耦合您的 ShellVM 和 OtherVM,而且您必須確保在關閉 OtherVM 時取消訂閱該事件,否則它將永遠不會被垃圾收集。


下面是如何設置 DI 容器

在您的 Bootstrapper 類中,您需要添加 SimpleContainer:


private SimpleContainer _simplecontainer = new SimpleContainer();

然后你需要覆蓋一些方法并確保代碼如下:


protected override object GetInstance(Type serviceType, string key)

{

    return _container.GetInstance(serviceType, key);

}


protected override IEnumerable<object> GetAllInstances(Type serviceType)

{

    return _container.GetAllInstances(serviceType);

}


protected override void BuildUp(object instance)

{

    _container.BuildUp(instance);

}

現在覆蓋 OnConfigure 方法。這是我們告訴 Caliburn.Micro 我們正在使用的 ViewModels 以及我們設置 EventAggregator 和 WindowManager 的地方(因此它可以將您的 ShellViewModel 包裝在一個窗口中):


protected override void Configure()

{

    base.Configure();


    _container.Singleton<IWindowManager, WindowManager>();

    _container.Singleton<IEventAggregator, EventAggregator>();


    _container.Singleton<ShellViewModel>();

    _container.PerRequest<OtherViewModel>(); // If you'll only ever have one OtherViewModel then you can set this as a Singleton instead of PerRequest

}

您的 DI 現已全部設置完畢。最后,在您的 StartUp 覆蓋中,您只需確保它看起來像這樣:


protected override void OnStartup(object sender, StartupEventArgs e)

{

    base.OnStartup(sender, e);


    DisplayRootViewFor<ShellViewModel>();

}

如果您現在運行您的應用程序,當 ShellViewModel 創建時,Caliburn.Micro 將查看 ShellViewModel 的構造函數參數以查看它需要提供什么。它將看到它需要一個事件聚合器和 OtherViewModel,因此它會在 SimpleContainer 中查看它們是否已被注冊。如果有,那么它將創建實例(如果需要)并將它們注入到構造函數中。當它創建 OtherViewModel 時,它還會檢查構造函數參數并創建任何需要的東西。


最后它將顯示 ShellViewModel。


查看完整回答
反對 回復 2021-10-24
  • 1 回答
  • 0 關注
  • 564 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號