【问题标题】:25 WPF Calendars in one window, takes 5 seconds to open Window25个WPF日历在一个窗口中,打开窗口需要5秒
【发布时间】:2013-08-31 07:53:44
【问题描述】:

我是 WPF 的新手,并试图了解它可能会慢多少。我在 Visual Studio 2010 (.NET 4) 中启动了一个新的 WPF 应用程序,并创建了这个 XAML:

<Window x:Class="CalendarTest1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="800" Width="1000">
    <WrapPanel>
        <Calendar />
        <Calendar />
        <Calendar />
...repeats for a total of 25 calendar objects...
    </WrapPanel>
</Window>

当我在 IDE 中运行我的应用程序时,窗口打开需要 5 秒钟。打开后,它会快速重绘(当我调整它的大小时),一切看起来都很流畅。

我的电脑不是最快的:AMD 双核 2.3GHz、2GB RAM、XP 32 位操作系统、板载视频。

我可以放置 25 个按钮,而不是日历,并且加载时间不到 1 秒。

我正在尝试在 MS Outlook 日历的日视图中创建类似于小月历的内容,如下所示:

所以我想我可以使用 WrapPanel 并在调整大小时添加/删除日历控件。我可能不需要 25,但即使使用 9 或 12,它也比我想象的要慢(我有一个旧版 Win32 应用程序,它在不到 1 秒的时间内显示 18 个这样的日历)。

我的问题是:

Calendar 控件是否因为某种设计而变慢 - 要么是糟糕的设计,要么只是不适合这种用途,还是因为它试图显示大量数据/控件/信息而变慢?

如果我费心创建自己的控件,假设我使用了一个好的设计(欢迎提出一般想法),它会不会快很多,或者这只是 WPF 的“典型”?

我可以做些什么来加快默认日历控件的使用速度?

【问题讨论】:

  • 您是第一次测量还是总是需要 5 秒?
  • 尝试测试 exe,而不是 Visual Studio 调试器。
  • 总是需要 5 秒,即使我直接运行 EXE,而不是从 IDE 运行。我的电脑不是很快.. 但它可以很好地处理 VS 2010,所以我希望这个小例子很快。
  • Calendar 控件是一个本机控件,而且是一个复杂的控件。所以是的,它肯定不是最快的。这使您的屏幕非常糟糕。它甚至与您的最终目标相似吗?
  • trying to get an idea of just how much slower it might be - 与什么相比?到winforms? Please...

标签: c# wpf performance xaml calendar


【解决方案1】:

本身不是答案,但将其添加到 Window.Resources 可将我机器中的加载时间减少 50%(现在 25 个日历的加载时间不到 1 秒)

    <Window.Resources>
        <Style TargetType="CalendarDayButton">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="CalendarDayButton">
                        <ContentPresenter ContentSource="Content" Margin="2"/>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style TargetType="Calendar">
            <Setter Property="CalendarDayButtonStyle" Value="{StaticResource {x:Type CalendarDayButton}}"/>
        </Style>
    </Window.Resources>

编辑:

这种视觉变化不会影响控件的功能。所有 Calendar's Day 项仍为Selectable,您可以绑定Calendar.SelectedDate 属性。

没有任何视觉指示表明项目已被选中,因此单击日期似乎无济于事。

只需将其添加到您的 ControlTemplate:

                <ControlTemplate TargetType="CalendarDayButton">
                    <ContentPresenter ContentSource="Content" Margin="2"/>

                    <ControlTemplate.Triggers>
                        <!-- Set The FontWeight to "Bold" when Selected -->
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="FontWeight" Value="Bold"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>

您可以使用此ControlTemplate 及其Triggers 来添加视觉效果。请记住,模板越复杂,加载所需的时间就越长。

【讨论】:

  • +1 好。用简单的 TextBlock 替换 CalendarButton
  • 这里也有 50%,降至 2 秒左右。用户需要能够每天点击。我目前正在按照您的建议查看 ItemsControl,我认为“答案”实际上归结为不使用此控件,但我将能够创建自己的版本,而且速度会很快,所以不必一起删除 WPF。
  • @eselk Day 控件仍然可以点击。选择日期时没有视觉指示。查看我的编辑
  • 哦,非常好。你认为我应该继续优化这种类型(修改模板),还是从头开始创建一个新的日历控件会更好?
  • @eselk 旁白:一旦你学会了 WPF+MVVM,你就再也不想回头了。
