这应该很简单,但是它会让 VS2008 陷入严重的循环。
我正在尝试使用 MVVM 的 WPF,虽然我已经开发了大约 15 年,并且有一个比较,但我完全是新手。科学。程度。在当前的客户端,我需要使用VB.Net。
我已经重命名了我自己的变量,并删除了下面代码中的一些干扰,所以如果它在语法上不是 100% 完美,请原谅我!您可能并不真正需要代码来理解这个问题,但我将其包含在内,以防它有帮助。
我有一个非常简单的 MainView.xaml 文件:
<Window x:Class="MyApp.Views.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window" Height="400" Width="800" Name="MainWindow">
<Button Name="Button1">Show Grid</Button>
<StackPanel Name="teststack" Visibility="Hidden"/>
</Window>
我还有一个名为 DataView 的 UserControl,它由 DataGrid 组成:
<UserControl x:Class="MyApp.Views.DataView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfToolkit="http://schemas.microsoft.com/wpf/2008/toolkit" >
<Grid>
<WpfToolkit:DataGrid
ItemsSource="{Binding Path=Entries}" SelectionMode="Extended">
</WpfToolkit:DataGrid>
</Grid>
</UserControl>
DataView 用户控件的构造函数通过将 DataContext 绑定到视图模型来设置 DataContext,如下所示:
Partial Public Class DataView
Dim dataViewModel As ViewModels.DataViewModel
Public Sub New()
InitializeComponent()
dataViewModel = New ViewModels.DataViewModel
dataViewModel.LoadDataEntries()
DataContext = dataViewModel
End Sub
End Class
DataView 的视图模型如下所示(ViewModelBase 中没有太多内容):
Public Class DataViewModel
Inherits ViewModelBase
Public Sub New()
End Sub
Private _entries As ObservableCollection(Of DataEntryViewModel) = New ObservableCollection(Of DataEntryViewModel)
Public ReadOnly Property Entries() As ObservableCollection(Of DataEntryViewModel)
Get
Return _entries
End Get
End Property
Public Sub LoadDataEntries()
Dim dataEntryList As List(Of DataEntry) = DataEntry.LoadDataEntries()
For Each dataentry As Models.DataEntry In dataEntryList
_entries.Add(New DataEntryViewModel(dataentry))
Next
End Sub
End Class
现在,如果我在 XAML 中实例化这个 UserControl,它就可以正常工作。当我运行代码时,网格会显示并填充它,效果很好。
但是,网格需要很长时间才能加载其数据,并且我想在单击按钮后以编程方式创建此用户控件,而不是在 XAML 中以声明方式实例化网格。我想实例化用户控件,并将其作为 StackPanel 控件的子控件插入:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
Dim dataView As New DataView
teststack.Children.Add(dataView)
End Sub
当我这样做时,一旦 Button1_Click 完成,我的应用程序就会锁定,开始消耗 RAM,并占用 CPU 大约 50%。
我没有正确实例化我的 UserControl 吗?这一切似乎都归结为 DataEntry 构造函数中的 DataContext 赋值。如果我注释掉,该应用程序将按预期工作(当然,网格中没有任何内容)。
如果我将此代码块移动到 Button1_Click 中(基本上将 DataEntry 的构造函数代码向上移动一个级别),应用程序仍然会失败:
dataViewModel = New ViewModels.DataViewModel
dataViewModel.LoadDataEntries()
dataView.DataContext = dataViewModel
我被难住了。谁能给我一些关于我可能做错的事情的提示,甚至如何调试我的应用程序陷入的无限循环?
非常感谢。
问题的根本原因似乎是您正在加载的原始数据量或加载数据的效率低下。话虽如此,您看到应用程序锁定的原因是您在加载数据时锁定了 UI 线程。
我相信在您的第一种情况下,数据加载已被卸载到另一个线程来加载数据。在第二个示例中,您在 UI 线程上实例化控件,因此所有构造函数和加载逻辑都在当前线程(UI 线程)上执行。如果您将此工作卸载到另一个线程上,那么您应该会看到与第一个示例类似的结果。
我最终放弃了在
DataContext
实例化期间(在 XAML 或代码中)获取 UserControl
集上的 UserControl
的尝试。现在,我加载数据并在 DataContext
中的事件中设置 UserControl
的 UserControl
(我相信是 IsVisibleChanged
)。当我在 XAML 中实例化 UserControl
时,我将其 Visibility
设置为 Hidden
。当单击 Button1
时,我将 UserControl
的 Visibility
设置为 Visible
。因此 UserControl
会弹出视图,并加载其数据并设置 DataContext
。似乎有效,但也显得非常笨拙。 :-( 感谢各位的帮助!
如果只是您的控件需要很长时间来填充数据的问题,您应该在另一个线程上填充控件,然后通过委托添加它:
因为我不太擅长编写 VB.NET,但这是 C# 的等效内容:
private void Button1_Click(Object sender, RoutedEventArgs e)
{
Thread thr = new Thread(delegate()
{
DataView dataView = new DataView();
this.Dispatcher.BeginInvoke((Action) delegate()
{
teststack.Children.Add(dataView);
});
});
thr.Start();
}