从代码隐藏设置用户控件的 DataContext

发布于 2024-07-26 06:04:33 字数 3101 浏览 7 评论 0原文

这应该很简单,但是它会让 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,如下所示:

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

我被难住了。 谁能给我一些关于我可能做错的事情的提示,甚至如何调试我的应用程序陷入的无限循环?

非常感谢。

This should be pretty easy, but it throws VS2008 for a serious loop.

I'm trying out WPF with MVVM, and am a total newbie at it although I've been developing for about 15 years, and have a comp. sci. degree. At the current client, I am required to use VB.Net.

I have renamed my own variables and removed some distractions in the code below, so please forgive me if it's not 100% syntactically perfect! You probably don't really need the code to understand the question, but I'm including it in case it helps.

I have a very simple MainView.xaml file:

<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>

I also have a UserControl called DataView that consists of a 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>

The constructor for the DataView usercontrol sets up the DataContext by binding it to a view model, as shown here:

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

The view model for DataView looks like this (there isn't much in 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

Now, this UserControl works just fine if I instantiate it in XAML. When I run the code, the grid shows up and populates it just fine.

However, the grid takes a long time to load its data, and I want to create this user control programmatically after the button click rather than declaratively instantiating the grid in XAML. I want to instantiate the user control, and insert it as a child of the StackPanel control:

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

When I do this, as soon as the Button1_Click finishes, my application locks up, starts eating RAM, and hits the CPU about 50%.

Am I not instantiating my UserControl properly? It all seems to come down to the DataContext assignment in DataEntry's constructor. If I comment that out, the app works as expected (without anything in the grid, of course).

If I move this code block into Button1_Click (basically moving DataEntry's constructor code up a level), the app still fails:

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

I'm stumped. Can anybody give me some tips on what I could be doing wrong, or even how to debug what infinite loop my app is getting itself into?

Many thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

静水深流 2024-08-02 06:04:34

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

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

If it's only a matter of your control taking a long time to populate data, you should populate the control on another thread then add it through a delegate:

Since I'm not too good at writing VB.NET, but here's the C# equivalent:

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();
}
罗罗贝儿 2024-08-02 06:04:33

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

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

The root cause of your issue appears to be either the raw amount of data you're loading or some inefficiency in how you load that data. Having said that, the reason you're seeing the application lock up is that you're locking the UI thread when loading the data.

I believe that in your first case the data loading has been off loaded onto another thread to load the data. In you second example you're instantiating the control on the UI thread and as a result all the constructor and loading logic is performed on the current thread (the UI thread). If you offload this work onto another thread then you should see similar results to the first example.

屌丝范 2024-08-02 06:04:33

我最终放弃了尝试在 UserControl 实例化期间获取 UserControl 上的 DataContext(无论是在 XAML 中还是在代码中)。 现在,我加载数据并在 UserControl 的事件中设置 UserControlDataContext (IsVisibleChanged,我相信)。 当我在 XAML 中实例化 UserControl 时,我将其 Visibility 设置为 Hidden。 单击 Button1 时,我将 UserControlVisibility 设置为 Visible。 因此,UserControl 弹出到视图中,并加载其数据并设置 DataContext。 似乎有效,但也显得非常笨拙。 :-( 感谢各位的帮助!

I eventually gave up on trying to get the DataContext on the UserControl set during instantiation of the UserControl (either in XAML or code). Now I load up the data and set the DataContext of the UserControl in an event in the UserControl (IsVisibleChanged, I believe). When I instantiate the UserControl in XAML, I have it's Visibility set to Hidden. When Button1 is clicked, I set the UserControl's Visibility to Visible. So the UserControl pops into view, and it loads up its data and DataContext is set. Seems to work, but also seems very kludgey. :-( Thanks for the help, folks!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文