Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/313.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF自定义布局/虚拟化_C#_.net_Wpf_Virtualization - Fatal编程技术网

C# WPF自定义布局/虚拟化

C# WPF自定义布局/虚拟化,c#,.net,wpf,virtualization,C#,.net,Wpf,Virtualization,这就是我试图通过WPF实现的目标。一个文本块作为wrappanel中的标题和下方按钮。问题是这需要滚动等。 我为每个组使用ItemsControl和binding实现了这一点。 我有一个ItemsControl,它有一个stackpanel作为paneltemplate,它的itemtemplate是一个textblock和一个wrappanel 它可以工作,但当项目很多时,在运行缓慢的intel gma+atom机器上实例化时速度很慢。看起来渲染不是问题,而是视觉树的创建。 所以我在这里唯一的

这就是我试图通过WPF实现的目标。一个文本块作为
wrappanel
中的标题和下方按钮。问题是这需要滚动等。 我为每个组使用ItemsControl和binding实现了这一点。 我有一个ItemsControl,它有一个stackpanel作为paneltemplate,它的itemtemplate是一个textblock和一个wrappanel

它可以工作,但当项目很多时,在运行缓慢的intel gma+atom机器上实例化时速度很慢。看起来渲染不是问题,而是视觉树的创建。 所以我在这里唯一的赌注就是用虚拟化创建一个自定义面板,我想是吧

这就是我所做的。
上述解决方案在某些机器上运行缓慢

我正在寻找一个解决方案,它将需要最大100毫秒在慢速机器创建。 多谢各位

