在另一个 ViewModel 中触发一个 ViewModel 的 EventHandler

Trigger EventHandler of one ViewModel in another ViewModel

我已经使用 MessagingCenter 取得了预期的结果,但我从 Xamarin 文章中了解到,MessagingCenter 不是触发 30 多个事件的首选方式。除此之外,我必须在完成操作后取消订阅 MessagingCenter。我想要设置页面,其中有 30 多个设置必须在不同视图的整个应用程序中进行更改。如何将 SettingsViewModel 注入 Xamarin.Forms 应用程序中的其他 ViewModel?

SettingsViewModel.cs:

namespace MessagingCenterApp.ViewModels
{
  public class SettingsViewModel : BaseViewModel, ISettingsViewModel
  {
    public ICommand ChangeCommand { get; set; }
    public SettingsViewModel()
    {
      Title = "Settings";

      this.BoxColor = Color.Red;

      this.ChangeCommand = new Command(this.ChangeColor);
    }

    private void ChangeColor()
    {
      this.BoxColor = Color.FromHex(this.BoxColorS);

      MessagingCenter.Send<Object, Color>(this, "boxColor", this.BoxColor);
    }

    private Color _boxColor;
    public Color BoxColor
    {
      get => _boxColor;
      set
      {
        _boxColor = value;
        this.OnPropertyChanged();
      }
    }

    private string _boxColorS;
    public string BoxColorS
    {
      get => Preferences.Get("BoxColor", "#17805d");
      set
      {
        Preferences.Set("BoxColor", value);
        this.ChangeColor();
        this.OnSettingsChanged();
        this.OnPropertyChanged();
      }
    }

    public event EventHandler<SettingsChangedEventArgs> SettingsChanged;
    private void OnSettingsChanged() => this.SettingsChanged?.Invoke(this, new SettingsChangedEventArgs(this.Settings));

    public Settings Settings { get; private set; }
  }
} 

HomeViewModel.cs:

namespace MessagingCenterApp.ViewModels
{
  public class HomeViewModel : BaseViewModel
  {
    public HomeViewModel()
    {
      this.Title = "Home";

      MessagingCenter.Subscribe<Object, Color>(this, "boxColor", (sender, arg) =>
      {

        System.Diagnostics.Debug.WriteLine("received color = " + arg);
        this.BoxColor = arg;
      });

      this.BoxColor = Color.Red;

      this.SettingsViewModel = new SettingsViewModel();
      this.SettingsViewModel.SettingsChanged += OnSettingsChanged;
    }

    private void OnSettingsChanged(object sender, SettingsChangedEventArgs e)
    {
      throw new NotImplementedException();
    }

    private Color _boxColor;
    public Color BoxColor
    {
      get => _boxColor;
      set
      {
        _boxColor = value;
        OnPropertyChanged();
      }
    }

    private ISettingsViewModel SettingsViewModel { get; }
  }
}

我是否应该以某种方式在 MainViewModel 中完成所有操作?我的意思是:

namespace MessagingCenterApp.ViewModels
{
  public class MainViewModel : BaseViewModel
  {
    public MainViewModel()
    {
      this.SettingsViewModel = new SettingsViewModel();
      this.HomeViewModel = new HomeViewModel(this.SettingsViewModel);
    }

    public SettingsViewModel SettingsViewModel { get; set; }
    public HomeViewModel HomeViewModel { get; }
  }
}

然后在AppShell中初始化了?我无法使这种方法起作用。

重要!我不想使用任何 MVVM 框架!只有本机行为。

mvvmcross 的 Messenger 据称比 X-Form 的 built-in 消息中心“更轻”。

我通过在“BasePage”中定义一些辅助方法来使用 mvvmcross Messenger。然后每个页面继承自“BasePage”而不是“ContentPage”。

这会自动处理每个方法的“退订”。并使管理 mvvmcross 的“订阅令牌”变得更加容易。

BasePage.xaml.cs:

// If not using mvvmcross, this could inherit from ContentPage instead.
public class BasePage : MvxContentPage
{
    protected readonly IMvxMessenger Messenger;

    public BasePage()
    {
        this.Messenger = Mvx.IoCProvider.Resolve<IMvxMessenger>();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();

        // Examples of subscribing to messages. Your subclasses of BasePage can also do this.
        this.Subscribe<MyMessage1>(OnMyMessage1);
        this.SubscribeOnMainThread<MyMessage2>(OnMyMessage2);
    }

    protected override void OnDisappearing()
    {
        UnsubscribeAll();

        base.OnDisappearing();
    }

    #region Messenger Subscriptions
    protected List<MvxSubscriptionToken> _subscriptions = new List<MvxSubscriptionToken>();

    /// <summary>
    /// Create subscription and add to "_subscriptions".
    /// Call this from subclass' OnAppearing, once per subscription.
    /// Automatically unsubscribed in OnDisappearing.
    /// </summary>
    /// <param name="token"></param>
    /// <param name="msgType"></param>
    protected void Subscribe<T>(Action<T> onMessage) where T : MvxMessage
    {
        var token = this.Messenger.Subscribe<T>(onMessage);
        // Hold token to avoid GC of the subscription.
        _subscriptions.Add(token);
    }
    protected void SubscribeOnMainThread<T>(Action<T> onMessage) where T : MvxMessage
    {
        var token = this.Messenger.SubscribeOnMainThread<T>(onMessage);
        // Hold token to avoid GC of the subscription.
        _subscriptions.Add(token);
    }
    /// <summary>
    /// OnDisappearing calls this.
    /// </summary>
    private void UnsubscribeAll()
    {
        if (_subscriptions.Count > 0)
        {
            foreach (MvxSubscriptionToken token in _subscriptions)
            {
                // Per "https://www.mvvmcross.com/documentation/plugins/messenger", this is sufficient to Unsubscribe:
                // "Subscriptions can be cancelled at any time using the Unsubscribe method on the IMvxMessenger or by calling Dispose() on the subscription token."
                token.Dispose();
            }

            _subscriptions.Clear();
        }
    }
    #endregion
}

对于视图模型,class 将是您的视图模型继承自的“BaseViewModel”。内容同上,只是Appearing/Disappearing.

的方法名不同

BaseViewModel.cs:

public class BaseViewModel : MvxViewModel
{
    ...
    // mvvmcross' MvxViewModel provides these.
    protected override void ViewAppearing()
    {
        ...
    }
    protected override void ViewDisappearing()
    {
        ...
    }

    ... Messenger Subscriptions methods ...
}