MVVM模式 - 将UI相关数据放入模型中是否可以?

时间:2013-05-15 22:33:45

标签: c# wpf mvvm

ATM我正试图搞清楚MVVM,数据绑定和命令。我正在尝试使用该模式(重新)创建game menu。我有几个问题。

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

我的想法是,它更容易,因为每当我进入子菜单(例如数据记录)时我只会更改属性,按钮内容会自动更改。 你会怎么处理它?<​​/ p>

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
        }
    }

但由于某种原因,我得到了一个很好的旧'对象引用未设置为对象的实例。每当我到达秒表制定者并召集事件时。

3 个答案:

答案 0 :(得分:3)

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

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

public void YouChanged(string propName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(propName);
    }
}

答案 1 :(得分:3)

这是一个简单的概念,

  • 尽可能让模特保持愚蠢。尽量让它在最佳范围内可重复使用。

指向“1”

不,我个人不会来自模型的Button Content。您解释的Button的内容与后端逻辑或功能无关。假设同一个Content用于TextBlock左右,其中标签在信使应用程序中指示“用户名”,那么模型可以保存该数据。这只是你在视图中重新使用ui控件。

解决方案:

我可能只有单独的Button,并在需要时将其设置为折叠。这样我就不会使按钮对应的Command基于它的内容或其他神奇的东西执行不同的动作。如果您坚持使用一个按钮,那么可以将字符串存储在资源文件中,并使用Bindings从View中绑定它们(如果需要也可以帮助定位)。

指向“2”

在VM中。这是与功能相关的逻辑,应该是对应用行为的单元测试“可测试”。

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

指向“3”

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

首先,我必须说秒表实施相当差(没有冒犯),你可以并且应该可以使它体面。

Simple StopWatch Example - 仔细查看并检查字符串格式的用法  使用DispatcherTimer。您可以直接在xaml中提供字符串格式,使其更加清晰,因为您的后端只能保存实际数据。

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

答案 2 :(得分:0)

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

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

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

视图模型:UI的逻辑表示

视图模型本质上是UI的逻辑表示。如果我的Tic-Tac-Toe的特定UI具有“重置”按钮,则视图模型上应该有适当的命令。就个人而言,我会尝试保持View-Model尽可能没有与UI相关的对象,并尝试让界面显示玩游戏的功能,而不是任何美学属性。

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

观点:审美逻辑

我已经含蓄地暗示了View是你专注于审美逻辑的事实。这包括对颜色,动画,某些元素是否可见以及布局的具体引用。

1%怎么样?我在开始时说过,将99%的相关数据放在99%的时间里是不可能的。但是,如果我的应用程序正在建模一个UI概念(比如颜色选择器),那么我的模型很自然会有一个颜色概念。话虽如此,即便如此,我仍会尝试通过将颜色存储为AGRB值而不是代表颜色的各种.NET类之一来保持UI技术不可知。