更新

 public class PreferenceCheckedConvertor : IMultiValueConverter
    {


    public object Convert(object[] values, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
    {

        var preference = values[0] as OrderItemPreference;
        var items = values[1] as ObservableCollection<OrderItemPreference>;

        var found = items.FirstOrDefault(item => item.Preference.Id == preference.Preference.Id);
        if (found == null)
        {
            return false;
        }
        return true;

    }
    public object[] ConvertBack(object value, Type[] targetTypes,
           object parameter, System.Globalization.CultureInfo culture)
    {
        try
        {
            return null;
        }
        catch (Exception e)
        {
            return null;
        }
    }


}
公共类首选项CheckedConverter:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,
对象参数,System.Globalization.CultureInfo(区域性)
{
var preference=值[0]作为OrderItemPreference;
var项目=作为可观察集合的值[1];
var found=items.FirstOrDefault(item=>item.Preference.Id==Preference.Preference.Id);
if(found==null)
{
返回false;
}
返回true;
}
公共对象[]转换回(对象值,类型[]targetTypes,
对象参数,System.Globalization.CultureInfo(区域性)
{
尝试
{
返回null;
}
捕获(例外e)
{
返回null;
}
}
}
ff

公共类首选项转换器:IMultiValueConverter
{
公共对象转换(对象[]值,类型targetType,
对象参数,System.Globalization.CultureInfo(区域性)
{
变量首选项=值[0]为IEnumerable;
var项目=作为可观察集合的值[1];
var newList=新列表(preferences.Count());
foreach(首选项中的var首选项)
{
var curItem=items.FirstOrDefault(item=>item.Preference.Id==Preference.Id);
if(curItem==null)
{
添加(新的OrderItemPreference()
{
偏好=偏好
});
}
其他的
{
newList.Add(curItem);
}
}
返回newList;
}
公共对象[]转换回(对象值,类型[]targetTypes,
对象参数,System.Globalization.CultureInfo(区域性)
{
尝试
{
返回null;
}
捕获(例外e)
{
返回null;
}
}}

要使WPF布局更快,您需要启用虚拟化。在代码中:

  • 删除包装所有控件的
    ScrollViewer
  • 将顶级
    项控件
    替换为
    列表框

    <ListBox Name="items" HorizontalContentAlignment="Stretch"
             ScrollViewer.HorizontalScrollBarVisibility="Disabled" ... >
    
  • 这将为顶级项目启用虚拟化。在我的电脑上,这允许在1秒内显示100000个项目

    N.B.:

  • 虽然您认为瓶颈是WPF布局,但您可能错了,因为您没有分析您的应用程序。因此,虽然这回答了您的问题,但实际上可能无法解决窗口运行缓慢的问题。分析器不仅可以分析代码,还可以分析框架代码。他们分析电话、记忆等,而不是你的来源。它们是提高性能的一个很好的工具,也是找到性能问题根源的唯一真正方法

  • 为了所有神圣的爱,请阅读!如果您不尝试使示例简短、自包含且可编译,您将没有足够的声誉来解决所有代码问题。为了运行您的示例,我必须创建自己的视图模型,去掉所有不相关的代码,简化绑定,更不用说您自己的各种转换器、控件和绑定了,这些都没有被描述过

  • 更新以支持.NET 4.0

    public static class PixelBasedScrollingBehavior
    {
        public static bool GetIsEnabled (DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }
    
        public static void SetIsEnabled (DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }
    
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(PixelBasedScrollingBehavior),
                new UIPropertyMetadata(false, IsEnabledChanged));
    
        private static void IsEnabledChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var isEnabled = (bool)e.NewValue;
    
            if (d is VirtualizingPanel) {
                if (TrySetScrollUnit(d, isEnabled))
                    return;
                if (!TrySetIsPixelBased(d, isEnabled))
                    throw new InvalidOperationException("Failed to set IsPixelBased or ScrollUnit property.");
            }
            if (d is ItemsControl) {
                TrySetScrollUnit(d, isEnabled);
            }
        }
    
        private static bool TrySetScrollUnit (DependencyObject ctl, bool isEnabled)
        {
            // .NET 4.5: ctl.SetValue(VirtualizingPanel.ScrollUnitProperty, isEnabled ? ScrollUnit.Pixel : ScrollUnit.Item);
    
            var propScrollUnit = typeof(VirtualizingPanel).GetField("ScrollUnitProperty", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
            if (propScrollUnit == null)
                return false;
            var dpScrollUnit = (DependencyProperty)propScrollUnit.GetValue(null);
    
            var assemblyPresentationFramework = typeof(Window).Assembly;
            var typeScrollUnit = assemblyPresentationFramework.GetType("System.Windows.Controls.ScrollUnit");
            if (typeScrollUnit == null)
                return false;
            var valueScrollUnit = Enum.Parse(typeScrollUnit, isEnabled ? "Pixel" : "Item");
    
            ctl.SetValue(dpScrollUnit, valueScrollUnit);
            return true;
        }
    
        private static bool TrySetIsPixelBased (DependencyObject ctl, bool isEnabled)
        {
            // .NET 4.0: ctl.IsPixelBased = isEnabled;
    
            var propIsPixelBased = ctl.GetType().GetProperty("IsPixelBased", BindingFlags.NonPublic | BindingFlags.Instance);
            if (propIsPixelBased == null)
                return false;
    
            propIsPixelBased.SetValue(ctl, isEnabled, null);
            return true;
        }
    }
    
    必须同时在
    列表框
    虚拟化StackPanel
    上设置
    本地:基于像素的ScrollingBehavior.IsEnabled=“True”
    ,否则滚动将在项目模式下工作。代码在.NET4.0中编译。如果安装了.NET 4.5,它将使用新属性

    工作示例:

    main window.xaml

    
    
    <VirtualizingStackPanel Orientation="Vertical" ScrollUnit="Pixel"
                            VirtualizationMode="Recycling"/>
    
    public static class PixelBasedScrollingBehavior
    {
        public static bool GetIsEnabled (DependencyObject obj)
        {
            return (bool)obj.GetValue(IsEnabledProperty);
        }
    
        public static void SetIsEnabled (DependencyObject obj, bool value)
        {
            obj.SetValue(IsEnabledProperty, value);
        }
    
        public static readonly DependencyProperty IsEnabledProperty =
            DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(PixelBasedScrollingBehavior),
                new UIPropertyMetadata(false, IsEnabledChanged));
    
        private static void IsEnabledChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var isEnabled = (bool)e.NewValue;
    
            if (d is VirtualizingPanel) {
                if (TrySetScrollUnit(d, isEnabled))
                    return;
                if (!TrySetIsPixelBased(d, isEnabled))
                    throw new InvalidOperationException("Failed to set IsPixelBased or ScrollUnit property.");
            }
            if (d is ItemsControl) {
                TrySetScrollUnit(d, isEnabled);
            }
        }
    
        private static bool TrySetScrollUnit (DependencyObject ctl, bool isEnabled)
        {
            // .NET 4.5: ctl.SetValue(VirtualizingPanel.ScrollUnitProperty, isEnabled ? ScrollUnit.Pixel : ScrollUnit.Item);
    
            var propScrollUnit = typeof(VirtualizingPanel).GetField("ScrollUnitProperty", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
            if (propScrollUnit == null)
                return false;
            var dpScrollUnit = (DependencyProperty)propScrollUnit.GetValue(null);
    
            var assemblyPresentationFramework = typeof(Window).Assembly;
            var typeScrollUnit = assemblyPresentationFramework.GetType("System.Windows.Controls.ScrollUnit");
            if (typeScrollUnit == null)
                return false;
            var valueScrollUnit = Enum.Parse(typeScrollUnit, isEnabled ? "Pixel" : "Item");
    
            ctl.SetValue(dpScrollUnit, valueScrollUnit);
            return true;
        }
    
        private static bool TrySetIsPixelBased (DependencyObject ctl, bool isEnabled)
        {
            // .NET 4.0: ctl.IsPixelBased = isEnabled;
    
            var propIsPixelBased = ctl.GetType().GetProperty("IsPixelBased", BindingFlags.NonPublic | BindingFlags.Instance);
            if (propIsPixelBased == null)
                return false;
    
            propIsPixelBased.SetValue(ctl, isEnabled, null);
            return true;
        }
    }
    
    using System;
    using System.Collections.ObjectModel;
    using System.Reflection;
    using System.Windows;
    using System.Windows.Controls;
    
    namespace So17371439ItemsLayoutBounty
    {
        public partial class MainWindow
        {
            public ObservableCollection<PreferenceGroup> PreferenceGroups { get; private set; }
    
            public MainWindow ()
            {
                var rnd = new Random();
                PreferenceGroups = new ObservableCollection<PreferenceGroup>();
                for (int i = 0; i < 100000; i++) {
                    var group = new PreferenceGroup { Name = string.Format("Group {0}", i), SelectionMode = rnd.Next(1, 4) };
                    int nprefs = rnd.Next(5, 40);
                    for (int j = 0; j < nprefs; j++)
                        group.Preferences.Add(new Preference { Name = string.Format("Pref {0}", j), Quantity = rnd.Next(100) });
                    PreferenceGroups.Add(group);
                }
                InitializeComponent();
            }
        }
    
        public class PreferenceGroup
        {
            public string Name { get; set; }
            public int SelectionMode { get; set; }
            public ObservableCollection<Preference> Preferences { get; private set; }
    
            public PreferenceGroup ()
            {
                Preferences = new ObservableCollection<Preference>();
            }
        }
    
        public class Preference
        {
            public string Name { get; set; }
            public string GroupId { get; set; }
            public int Quantity { get; set; }
        }
    
        public static class PixelBasedScrollingBehavior
        {
            public static bool GetIsEnabled (DependencyObject obj)
            {
                return (bool)obj.GetValue(IsEnabledProperty);
            }
    
            public static void SetIsEnabled (DependencyObject obj, bool value)
            {
                obj.SetValue(IsEnabledProperty, value);
            }
    
            public static readonly DependencyProperty IsEnabledProperty =
                DependencyProperty.RegisterAttached("IsEnabled", typeof(bool), typeof(PixelBasedScrollingBehavior),
                    new UIPropertyMetadata(false, IsEnabledChanged));
    
            private static void IsEnabledChanged (DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                var isEnabled = (bool)e.NewValue;
    
                if (d is VirtualizingPanel) {
                    if (TrySetScrollUnit(d, isEnabled))
                        return;
                    if (!TrySetIsPixelBased(d, isEnabled))
                        throw new InvalidOperationException("Failed to set IsPixelBased or ScrollUnit property.");
                }
                if (d is ItemsControl) {
                    TrySetScrollUnit(d, isEnabled);
                }
            }
    
            private static bool TrySetScrollUnit (DependencyObject ctl, bool isEnabled)
            {
                // .NET 4.5: ctl.SetValue(VirtualizingPanel.ScrollUnitProperty, isEnabled ? ScrollUnit.Pixel : ScrollUnit.Item);
    
                var propScrollUnit = typeof(VirtualizingPanel).GetField("ScrollUnitProperty", BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy);
                if (propScrollUnit == null)
                    return false;
                var dpScrollUnit = (DependencyProperty)propScrollUnit.GetValue(null);
    
                var assemblyPresentationFramework = typeof(Window).Assembly;
                var typeScrollUnit = assemblyPresentationFramework.GetType("System.Windows.Controls.ScrollUnit");
                if (typeScrollUnit == null)
                    return false;
                var valueScrollUnit = Enum.Parse(typeScrollUnit, isEnabled ? "Pixel" : "Item");
    
                ctl.SetValue(dpScrollUnit, valueScrollUnit);
                return true;
            }
    
            private static bool TrySetIsPixelBased (DependencyObject ctl, bool isEnabled)
            {
                // .NET 4.0: ctl.IsPixelBased = isEnabled;
    
                var propIsPixelBased = ctl.GetType().GetProperty("IsPixelBased", BindingFlags.NonPublic | BindingFlags.Instance);
                if (propIsPixelBased == null)
                    return false;
    
                propIsPixelBased.SetValue(ctl, isEnabled, null);
                return true;
            }
        }
    }