【问题标题】:How to provide and pass "object" to the viewmodelbase?如何提供“对象”并将其传递给视图模型库?
【发布时间】:2020-02-23 17:03:06
【问题描述】:

我刚开始做 MVVM,因为听说过它的很多好处:

  1. 清洁码
  2. 可重用代码
  3. 更好的代码组织

因此开始执行通常的“代码隐藏”以确保我的代码正常工作,然后应用 MVVM 对其进行清理。 所以这是我的“背后代码”示例之一:

private const int LED_PIN = 17, RELAY_PIN = 27;
private GpioPin LEDpin, RELAYpin;

    private bool InitGPIO(TextBlock txt)
    {
        var gpio = GpioController.GetDefault();

        // Show an error if there is no GPIO controller
        if (gpio == null)
        {
            txt.Text = "There is no GPIO controller on this device.";
            txt.Foreground = new SolidColorBrush(Colors.Red);
            return false;
        }

        txt.Text = "GPIO controller initialized correctly.";
        txt.Foreground = new SolidColorBrush(Colors.Green);

        LEDpin = gpio.OpenPin(LED_PIN);
        RELAYpin = gpio.OpenPin(RELAY_PIN);
        LEDpinValue = GpioPinValue.Low;
        RELAYpinValue = GpioPinValue.High;
        LEDpin.Write(LEDpinValue);
        RELAYpin.Write(RELAYpinValue);
        LEDpin.SetDriveMode(GpioPinDriveMode.Output);
        RELAYpin.SetDriveMode(GpioPinDriveMode.Output);
        return true;
    }

要使用这个“InitGPIO”方法,我必须提供:

  1. 固定“int”引脚。
  2. GpioPin 类型。
  3. GpioPinValue 类型。
  4. 显示错误的文本块。

我已经创建了一个 ViewModelBase 和用于读取它的简化方法:

public class ViewModelBase
{
    public InitGpioCommand InitGpiocommand { get; set; }
    public ViewModelBase() 
    {
        this.InitGpiocommand = new InitGpioCommand(this);
    }

    public bool InitGPIO(DigitalControl dc)
    {
        var gpio = GpioController.GetDefault();

        // Show an error if there is no GPIO controller
        if (gpio == null)
        {
            dc.Status.Text = "There is no GPIO controller on this device.";
            dc.Status.Foreground = new SolidColorBrush(Colors.Red);
            return false;
        }

        dc.Status.Text = "GPIO controller initialized correctly.";
        dc.Status.Foreground = new SolidColorBrush(Colors.Green);

        dc.DevicePin = gpio.OpenPin(dc.PinNumber);
        dc.PinValue = GpioPinValue.Low;
        dc.DevicePin.Write(dc.PinValue);
        dc.DevicePin.SetDriveMode(GpioPinDriveMode.Output);
        return true;
    }
}

一切都在这个模型中被总结了:

public class DigitalControl
{
    public TextBlock Status { get; set; }
    public GpioPin DevicePin  { get; set; }
    public GpioPinValue PinValue { get; set; }
    public int PinNumber { get; set; }
}

和我当前触发 InitGPIO 方法的按钮:

   <Button x:Name="FirstLightTest"
           Content="Test" 
           Command="{Binding InitGPIO,Source={StaticResource viewmodel}}">
   </Button>

这当然行不通。

我意识到我必须:

  1. 将“TextBlock”从 xaml 传递到 ViewModelBase 中的方法参数。
  2. 在 C# 代码中的某处分配 GpioPin、GpioPinValue 和 PinNumber,并将它们传递给 ViewModelBase 内的方法。

为了填充该方法中的所有参数。 我真的不知道这是否是一个糟糕的 MVVM 设计,但我认为使用这种复杂模式的最好方法是将它分解成这样的小问题,看看它是否有价值。

【问题讨论】:

    标签: c# xaml mvvm uwp


    【解决方案1】:

    代码中有一些混淆。首先Binding绑定InitGIPO,这是一个方法。这不起作用,因为 Command 只能绑定到 ICommand 属性。在这种情况下,正确的目标是InitGpiocommand。我总是建议使用现有的 MVVM 框架作为起点,例如 MVVM Light 框架或 MvvmCross。这些提供了一个简单的DelegateCommand 的实现,它可以调用一个简单的无参数方法。然后你可以让方法看起来像这样:

    private bool InitGPIO()
    {
        ...
    }
    

    现在,我们从哪里获得 DigitalControl 实例?我们将向我们的视图模型添加一个属性来表示这个实例:

    public DigitalControl DigitalControl { get; } = new DigitalControl();
    

    正如@max 已经提到的,绝对不鼓励将 UI 控件放入任何 View Model 属性中,所以让我们将 DigitalControl 的定义更改为:

    public class DigitalControl
    {
        public string Status { get; set; }
        public GpioPin DevicePin  { get; set; }
        public GpioPinValue PinValue { get; set; }
        public int PinNumber { get; set; }
    }
    

    Status 属性现在可以数据绑定TextBlock,如下所示:

    <TextBlock Text="{Binding DigitalControl.Status, Mode=TwoWay}" .../>
    

    一旦用户修改了TextBlock,更改将自动传播到视图模型的DigitalControl 实例的Status 属性。

    要在InitGIPO 中引用DigitalControl 属性,您可以将其作为视图模型中的任何其他属性进行引用。

    【讨论】:

    • 等等赋值步骤呢? private const int LED_PIN = 17, RELAY_PIN = 27;
    • 我不确定你的意思,你能否用新代码更新答案,以便我看得更清楚:-)?
    【解决方案2】:

    对我来说,在模型中包含 UI 组件 (TextBlock) 违反了 MVVM 模式。相反,TextBlock 的属性应该通过绑定机制绑定到视图模型,而不是直接分配。 总结一下:

    1. 从模型中删除 TextBlock 引用
    2. 在视图模型中提供TextBlock 可以绑定到的属性(文本、前景色或布尔标志)。
    3. 从 xaml 绑定到视图模型属性。

    【讨论】:

    • 谢谢 Max,我显然不认为这会发生。因为当代码落后时很有意义,顺便说一句很好的提示。我喜欢它
    猜你喜欢
    • 1970-01-01
    • 2013-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 2022-01-17
    相关资源
    最近更新 更多