【问题标题】:Change a ViewModel Property from a different class and update the View - MVVM从不同的类更改 ViewModel 属性并更新视图 - MVVM
【发布时间】:2021-08-21 21:29:10
【问题描述】:

我需要从class 中的方法调用更改View 上的ButtonVisibility

我尝试通过在class 中公开VeiwModel 来访问它,然后成功地将Property“ShowRedHat”从真更改为假,但这不会更新Button 的可见性在视图中。这也会双重加载 ViewModel,这在我的解决方案中是不可接受的。

感谢任何帮助。

班级:

   public class HatEngine
   {
      
       public void SetShowRedHat()
       {
          ????.ShowRedHat = false;
       }
   }

ViewModel 中的属性:

public class MyViewModel : ObservableObject
{
    private bool _showRedHat;
    public bool ShowRedHat
    {
        get { return _showRedHat; }
        set
        {
            OnPropertyChanged(ref _showRedHat, value);
        }
    }
}

视图中的按钮:

    <Button Content="Red Hat"                    
            Command="{Binding RedHatCommand}"
            Visibility="{Binding ShowRedHat, Converter={StaticResource BoolToVis}}"/>

【问题讨论】:

  • 为什么视图模型上的动作发生在一个完全不同的类中?视图模型应该控制其状态的变化;在内部或通过绑定到视图。如果 HatEngine 中的某些更改会导致您的视图模型发生更改,那么也许应该颠倒这种关系。这意味着视图模型应该具有对 HatEngine 类的引用,并且可能 HatEngine 类应该引发一个事件(或多个事件),视图模型使用该事件来更改任何必要的状态。
  • 嗨@coding.monkey。两个方向都存在同样的问题。如果我在 HatEngine 中更改了一个属性,ViewModel 如何知道该属性已更改?谢谢
  • 没有足够的信息来说明 HatEngine 在这个环境中扮演什么角色。是服务吗?它是另一个 ViewModel(似乎不是基于提供的代码,因为它不是从 ObservableObject 派生的)。 假设它打算作为服务工作,有两种选择:直接从服务触发事件或使用事件聚合在两个类之间进行通信。下面我尝试了第一个选项;但是,更多信息将有助于找到真正的解决方案。

标签: class mvvm view properties viewmodel


【解决方案1】:

如果HatEngine 的目的是成为MyViewModel 使用的服务,那么类似下面的内容就是获得所需内容的开始。

这个例子通过构造函数使用依赖注入;这在 MVVM 中很常见,如果您不熟悉它,我强烈建议您进一步研究。

// define delegate for event to be fired from HatEngine instances
public delegate void HatEngineNotifyEventHandler(object sender, bool shouldShow);

// interface declaration for HatEngine - this is important for injecting mocks for unit testing
public interface IHatEngine
{
    event HatEngineNotifyEventHandler Notify;
    void SetShowRedHat(bool show);
}

// simple IHatEngine implementation
public sealed class HatEngine : IHatEngine
{
    public event HatEngineNotifyEventHandler Notify;

    public void SetShowRedHat(bool show) => OnNotify(show);

    private void OnNotify(bool shouldShow) =>
        Notify?.Invoke(this, shouldShow);
}

public class MyViewModel : ObservableObject
{
    private readonly IHatEngine _hatEngine;
    private bool _showRedHat;

    // MyViewModel consumes an IHatEngine instance and subscribes to its Notify event
    public MyViewModel(IHatEngine hatEngine = null)
    {
        // many MVVM frameworks include a DI container that should be used here
        // to resolve an IHatEngine instance; however, for simplicity for this
        // example just create HatEngine() directly
        _hatEngine = hatEngine ?? new HatEngine();

        // when the event is received, update ShowRedHat accordingly
        _hatEngine.Notify += (_, shouldShow) => ShowRedHat = shouldShow;
    }

    public bool ShowRedHat
    {
        get => _showRedHat;
        set => OnPropertyChanged(ref _showRedHat, value);
    }
}

【讨论】:

  • 嗨@coding.monkey。我在上面实现了,没有任何变化。我创建了接口并将委托添加到接口。我将 HatEngine 链接到 IHatEngine 并添加了推荐的代码。我向 MyViewModel 添加了推荐代码。最后,我将视图上的绑定设置为 ShowRedHat。我在这个代码块中看到了一个下划线'hatEngine.Notify += (, shouldShow) => ShowRedHat = shouldShow;'。这是造成问题的原因吗?我尝试将此下划线更改为 _showRedHat,但没有成功。
  • 您需要花一些时间调试代码以了解发生了什么。尝试在多个位置放置断点(例如,在 HatEngine 中的 SetShowRedHat(),在 MyViewModel 的事件处理程序中)。调试时要回答的问题可能是:Notify 事件是否触发(是否有任何代码实际调用 SetShowRedHat())?是触发 NotifyPropertyChanged 事件的 OnPropertyChanged() 方法。最后,尝试简化 xaml 绑定...而不是绑定到可见性并使用转换器,而是绑定到已经是布尔值的 IsEnabled 属性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-09
  • 1970-01-01
  • 2012-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多