RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1586419
Accepted
ikikaidesu
ikikaidesu
Asked:2024-07-07 19:00:49 +0000 UTC2024-07-07 19:00:49 +0000 UTC 2024-07-07 19:00:49 +0000 UTC

c# WPF 随着时间的推移改变窗口中的内容并传输数据

  • 772

我想知道如何在代码中更改一段时间后窗口中的内容?按照惯例,有Main一个页面,我想将其更改为Additional我在代码中运行的计时器结束时的页面。有一些想法可以通过ContentControl我简单地存储当前视图并在计时器结束时将其更改为Additional,但我还需要Main将数据从零件传输到Additional,这里出现了第二个问题:我可以MainVM存储两者的模型吗交互页面,或者相反,Model为两者创建一个页面VM。我确信这两种方法都不是很好,所以我想知道是否有更好的方法来实现这一点?

c#
  • 1 1 个回答
  • 56 Views

1 个回答

  • Voted
  1. Best Answer
    EvgeniyZ
    2024-07-10T05:58:26Z2024-07-10T05:58:26Z

    最简单的事情,在我看来最适合您的情况,就是通过构造函数请求必要的数据,甚至是另一个虚拟机中所需的虚拟机。这里最重要的是不要混淆图层。

    简单的例子

    视图模型层

    • 家庭虚拟机:

      public partial class MainViewModel : ObservableObject
      {
          [ObservableProperty]
          private object _currentPage;
      
          public MainViewModel()
          {
              CurrentPage = new HomePageViewModel(this);
          }
      }
      
    • VM窗口主页:

      public partial class HomePageViewModel(MainViewModel mainViewModel) : ObservableObject
      {
          private readonly MainViewModel _mainViewModel = mainViewModel;
      
          [ObservableProperty]
          private TimeSpan _time;
      
          [RelayCommand]
          private async Task Run()
          {
              Time = TimeSpan.FromSeconds(5);
              var delay = TimeSpan.FromSeconds(1);
              while (Time > TimeSpan.Zero)
              {
                  await Task.Delay(delay);
                  Time -= delay;
              }
      
              _mainViewModel.CurrentPage = new ResultPageViewModel(Random.Shared.Next(1, 1000));
          }
      }
      
    • 虚拟机结果页面:

      public class ResultPageViewModel(int score)
      {
          public int Score { get; } = score;
      }
      
    • 说明:

      • 正如MainViewModel您所看到的,有一个属性包含当前显示的页面(CurrentPage),我们需要在此虚拟机之外替换它。我应该怎么办?正如我上面所说,在必要时(在我的例子中)通过构造函数传递到该主虚拟机的链接new HomePageViewModel(this);。

      • 我们HomePageViewModel接受这个主虚拟机 ( HomePageViewModel(MainViewModel mainViewModel)) 并保存链接以供以后使用。这就是整个节目。

      • 接下来,您要求一个计时器,HomePageViewModel正如您所看到的,Run单击按钮时将调用一个异步任务,在其中我们只需旋转一个无限循环,直到计时器等于0,并且每次迭代我们都会更改时间和等待指定时间(1 秒)。

      • 在临时“计时器”结束时,我们将主虚拟机的内容更改为ResultPageViewModel,例如,我还向其中传递一个随机数(有条件地是玩家的分数)。请注意,我们再次通过构造函数传递它,但只是一个值。

      • 嗯,ResultPageViewModel它尽可能简单,我们只需获取传入值并将其添加到绑定属性即可。

    XAML

    • 窗户:

      <Window.Resources>
          <DataTemplate DataType="{x:Type local:HomePageViewModel}">
              <local:HomePage />
          </DataTemplate>
          <DataTemplate DataType="{x:Type local:ResultPageViewModel}">
              <local:ResultPage />
          </DataTemplate>
      </Window.Resources>
      
      <ContentPresenter Content="{Binding CurrentPage}" />
      
    • HomePage:

      <StackPanel VerticalAlignment="Center" >
          <TextBlock
              HorizontalAlignment="Center"
              FontSize="30"
              FontWeight="Medium"
              Text="{Binding Time}" />
          <Button
              HorizontalAlignment="Center"
              Command="{Binding RunCommand}"
              Content="Старт" />
      </StackPanel>
      
    • ResultPage:

      <Viewbox>
          <StackPanel>
              <TextBlock
                  Margin="10,0,10,-5"
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center"
                  FontSize="16"
                  FontWeight="Medium"
                  Text="Результат"
                  Typography.Capitals="AllSmallCaps" />
              <TextBlock
                  HorizontalAlignment="Center"
                  VerticalAlignment="Center"
                  FontSize="15"
                  Text="{Binding Score}" />
          </StackPanel>
      </Viewbox>
      

    这一切的结果是:

    结果

    正如你所看到的,一切都已转移,一切正常,内容已更改,计时器正在滴答作响(gif 速度加快)。

    什么问题?

    • VM 层之间有着紧密的联系,这反过来又会产生如下问题:

      • 维护和扩展困难——如果组件紧密耦合,一个组件的更改可能会导致其他组件出现意想不到的后果。

      • 可重用性低——与其他组件紧密耦合的组件通常很难在其他上下文或项目中重用,因为它们依赖于它们之间的关系。

      • 测试困难——紧密耦合的组件通常更难以单独测试。

    我应该怎么办?

    这一切都取决于项目和要求。对于小型项目来说,这种连接不会带来任何特殊问题。但如果项目很大,那么就值得考虑了……让我们尝试解决这些问题:

    • 这里的主要问题是更改主虚拟机中的页面,如果您查看代码,我们就会明白我们需要某种独立的通知机制,这将允许您在一个地方通知并订阅这些另一个中的通知。让我们这样做:

    • 假设有一个类来存储通知类型(可以是任何内容,甚至是单独的通知类型EventArgs(我想我们已经遇到过),以及Action收到这种类型的通知时应该发生的(操作),我们得到一个原始的“事件总线”:

      public class EventBus
      {
          private readonly Dictionary<Type, List<Action<object>>> _subscriptions = [];
      
          public void Subscribe<T>(Action<T> action)
          {
              var type = typeof(T);
              if (!_subscriptions.TryGetValue(type, out List<Action<object>>? value))
              {
                  value = [];
                  _subscriptions[type] = value;
              }
      
              value.Add(x => action((T)x));
          }
      
          public void Publish<T>(T data)
          {
              if (data is null) return;
      
              var type = typeof(T);
              if (_subscriptions.TryGetValue(type, out List<Action<object>>? value))
              {
                  foreach (var action in value)
                  {
                      action?.Invoke(data);
                  }
              }
          }
      }
      
    • 现在我们重写主VM

      public MainViewModel()
      {
          var eventBus = new EventBus();
          eventBus.Subscribe<int>(score => CurrentPage = new ResultPageViewModel(score));
          CurrentPage = new HomePageViewModel(eventBus);
      }
      

      这里我们创建一个“总线”,订阅所需的事件类型,并指定应该发生的操作(VM 更改)。

    • 在HomePageViewModel我们将依赖更改为MainViewModel,EventBus并将VM更改为简单_eventBus.Publish(Random.Shared.Next(1, 1000));

    • 让我们启动并检查。

    正如你所看到的,VM 层现在对 具有“弱依赖” EventBus,层之间没有连接,并且有了这个总线,我们现在可以在任何地方订阅任何事件。您可能想知道“但是我们有一些东西new ResultPageViewModel(score);使它MainViewModel依赖于- 是的,它是,但是如果它旨在管理不同之间的转换,ResultPageViewModel这不一定是问题。在这个例子中,它可以被视为协调器或导航但我们可以通过制作一个“工厂”来摆脱这种依赖,例如我们制作一个接口:MainViewModelViewModelMainViewModel

    public interface IViewModelFactory
    {
        ResultPageViewModel CreateResultPageViewModel(int score);
        // Другие методы для создания других ViewModel...
    }
    

    我们在 中实现了它MainViewModel,就这样,它不再直接创建其他VM。但同样,这一切都取决于您的应用程序和您的要求。

    顺便说一句,“事件总线”在库中CommunityToolkit.MVVM,在本示例中使用它来生成INotifyPropertyChanged和ICommand,所以如果您使用这个库,就会知道那里的一切都更加简单(我在这里写了一个示例)。

    其实他已经把一切都解释清楚了,并且为以后的发展做好了储备。
    祝你升学顺利!

    • 1

相关问题

  • 使用嵌套类导出 xml 文件

  • 分层数据模板 [WPF]

  • 如何在 WPF 中为 ListView 手动创建列?

  • 在 2D 空间中,Collider 2D 挂在玩家身上,它对敌人的重量相同,我需要它这样当它们碰撞时,它们不会飞向不同的方向。统一

  • 如何在 c# 中使用 python 神经网络来创建语音合成?

  • 如何知道类中的方法是否属于接口?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5