如何在MVVM的View部分动态加载时向WPF提供反馈

  • 本文关键字:WPF 加载 动态 MVVM View c# wpf
  • 更新时间 :
  • 英文 :


对于研究,我已经阅读了这篇文章,并使用BackgroundWorker编写了许多应用程序。没有文章提供关于如何在加载UI时更新UI的任何信息。我已经创建了自己的BusyIndicator(因为这在WPF中是缺乏的),但是当UI更新时它也无法更新。我肯定我不是第一个动态创建UI的人,所以这必须由某人解决,但我找不到它。

我想在动态UI加载时向用户提供反馈。首先介绍一下背景。该应用程序是从最初用Silverlight编写的JavaScript应用程序(通过Typescript)转换而来的。应用程序读取一个"视图"。作为XML,然后在XML中动态地创建/加载控件。正是在这个过程中,我想提供一些反馈,但由于UI中的控件加载实际上是在UI线程上,并且反馈也在UI线程上,因此没有向用户提供有效的沟通。

我已经尝试使用调度程序调用委托在主UI线程或单个用户界面元素(ProgressBar)。使用这些方法中的任何一种都可以更新,但只有在其他所有方法都完成之后才能更新。

我没有尝试使用后台线程,因为当XML被解析时,每个控件都被创建并添加到需要在UI线程上的XML中。

谁能给我一个可能的解决方案?是否有一种方法来强制我的忙指示器更新,而仍然加载UI?编辑:提供请求的代码

实际发生的情况是,用户从两个组合框中进行选择,以提供他们感兴趣的数据系统和数据系统的视图。选择视图后,将运行查询以从数据库获取XML。XML定义了控件类型、位置、大小和警报值、警报颜色等。我们目前有超过1000个不同的视图供用户选择,其中一些视图包含1000个控件。

在下面的代码片段中,动态创建了一个控件类型MT_BoxTextCtrl,这是一个简单的标签和只读文本框。显然,实际的代码要复杂得多,并且包含对xml的解析,但这里基本上显示了发生的事情。

private void Window_Loaded(object sender, RoutedEventArgs e)
{
//simulate reading of xml.  Here we just put in labels, Textboxs and new tabItems
TabItem aTab = null;
Canvas activeCanvas = null;
int tabHeader = 1;
for(int i=0, c=0, r=0; i<10000; i++)
{
// the XML parser would read the xml which contains nodes to define new tabs and the controls contiained within the tab
// here we are just simulating what occurs, ie create the tab/scrollViewer and canvas.  Then add controls to it.
if(i%250 == 0)
{
aTab = new TabItem();
aTab.Header = "TabItem " + tabHeader;
tabHeader++;
ScrollViewer sv = new ScrollViewer();
activeCanvas = new Canvas();
activeCanvas.Name = String.Format("_Canvas{0}", _TabCtrl.Items.Count);
activeCanvas.VerticalAlignment = VerticalAlignment.Top;
activeCanvas.HorizontalAlignment = HorizontalAlignment.Left;
activeCanvas.Height = 0D;
activeCanvas.Width = 0D;
sv.HorizontalScrollBarVisibility = ScrollBarVisibility.Visible;
sv.Content = activeCanvas;
aTab.Content = sv;
_TabCtrl.Items.Add(aTab);
r = c = 0;
}
MT_BoxTextCtrl ctrl = new MT_BoxTextCtrl();
ctrl.Label = "Gauge " + i.ToString();
ctrl.Location = new Point(c * 200, r * 40);
ctrl.Width = 200;
ctrl.Height = 40;
ctrl.LblLocation = OpsViewer.Classes.MT_Helper.Loc.left;
activeCanvas.Children.Add(ctrl);
Canvas.SetLeft(ctrl, ctrl.Location.X);
Canvas.SetTop(ctrl, ctrl.Location.Y);
if (activeCanvas.Height < ctrl.Location.Y + ctrl.Height)
activeCanvas.Height = ctrl.Location.Y + ctrl.Height + 10;
if (activeCanvas.Width < ctrl.Location.X + ctrl.Width)
activeCanvas.Width = ctrl.Location.X + ctrl.Width + 100;

r++;
if (r > 20)
{
r = 0;
c++;
}
}
}

这里是完整的mainwindow。xaml

<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" WindowState="Maximized"
Loaded="Window_Loaded">
<TabControl x:Name="_TabCtrl" Grid.Row="1" Grid.ColumnSpan="2"  Margin="2,2,2,2" Background="{x:Null}">
</TabControl>

您会注意到,这种工作方式提供了另一种抽象层次,因为视图实际上甚至没有在应用程序中定义,并且可以快速创建/修改而无需重新分发客户端。以同样的方式MVVM模型从视图中删除了数据,现在我已经从应用程序中删除了视图。

这一切都工作,但它需要超过5到10秒来创建控制。在此期间,UI线程忙于完成其工作或制作控件。

我的问题仍然是如何在"加载"过程中提供用户反馈。时间。

我想到的解决方案是创建第二个在自己的线程中运行的应用程序。在主应用程序中,我打开Windows Forms,其中包含一个ProgressBar和一个标签。随着进度的推进,我会"踩栏"并更改标签。

我最初的设计使用的代码作为另一个应用程序的启动画面。在思考这个问题时,我意识到启动屏幕实际上是我所寻找的,因为它在代码初始化时提供反馈。对于这个特殊的解决方案,我只是简单地修改了启动屏幕,使其看起来更像一个反馈对话框,并在每次出现新"视图"时将其弹出。是由用户加载的

最新更新