【问题标题】:How to temporary disable WPF Listview virtualization?如何临时禁用 WPF Listview 虚拟化?
【发布时间】:2015-10-06 11:21:00
【问题描述】:

在自定义 ListView 控件上,我正在开发一个“导出到 Excel”小按钮,它将 ListView 的所有内容发送到 Excel。由于此按钮嵌入在 ListView 控件中,因此我不知道列出了哪些类型的对象或显示了哪些列。

所以我的方法是通用的,只需解析所有列标题和所有行以将数据导出到 Excel。但是在解析不可见的 ListViewItem 时,您会得到 null 结果。一个解决方案是在我的 ListView 上设置 VirtualizingStackPanel.VirtualizationMode="False" 但当您有数千行时它会强烈影响 GUI 体验。

我正在寻找一种方法来为我的通用导出方法加载所有 ListViewItem,并为 GUI 保持虚拟化。

有人可以帮我吗?

谢谢。

【问题讨论】:

  • 我不明白你想要什么,关闭虚拟化的唯一方法是将 VirtualizingStackPanel.IsVirtualizingProperty 设置为 false。等完成你的方法后可以再次开启。
  • 您应该只为您的任务使用底层数据,而不是生成的 UI 容器。
  • 基础数据是来自 SQL 数据库的表数据,与我显示的列(甚至是链接表)一样多的字段。我的应用程序中有很多 ListView,这意味着我必须返回每个视图并定义应该导出到 Excel 的内容。所以我正在寻找一种方法来强制 ListView 通过代码加载所有项目。
  • 您可以使用 ListView 的 ItemGenerator 做一些事情,使其生成视图容器,然后向它询问每个项目的视图。我现在不在电脑前寻找细节。

标签: wpf listview virtualization listviewitem


【解决方案1】:

我终于来了 Reflection 来解决我的问题。基本上,我首先解析所有列以找到绑定的属性名称。然后对 ListView 中的 Items 集合进行一些反思,以找到属性值。

这是代码(尚未完善):

private void OnExportToExcel(object sender, ExecutedRoutedEventArgs args)
    {
        if (this.Items.Count > 0)
        {
            // Ensure we have a visible and selected item
            if (this.SelectedItem == null)
                this.SelectedItem = this.Items[0];
            this.ScrollIntoView(this.SelectedItem);

            // Allow UI thread to update first or our selected lvi will be null if not visible
            UIHelpers.AllowUIToUpdate();

            List<string> columnPropertyBindingPathList = new List<string>();
            int colIndex = 0;

            // Get column binding path of underlying data
            foreach (GridViewColumn h in ((GridView)this.View).Columns)
            {
                string bindingPath = "";

                if (h.DisplayMemberBinding != null)
                {
                    bindingPath = (h.DisplayMemberBinding as Binding).Path.Path;
                }
                else
                {
                    ListViewItem lvi = this.ItemContainerGenerator.ContainerFromIndex(this.SelectedIndex) as ListViewItem;
                    if (lvi != null)
                    {
                        GridViewRowPresenter gvp = UIHelpers.FindVisualChild<GridViewRowPresenter>(lvi);
                        DependencyObject col = VisualTreeHelper.GetChild(gvp, colIndex);
                        TextBlock tb = col as TextBlock;
                        if (tb == null)
                        {
                            tb = UIHelpers.FindVisualChild<TextBlock>(col);
                            bindingPath = BindingOperations.GetBinding(tb, TextBlock.TextProperty).Path.Path;
                        }
                    }
                }

                colIndex++;
                if (bindingPath != "")
                    columnPropertyBindingPathList.Add(bindingPath);
            }

            if (columnPropertyBindingPathList.Count > 0)
            {
                Mouse.SetCursor(Cursors.Wait);

                // Init array to export to excel
                object[,] dataArray = new object[this.Items.Count + 1, columnPropertyBindingPathList.Count];

                // Add column header
                for (int colCnt = 0; colCnt < columnPropertyBindingPathList.Count; colCnt++)
                    dataArray[0, colCnt] = columnPropertyBindingPathList[colCnt];

                // Reflection to read underlying objects
                int rowCnt = 1;
                foreach (object obj in this.Items)
                {
                    for (int colCnt = 0; colCnt < columnPropertyBindingPathList.Count; colCnt++)
                        dataArray[rowCnt, colCnt] = UIHelpers.GetPropValue(columnPropertyBindingPathList[colCnt], obj);

                    rowCnt++;
                }

                Mouse.SetCursor(Cursors.Arrow);

                // Throw event
                RoutedEventArgs newEventArgs = new RoutedEventArgs(EmListView.ExportToExcelEvent);
                newEventArgs.Source = dataArray;
                RaiseEvent(newEventArgs);
            }
            else
            {
                // Throw event
                RoutedEventArgs newEventArgs = new RoutedEventArgs(EmListView.ExportToExcelEvent);
                newEventArgs.Source = null;
                RaiseEvent(newEventArgs);
            }
        }
        else
        {
            // Throw event
            RoutedEventArgs newEventArgs = new RoutedEventArgs(EmListView.ExportToExcelEvent);
            newEventArgs.Source = null;
            RaiseEvent(newEventArgs);
        }
    }

UIHelpers 方法:

/// <summary>
    /// Give the UI thread the time to refresh
    /// </summary>
    public static void AllowUIToUpdate()
    {
        DispatcherFrame frame = new DispatcherFrame();

        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Render, new DispatcherOperationCallback(delegate(object parameter)
        {
            frame.Continue = false;
            return null;
        }), null);

        Dispatcher.PushFrame(frame);
    }

    /// <summary>
    /// Find a visual child type inside a DependencyObject
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(obj, i);
            if (child != null && child is T)
                return (T)child;
            else
            {
                T childOfChild = FindVisualChild<T>(child);
                if (childOfChild != null)
                    return childOfChild;
            }
        }
        return null;
    }

    /// <summary>
    /// Find a property value inside a object (even for multi level property)
    /// </summary>
    /// <param name="name"></param>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static Object GetPropValue(String name, Object obj)
    {
        foreach (String part in name.Split('.'))
        {
            if (obj == null) { return null; }

            Type type = obj.GetType();
            PropertyInfo info = type.GetProperty(part);

            if (info == null) { return null; }

            obj = info.GetValue(obj, null);
        }

        return obj;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多