1

ATM 我正在​​尝试掌握 MVVM、数据绑定和命令。我正在尝试(重新)使用该模式创建游戏菜单。我有几个问题。

1) 现在我在应用程序模型中有按钮内容(Party Paradigms 等),并从我的 UI 按钮绑定到它。但由于这更像是一种 UI 类的东西,我想知道这是否是处理事情的正确方法。

我的想法是这会更容易,因为只要我进入子菜单(例如数据日志),我就会更改属性,并且按钮内容会自动更改。你会怎么处理?

2)时钟图标旁边的标签应该是一个计数器。同样,您会将这种逻辑放在 VM 或 xaml.cs 文件中吗?

我也遇到了 StopWatch 和 INotifyPropertyChanged 接口的一些问题。现在我的 xaml.cs 文件中有 Stopwatch 方法:

MainMenuVM mvm = new MainMenuVM();

    public MainWindow()
    {
        InitializeComponent();
        DataContext = mvm;
        Thread thread = new Thread(StopWatch);
        thread.Start();
    }

    public void StopWatch()
    {
        int secs = 0, mins = 0, hours = 0;

        while (true)
        {
            secs++;
            if (secs == 60)
            {
                mins++;
                secs = 0;
            }

            if (mins == 60)
            {
                hours++;
                mins = 0;
            }

            if (mins >= 10 && secs < 10)
            {
                mvm.Stopwatch = "0" + hours + ":" + mins + ":" + "0" + secs;
            }

            if (mins >= 10 && secs >= 10)
            {
                mvm.Stopwatch = "0" + hours + ":" + mins + ":" + secs;
            }

            if (mins < 10 && secs >= 10)
            {
                mvm.Stopwatch = "0" + hours + ":" + "0" + mins + ":" + secs;
            }

            if (mins < 10 && secs < 10)
            {
                mvm.Stopwatch = "0" + hours + ":" + "0" + mins + ":" + "0" + secs;
            }

            Thread.Sleep(1000);
        }
    }

而且我的时间标签内容绑定到 mvm.Stopwatch 属性。

<Label x:Name="lblTime" Content="{Binding Stopwatch}" />

秒表属性:

public string Stopwatch
    {
        get
        {
            if (_stopwatch == null)
            {
                _stopwatch = "00:00:00";
            }
            return _stopwatch;
        }
        set { _stopwatch = value; YouChanged("Stopwatch"); // Calling the INotify event
        }
    }

但由于某种原因,我得到了一个很好的旧“对象引用未设置为对象的实例”。每当我到达秒表设置器并调用事件时。

4

3 回答 3

3

在视图模型中有与视图相关的数据(颜色、可见性、标签等)是正常的。请记住,在 MVVM 中有一个“模型”和一个“视图模型”,因此后者实际上应该具有视图的属性。

至于“未设置对象引用”,我猜您需要检查是否PropertyChanged为空(在YouChanged方法中),如果没有人实际订阅该事件,则会发生这种情况:

public void YouChanged(string propName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(propName);
    }
}
于 2013-05-15T22:51:15.850 回答
3

这是一个简单的概念,

  • 尽可能让模型保持哑巴。尽量保持它的可重用性。

“1”

不,我个人不会Button Content来自模型。您解释的 Button 内容与后端逻辑或功能无关。假设如果在消息应用程序中标签指示“用户名”的地方Content也是TextBlock如此,那么模型保存该数据是有意义的。这里只是你在视图中重新使用了一个 ui 控件。

解决方案:

我可能只是有单独的按钮,并在需要时将其设置为折叠。这样我就不会使Command按钮对应于根据它的内容或其他神奇的东西执行不同的操作。如果您坚持使用一个按钮,则可以将字符串存储在资源文件中并使用绑定从视图绑定到它们(如果需要,也可以帮助本地化)。

“2”

在虚拟机中。这是与功能相关的逻辑,应该通过应用程序行为的单元测试“可测试”。

问问自己,我是否应该测试这个逻辑,如果是这样,它就不能在视图中。如果您无法从视图中删除它,那么您可能在 MVVM 中做错了)

“3”

在视图中不要有不只是视图相关的逻辑。因此,如果您有动画代码或纯粹是视觉增强的东西,那么请使用代码隐藏,否则不要使用它,因为它只会伤害您。

首先,我不得不说秒表的实现相当糟糕(没有冒犯),你可以而且应该让它变得体面。

简单的秒表示例- 浏览一下并检查字符串格式的用法和DispatcherTimer. 您可以直接在 xaml 中提供字符串格式,使其更加简洁,因为您的后端只能保存实际数据。

对于您的 PropertyChanged null 错误。您是否在函数中检查它是否为空?如果您的 MVVM 新手从MVVM Light 之类的辅助库开始。即使您想自己做所有事情,也可以用它来教自己他们做什么以及为什么这样做。

于 2013-05-15T22:51:44.377 回答
0

唯一可能的答案肯定是“这取决于...”,尽管我认为在 99% 的情况下答案是否定的。为了说明 MVVM 中不同层的作用,让我们考虑一个井字游戏

模型:领域的 UI 技术不可知模型

在井字游戏的 MVVM 实现中,模型包含定义井字游戏的对象和交互。(例如,玩家、游戏对象和代表某人轮流的方法。)重要的是,即使您从不打算在当前应用程序之外使用模型,也不应该将模型与您正在使用的事实联系起来WPF(比如说)。为什么?因为没有任何关于玩 WPF 特有的井字游戏。如果我愿意,我可以在一张纸上播放它,基本对象和它们的交互仍然是相同的。

视图模型:UI 的逻辑表示

View Model 本质上是 UI 的逻辑表示。如果我的井字游戏 UI 有一个“重置”按钮,那么视图模型上应该有一个适当的命令。就个人而言,我会尽量让 View-Model 没有与 UI 相关的对象,并尝试让界面暴露出玩游戏的功能,而不是任何美学属性。

如果我希望应用程序的背景根据播放器 1 或播放器 2 的轮到而改变,我将在我的 View-Model 上有一个名为“ActivePlayer”的属性,然后使用转换器或数据触发器(如果使用WPF) 将此值转换为适当的背景颜色。这样,围绕 UI 外观的所有波动都保留在 View 层中。(我认为转换器是视图的一部分)。

观点:审美逻辑

我已经含蓄地暗示了这样一个事实,即视图是您专注于美学逻辑的地方。这包括对颜色、动画、某些元素是否可见以及布局的具体引用。

那1%呢?我一开始就说过,放置与 UI 相关的数据在 99% 的情况下都是不可取的。但是,如果我的应用程序正在对 UI 概念(比如颜色选择器)进行建模,那么我的模型自然会有颜色的概念。话虽如此,即便如此,我仍会尝试通过将颜色存储为 AGRB 值而不是表示颜色的各种 .NET 类之一来使其与 UI 技术无关。

于 2013-05-17T10:50:36.460 回答