【解决方案2】:

这将使您了解什么是日历 与使用 Snoop 的按钮。是的,我们确实预计很多日历会花费更多的渲染时间。如果您需要大量使用它们,我会尝试创建自己的更简单的和/或虚拟化它们

这是一个按钮,三个孩子...

这是一个日历,有 522 个孩子。请注意,我没有展开的每个 CalendarButtons 仍然有 9 个孩子

【讨论】:

  • 好的,这就是我的猜测,但不知道如何确定(还没有学习这些工具/等)。我认为可以创建一个像 Calendar 控件这样的控件,它几乎没有那么多元素,并且会使其更快?我猜这相当于在 WPF 之前使用 1 个所有者绘制的窗口/控件,而不是在每个月的每一天都使用控件。
  • 是的,如果没有那么多元素,它会渲染得更快。所有这些CalendarDayButtons 都是日历控件中的可点击方块。所有这些都包含网格和矩形。例如,如果您不需要该功能,则可以通过删除它们来节省一些时间。总的来说,日历并不简单,因为几乎每个人都只会使用一个,而按钮很简单,因为通常你有很多按钮。日历的性质也使其成为更复杂的控件。
  • 我确实需要它们都是可点击的(用户可以点击任何一天到达那个日期),但我想这将归结为速度与编码易用性的权衡。而不是单独的对象,将有一个对象,然后必须根据鼠标的 X、Y 计算哪一天被点击。感觉就像Win32重新来过。我认为它在 WPF 中可能会有所不同,因为这些对象中的每一个都不是窗口句柄,并且开销可能会更少。
  • @eselk 您的目标是什么 .Net 版本?您应该在 Windows 7 机器上进行测试。 XP 已经过时了。
  • 我接受这个答案。虽然它没有给我任何关于从哪里开始创建自己的想法,但它确实表明使用内置控件不是要走的路。此外,在我看来,这表明 WPF 并不慢,但这个控件只是臃肿。所以我觉得我应该花时间创建自己的优化控件,并且它会很好地工作,并且我不需要因为一个控件不能很好地满足我的需求而避免使用 WPF。
【解决方案3】:

我将更新它,因为我有时间完成这个新控件,但到目前为止,我向自己证明了我可以在一个窗口中拥有大量控件并且仍然可以快速加载它。在这种情况下,1050 个文本块(7 列 * 6 行 * 我的用户控件的 25 个实例),我的窗口在不到 1 秒的时间内加载。

到目前为止,这是我的简单用户控件:

<UserControl x:Class="FastCalendar.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:FastCalendar"
             xmlns:vm="clr-namespace:FastCalendar.ViewModels"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" Margin="5">
    <UserControl.Resources>
        <vm:MainViewModel x:Key="ViewModel" />
    </UserControl.Resources>
    <ItemsControl Width="180" Height="170" ItemsSource="{Binding Path=Days, Source={StaticResource ViewModel}}">
        <ItemsControl.ItemContainerStyle>
            <Style>
                <Setter Property="Grid.Row" Value="{Binding Path=Row}" />
                <Setter Property="Grid.Column" Value="{Binding Path=Column}" />
            </Style>
        </ItemsControl.ItemContainerStyle>

        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Path=Day}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>

        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <Grid ShowGridLines="True">
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                </Grid>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>

    </ItemsControl>
</UserControl>

我将其中的 25 个放在 WrapPanel 中,它在不到 1 秒的时间内加载完毕。我仍然需要向我的用户控件添加更多控件和样式,但我认为它仍然会比内置的日历控件快得多(我希望如此)。

p.s.-即使窗口上有 50 个我的用户控件副本,它也会在大约 1 秒内加载。

【讨论】:

  • 当我开始为每个单元格/天设置基本属性(例如 Horizo​​ntalAlignment=Center 和其他一些非常基本的东西)时,它对我来说又变得太慢了。所以我只使用 Canvas 并覆盖 OnRender 来重做这个。更多的工作,但它的速度要快 100 到 1000 倍,所以对我来说是值得的(对于加载速度为 50 毫秒而不是 1000-2000 毫秒的快速界面,即使在较慢的 PC 上也是如此)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多