【问题标题】:Best practice of when to load data into a ListBox何时将数据加载到 ListBox 的最佳实践
【发布时间】:2014-02-13 04:28:45
【问题描述】:

WPF/VC++ (C++/cx) - Visual Studio 2013

所以我有一个 ListBox,其中填充了我创建的 UserControl。每次页面更改时,数据都会丢失,这是不幸的。因此,我可以选择在每次加载页面时将数据加载到 ListBox 中,或者在页面之间传递数据。他们每个人都有自己的优点和缺点,但有没有首选的做法?

我想要考虑的事情是 ListBox 中有多少个 UserControl,数量可能很大(超过 10000 个),以及数据是如何存储的。现在我将数据存储在 AVLTree 中,主要用于组织,因此不需要进行排序。只有 10 个页面,其中 6 个通常会被导航到(其中 4 个是很少使用或只使用一次的菜单页面),因此不必经常在页面之间传递数据。每个数据节点的大小只有约 1mb,因此不是很大,但足以在您开始超过 10000 个条目时产生影响(这可能被认为是一种罕见的情况)。

我来自游戏编程,所以速度和效率是首要目标。

是的,这是一个主观问题,但专业人士或一般编程社区可能会有首选方法。

【问题讨论】:

  • Every time the page changes the data is lost, which is unfortunate. - 那是因为您可能将storing the Data 的责任(就内存存储而言)放到了 UI 中,它不属于它。创建一个合适的 ViewModel,你的所有问题都会神奇地得到解决。顺便说一句,发布您当前的代码和 XAML。
  • I suppose the things to think about would be how many of the UserControls are in the ListBox - 同样,UI 不是数据。您不关心 WPF 中的“ListBox 中的用户控件”,因为内置的 UI 虚拟化会根据屏幕上可用的visible 区域仅创建 UI 元素的相关实例,留下“滚动”等式之外的项目。同样,发布您当前的代码和您需要的屏幕截图,我可以告诉您在 WPF 中执行此操作的正确方法。
  • 您应该使用 DataBinding,而不是手动将内容放入 UI。再次发布您当前的代码和 XAML 以及您需要的屏幕截图。
  • 不,WPF 中没有“填充列表框”之类的东西。只有DataBindingINotifyPropertyChanged。这就是WPF 的方式,其他任何事情都会导致一堆无用的不需要的代码。
  • 听起来您需要自学正确的 MVVM 方法。你需要几个小时才能习惯它,特别是如果你来自游戏编程,但相信我,这是值得的。以下是来自 Microsoft 的直接介绍:youtube.com/watch?v=BClf7GZR0DQ 网上有大量教程。祝你好运!

标签: wpf visual-c++ c++-cx


【解决方案1】:

没有更多背景信息,也没有关于你在做什么的细节(因为你不能发布任何代码或截图),我只能告诉你The WPF Mentality背后的基本思想是什么。

WPF 与我听说过的几乎所有其他 UI 框架都确实不同,因为它确实旨在用于以数据为中心的开发。

从头开始,WPF 主要基于DataBinding。这消除了大约 95% 的通过程序代码对 UI 进行任何操作的需要。

举个简单的例子,假设你有一个包含string LastNamestring FirstName 属性的Person 类:

public class Person
{
    public string LastName {get;set;}
    public string FirstName {get;set;}
}

而不是通过像这样编写过程代码隐藏来来回地将数据值传递给 UI:

//Traditional approach, Don't use this in WPF.
this.txtLastName.Text = person.LastName;
this.txtFirstName.Text = person.FirstName;
//...
person.LastName = this.txtLastName.Text;
person.FirstName = this.txtFirstName.Text;

您只需在 XAML 中以声明方式定义 DataBinding

<TextBox Text="{Binding LastName}"/>
<TextBox Text="{Binding FirstName}"/>

然后将 UI 的 DataContext 设置为相关的数据实例:

//Window constructor example
public MainWindow()
{
    InitializeComponent();
    DataContext = new Person();
}

