从Code-Behind设置用户控件的DataContext

时间:2009-07-08 20:07:53

标签: wpf vb.net mvvm user-controls datacontext

这应该很简单,但它会引发VS2008严重的循环。

我正在尝试使用MVVM的WPF,并且虽然我已经开发了大约15年,并且有一个comp,但我是一个新手。 SCI。学位。在当前的客户端,我需要使用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 usercontrol的构造函数通过将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完成,我的应用程序就会锁定,开始占用内存,并使CPU达到约50%。

我没有正确实例化我的UserControl吗?这一切似乎都归结为DataEntry构造函数中的DataContext赋值。如果我发表评论,该应用程序将按预期工作(当然,网格中没有任何内容)。

如果我将此代码块移动到Button1_Click(基本上将DataEntry的构造函数代码移动到某个级别),该应用程序仍然会失败:

dataViewModel = New ViewModels.DataViewModel
dataViewModel.LoadDataEntries()
dataView.DataContext = dataViewModel

我很难过。任何人都可以给我一些关于我可能做错的提示,甚至是如何调试我的应用程序自身的无限循环?

非常感谢。

3 个答案:

答案 0 :(得分:1)

您的问题的根本原因似乎是您正在加载的原始数据量或者加载该数据的效率低下。话虽如此,您看到应用程序锁定的原因是您在加载数据时锁定了UI线程。

我相信在你的第一种情况下,数据加载已经卸载到另一个线程来加载数据。在第二个示例中,您将实例化UI线程上的控件,因此所有构造函数和加载逻辑都在当前线程(UI线程)上执行。如果您将此工作卸载到另一个线程上,那么您应该看到与第一个示例类似的结果。

答案 1 :(得分:1)

我最终放弃了在UserControl实例化期间(在XAML或代码中)尝试在UserControl上设置DataContext。现在我加载数据并在UserControl中的事件中设置UserControl的DataContext(IsVisibleChanged,我相信)。当我在XAML中实例化UserControl时,我将它的Visibility设置为Hidden。单击Button1时,我将UserControl的Visibility设置为Visible。因此UserControl弹出视图,并加载其数据并设置DataContext。似乎工作,但似乎也非常kludgey。 :-(感谢帮助,伙计们!

答案 2 :(得分:-1)

如果您的控件只需要花费很长时间来填充数据,那么您应该在另一个线程上填充控件,然后通过委托添加它:

由于我不太擅长编写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();
}