我想知道如何在代码中更改一段时间后窗口中的内容?按照惯例,有Main
一个页面,我想将其更改为Additional
我在代码中运行的计时器结束时的页面。有一些想法可以通过ContentControl
我简单地存储当前视图并在计时器结束时将其更改为Additional
,但我还需要Main
将数据从零件传输到Additional
,这里出现了第二个问题:我可以MainVM
存储两者的模型吗交互页面,或者相反,Model
为两者创建一个页面VM
。我确信这两种方法都不是很好,所以我想知道是否有更好的方法来实现这一点?
最简单的事情,在我看来最适合您的情况,就是通过构造函数请求必要的数据,甚至是另一个虚拟机中所需的虚拟机。这里最重要的是不要混淆图层。
简单的例子
视图模型层
家庭虚拟机:
VM窗口主页:
虚拟机结果页面:
说明:
正如
MainViewModel
您所看到的,有一个属性包含当前显示的页面(CurrentPage
),我们需要在此虚拟机之外替换它。我应该怎么办?正如我上面所说,在必要时(在我的例子中)通过构造函数传递到该主虚拟机的链接new HomePageViewModel(this);
。我们
HomePageViewModel
接受这个主虚拟机 (HomePageViewModel(MainViewModel mainViewModel)
) 并保存链接以供以后使用。这就是整个节目。接下来,您要求一个计时器,
HomePageViewModel
正如您所看到的,Run
单击按钮时将调用一个异步任务,在其中我们只需旋转一个无限循环,直到计时器等于0
,并且每次迭代我们都会更改时间和等待指定时间(1 秒)。在临时“计时器”结束时,我们将主虚拟机的内容更改为
ResultPageViewModel
,例如,我还向其中传递一个随机数(有条件地是玩家的分数)。请注意,我们再次通过构造函数传递它,但只是一个值。嗯,
ResultPageViewModel
它尽可能简单,我们只需获取传入值并将其添加到绑定属性即可。XAML
窗户:
HomePage
:ResultPage
:这一切的结果是:
正如你所看到的,一切都已转移,一切正常,内容已更改,计时器正在滴答作响(gif 速度加快)。
什么问题?
VM 层之间有着紧密的联系,这反过来又会产生如下问题:
维护和扩展困难——如果组件紧密耦合,一个组件的更改可能会导致其他组件出现意想不到的后果。
可重用性低——与其他组件紧密耦合的组件通常很难在其他上下文或项目中重用,因为它们依赖于它们之间的关系。
测试困难——紧密耦合的组件通常更难以单独测试。
我应该怎么办?
这一切都取决于项目和要求。对于小型项目来说,这种连接不会带来任何特殊问题。但如果项目很大,那么就值得考虑了……让我们尝试解决这些问题:
这里的主要问题是更改主虚拟机中的页面,如果您查看代码,我们就会明白我们需要某种独立的通知机制,这将允许您在一个地方通知并订阅这些另一个中的通知。让我们这样做:
假设有一个类来存储通知类型(可以是任何内容,甚至是单独的通知类型
EventArgs
(我想我们已经遇到过),以及Action
收到这种类型的通知时应该发生的(操作),我们得到一个原始的“事件总线”:现在我们重写主VM
这里我们创建一个“总线”,订阅所需的事件类型,并指定应该发生的操作(VM 更改)。
在
HomePageViewModel
我们将依赖更改为MainViewModel
,EventBus
并将VM更改为简单_eventBus.Publish(Random.Shared.Next(1, 1000));
让我们启动并检查。
正如你所看到的,VM 层现在对 具有“弱依赖”
EventBus
,层之间没有连接,并且有了这个总线,我们现在可以在任何地方订阅任何事件。您可能想知道“但是我们有一些东西new ResultPageViewModel(score);
使它MainViewModel
依赖于- 是的,它是,但是如果它旨在管理不同之间的转换,ResultPageViewModel
这不一定是问题。在这个例子中,它可以被视为协调器或导航但我们可以通过制作一个“工厂”来摆脱这种依赖,例如我们制作一个接口:MainViewModel
ViewModel
MainViewModel
我们在 中实现了它
MainViewModel
,就这样,它不再直接创建其他VM。但同样,这一切都取决于您的应用程序和您的要求。顺便说一句,“事件总线”在库中
CommunityToolkit.MVVM
,在本示例中使用它来生成INotifyPropertyChanged
和ICommand
,所以如果您使用这个库,就会知道那里的一切都更加简单(我在这里写了一个示例)。其实他已经把一切都解释清楚了,并且为以后的发展做好了储备。
祝你升学顺利!