这种方法有以下优点:

  • 很明显Separates UI from Data,由于这些层的独立性,允许大量的可扩展性。您可以在 UI 中添加任何内容,而无需更改应用程序逻辑/业务逻辑中的一行代码。
  • 它减少了样板代码,因为 WPF 负责传递数据 In Both Directions (Data &lt;=&gt; UI)。
  • 它允许基于属性的方法(与基于事件的方法相反)。例如,不需要处理TextBox.TextChanged 事件之类的事情。 WPF 负责在需要时将示例中的 TextBox 中的 Text 值传递给基础数据对象。
  • 它消除了导航可视化树的需要。 WPFVisual Tree 是一个非常复杂的结构,它具有复杂的状态变化和复杂的转换以及复杂的生命周期。您真的不想想要处理这个问题,例如,“填充几个文本框”
  • 在处理 Collections 时,它有助于以自然的方式利用 WPF 的 UI Virtualization 功能(您实际上不必执行默认启用的任何操作)。这在执行时间和内存消耗方面都会导致Huge Performance Gain
  • 最后但同样重要的是,它允许使用 声明式 方法,而不是传统的 命令式 方法。您只需定义数据,然后编写业务逻辑(像往常一样以命令式形式),然后通过 DataBinding 定义 UI 及其与数据的关系。李>

这个基本概念适用于 WPF 中的 EVERYTHING

ListBoxes、ComboBoxes、Menus、TabControls、DataGrids 和所有ItemsControls 完全相同:

您不会“使用 UserControls 填充 ListBox”,而是:

  • 您创建了一个正确的ViewModel,其中包含一个包含您的数据项的IEnumerable&lt;T&gt;ObservableCollection&lt;T&gt; 是首选,因为 WPF 侦听它的 CollectionChanged 事件并在从集合中添加/删除项目时相应地更新 UI:

    public class MyViewModel
    {
        public ObservableCollection<Person> People {get;set;}
    
        //Constructor
        public MyViewModel()
        {
           People = new ObservableCollection<Person>();
    
           //populate the collection here...
        }
    }
    
  • 然后您定义 ListBox 在 XAML 中并使用 WPF 的 Data Templating 功能定义每个项目的 UI 外观:

    <ListBox ItemsSource="{Binding People}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBox Text="{Binding LastName}"/>
                    <TextBox Text="{Binding FirstName}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox> 
    

    注意:如果你想在里面使用一个 UserControl 也是一样的:

            <DataTemplate>
                <my:MyUserControl/>
            </DataTemplate>
    
  • 最后将 UI 的 DataContext 设置为 ViewModel 的一个实例:

    //Window Constructor
    public MainWindow()
    {
         InitializeComponent();
         DataContext = new MyViewModel();
    }
    

注意:我提到了INotifyPropertyChanged cmets 中的接口。此接口必须由 您的数据项或视图模型以支持双向绑定 适当地。否则 WPF 无法“知道”特定属性何时 (例如LastName)已更改并相应地更新UI。一世 认为该主题超出了此答案的范围,并且 因此我不会参与其中。您可以阅读链接的材料,并且 网上也有很多关于它的资料。

正如我已经提到的,我完全没有使用 C++ 的经验,因此所有这些示例都是用 C# 编写的。 请记住,我还提到 WPF 仅支持与 .Net Objects 的数据绑定,并且我认为它不支持较低级别的内存结构,例如您可以在 C++ 中构建的结构。

我的建议是,您将 C# 用于软件的上层面向 UI 的部分,而将 C++ 用于您可能需要的任何较低层的操作。

我强烈建议阅读这篇文章中链接的材料,最重要的是 Rachel 的 WPF Mentality 和 ItemsControl 相关材料。

【讨论】:

  • 这不是处理器密集型的吗?我的意思是,如果 UI 本身和它的控件一直在监听来自它的绑定的数据变化......
  • @HugoRocha 不,使用这种技术,WPF 只为屏幕上可见的项目创建 UI 元素(由于滚动)。这导致enormous performance gain。见UI Virtualizaton。另见MSDN
猜你喜欢
  • 2018-12-06
  • 2011-09-21
  • 1970-01-01
  • 2011-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-03
  • 1970-01-01
相关资源
最近更新 更多