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
}
}
但由于某种原因,我得到了一个很好的旧'对象引用未设置为对象的实例。每当我到达秒表制定者并召集事件时。
答案 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技术不可知。