WPF XAML 속도 최적화 문의

여러 스타일로 WPF LISTBOX를 만들었습니다. 그러나 프로그램이 화면에 LISTBOX를 표시할 때 LISTBOX가 모두 표시될 때까지 시간이 오래 걸립니다.

우선 화면 XML 코드는 다음과 같이 작성되었습니다.

             <telerik:RadListBox Grid.Row="0"
                ItemContainerStyle="{StaticResource ResourceKey=ListBoxItemRoomList}"
                ItemsSource="{Binding Path=Areas[0].Groups}"
                SelectedItem="{Binding Path=SelectedAreas, Mode=TwoWay}"
                Style="{StaticResource ResourceKey=ListBoxRoomList}">
                <telerik:RadListBox.ItemsPanel>
                    <ItemsPanelTemplate>
                        <WrapPanel />
                    </ItemsPanelTemplate>
                </telerik:RadListBox.ItemsPanel>
            </telerik:RadListBox>

그런 다음 Container.xaml에서 다음과 같은 스타일 레이아웃을 만들었습니다

 <Style x:Key="ListBoxItemRoomList" TargetType="{x:Type telerik:RadListBoxItem}">
        <Setter Property="Width" Value="275" />
        <Setter Property="Background" Value="#FFD9D9D9" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="telerik:RadListBoxItem">
                    <Border Margin="5" Background="{TemplateBinding Background}">
                        <Grid Margin="3">
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="30" />
                                <RowDefinition Height="Auto" />
                                <RowDefinition Height="30" />
                                <RowDefinition Height="Auto" />
                            </Grid.RowDefinitions>

                            <Label Grid.Row="0"
                                Padding="0,0,0,0"
                                Content="{Binding Path=FloorNo}"
                                FontSize="20"
                                Style="{StaticResource ResourceKey=LabelFloorHeader}" />

                            <Label Grid.Row="1" Style="{StaticResource ResourceKey=LabelListHeader}">
                                <Grid>
                                    <Border
                                        Width="200"
                                        CornerRadius="2"
                                        Style="{StaticResource ResourceKey=BorderFloorRa}"
                                        Visibility="{Binding Path=West.AssignRa, Converter={StaticResource ResourceKey=DefaultToVisibilityReverse}}">
                                        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="15">
                                            <Run Text="{Binding Path=West.AssignRa.Name}" />
                                            <Run Text="{Binding Path=West.AssignRa.AssignCount, StringFormat={StaticResource ResourceKey=FormatFloorUnit}}" />
                                            <Run Text="{Binding Path=West.AssignRa.ExtraCount, StringFormat={StaticResource ResourceKey=FormatSignCount}}" />
                                        </TextBlock>
                                    </Border>
                                    <TextBlock
                                        VerticalAlignment="Center"
                                        FontSize="20"
                                        Foreground="Red"
                                        Text="{x:Static res:Res.CAP_UNASSIGNED}"
                                        Visibility="{Binding Path=West.AssignRa, Converter={StaticResource ResourceKey=DefaultToVisibility}}" />
                                </Grid>
                            </Label>
                            <ctrl:EFDataGrid Grid.Row="2"
                                ItemsSource="{Binding Path=West.AssignRooms}"
                                ModifyCommand="{Binding Path=DataContext.RoomStatusPopup, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                Style="{DynamicResource ResourceKey=DataGridRoomList}">
                                <ctrl:EFDataGrid.Columns>
                                    <DataGridTemplateColumn>
                                        <DataGridTemplateColumn.CellTemplate>
                                            <DataTemplate>
                                                <CheckBox
                                                    Margin="5,5,0,5"
                                                    HorizontalAlignment="Center"
                                                    Command="{Binding Path=DataContext.CheckRow, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                                    IsChecked="{Binding Path=IsCheck, UpdateSourceTrigger=PropertyChanged}"
                                                    IsEnabled="{Binding Path=IsEnable, UpdateSourceTrigger=PropertyChanged}" />
                                            </DataTemplate>
                                        </DataGridTemplateColumn.CellTemplate>
                                    </DataGridTemplateColumn>

                                    <DataGridTextColumn Width="35" Binding="{Binding Path=Room.RoomNo}" CellStyle="{StaticResource ResourceKey=DataGridCellRoomListNumber}" />
                                    <DataGridTextColumn Width="30" Binding="{Binding Path=TypeCode}" />
                                    <DataGridTextColumn Width="43" Binding="{Binding Path=RoomStatus}" Foreground="Red" />
                                    <DataGridTextColumn Width="50" Binding="{Binding Path=AssignStatus}" CellStyle="{StaticResource ResourceKey=DataGridCellRoomListStatus}" />
                                    <DataGridTextColumn Width="72" Binding="{Binding Path=AssignRa}" CellStyle="{StaticResource ResourceKey=DataGridCellRoomListAssign}" />
                                </ctrl:EFDataGrid.Columns>
                            </ctrl:EFDataGrid>

                            <Label Grid.Row="3" Style="{StaticResource ResourceKey=LabelListHeader}">
                                <Grid>
                                    <Border
                                        Width="200"
                                        CornerRadius="2"
                                        Style="{StaticResource ResourceKey=BorderFloorRa}"
                                        Visibility="{Binding Path=East.AssignRa, Converter={StaticResource ResourceKey=DefaultToVisibilityReverse}}">
                                        <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="15">
                                            <Run Text="{Binding Path=East.AssignRa.Name}" />
                                            <Run Text="{Binding Path=East.AssignRa.AssignCount, StringFormat={StaticResource ResourceKey=FormatFloorUnit}}" />
                                            <Run Text="{Binding Path=East.AssignRa.ExtraCount, StringFormat={StaticResource ResourceKey=FormatSignCount}}" />
                                        </TextBlock>
                                    </Border>
                                    <TextBlock
                                        VerticalAlignment="Center"
                                        FontSize="20"
                                        Foreground="Red"
                                        Text="{x:Static res:Res.CAP_UNASSIGNED}"
                                        Visibility="{Binding Path=East.AssignRa, Converter={StaticResource ResourceKey=DefaultToVisibility}}" />
                                </Grid>
                            </Label>
                            <ctrl:EFDataGrid Grid.Row="4"
                                ItemsSource="{Binding Path=East.AssignRooms}"
                                ModifyCommand="{Binding Path=DataContext.RoomStatusPopup, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                Style="{DynamicResource ResourceKey=DataGridRoomList}">
                                <ctrl:EFDataGrid.Columns>
                                    <DataGridTemplateColumn>
                                        <DataGridTemplateColumn.CellTemplate>
                                            <DataTemplate>
                                                <CheckBox
                                                    Margin="5,5,0,5"
                                                    HorizontalAlignment="Center"
                                                    Command="{Binding Path=DataContext.CheckRow, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                                    IsChecked="{Binding Path=IsCheck, UpdateSourceTrigger=PropertyChanged}"
                                                    IsEnabled="{Binding Path=IsEnable, UpdateSourceTrigger=PropertyChanged}" />
                                            </DataTemplate>
                                        </DataGridTemplateColumn.CellTemplate>
                                    </DataGridTemplateColumn>
                                    <DataGridTextColumn Width="35" Binding="{Binding Path=Room.RoomNo}" CellStyle="{StaticResource ResourceKey=DataGridCellRoomListNumber}" />
                                    <DataGridTextColumn Width="30" Binding="{Binding Path=TypeCode}" />
                                    <DataGridTextColumn Width="43" Binding="{Binding Path=RoomStatus}" Foreground="Red" />
                                    <DataGridTextColumn Width="50" Binding="{Binding Path=AssignStatus}" CellStyle="{StaticResource ResourceKey=DataGridCellRoomListStatus}" />
                                    <DataGridTextColumn Width="72" Binding="{Binding Path=AssignRa}" CellStyle="{StaticResource ResourceKey=DataGridCellRoomListAssign}" />
                                </ctrl:EFDataGrid.Columns>
                            </ctrl:EFDataGrid>
                        </Grid>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

CellStyle은 예시로 이렇게 만들어졌습니다.

  <Style x:Key="DataGridCellRoomListAssign" BasedOn="{StaticResource DataGridCellRoomList}" TargetType="DataGridCell">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type DataGridCell}">
                    <Grid Background="{TemplateBinding Background}">
                        <Grid ToolTip="{StaticResource ResourceKey=ToolTipRoomListAssign}" ToolTipService.ShowDuration="30000" Visibility="{Binding Path=AssignRa, Converter={StaticResource ResourceKey=DefaultToVisibilityReverse}}">
                            <Border Margin="2,1" Style="{StaticResource ResourceKey=BorderFloorRa}">
                                <Border.Visibility>
                                    <MultiBinding Converter="{StaticResource ResourceKey=RoomToVisibilityReverse}">
                                        <Binding Path="AssignRa" />
                                        <Binding Path="AssignFloor.AssignRa" />
                                    </MultiBinding>
                                </Border.Visibility>
                                <Grid Margin="2,0">
                                    <TextBlock HorizontalAlignment="Left" VerticalAlignment="Center" Text="{Binding Path=AssignRa.Name}" />
                                    <Button
                                        Command="{Binding Path=DataContext.RoomRelease, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                        CommandParameter="{Binding}"
                                        IsEnabled="{Binding Path=DataContext.IsUpdatable, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                        Style="{StaticResource ResourceKey=ButtonFloorRa}" />
                                </Grid>
                            </Border>
                            <Border Margin="2,1" Background="Transparent" BorderThickness="0">
                                <Border.Visibility>
                                    <MultiBinding Converter="{StaticResource ResourceKey=RoomToVisibility}">
                                        <Binding Path="AssignRa" />
                                        <Binding Path="AssignFloor.AssignRa" />
                                    </MultiBinding>
                                </Border.Visibility>
                                <Button
                                    Command="{Binding Path=DataContext.RoomRelease, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                    CommandParameter="{Binding}"
                                    IsEnabled="{Binding Path=DataContext.IsUpdatable, RelativeSource={RelativeSource AncestorType=UserControl}}"
                                    Style="{StaticResource ResourceKey=ButtonRoomRa}" />
                            </Border>
                        </Grid>
                        <ctrl:EFToggleButton
                            ApplyCommand="{Binding Path=DataContext.RoomAssign, RelativeSource={RelativeSource AncestorType=UserControl}}"
                            HostGrid="{Binding RelativeSource={RelativeSource AncestorType=ctrl:EFDataGrid}}"
                            Style="{StaticResource ResourceKey=ToggleButtonRoomRa}"
                            TowardData="{Binding}"
                            Usable="{Binding Path=DataContext.IsUpdatable, RelativeSource={RelativeSource AncestorType=UserControl}}"
                            Visibility="{Binding Path=AssignRa, Converter={StaticResource ResourceKey=DefaultToVisibility}}">
                            <i:Interaction.Triggers>
                                <i:EventTrigger EventName="Drop">
                                    <prism:InvokeCommandAction Command="{Binding Path=DataContext.RoomAssign, RelativeSource={RelativeSource AncestorType=UserControl}}" />
                                </i:EventTrigger>
                            </i:Interaction.Triggers>
                        </ctrl:EFToggleButton>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

CellStyle이 스타일에 추가하지 않으면 속도가 약간 향상되지만 많이 향상되지는 않습니다.

속도를 향상시키기 위해 내가 만든 레이아웃을 어떻게 수정할 수 있나요?

저는 속도개선을 위해서 가상화 방법을 사용할려했지만 화면 구성상 가상화는 사용할수 없습니다.

실제로 속도가 느린
샘플 프로젝트를 깃헙에 공유해 주시면 더 도움이 되실 것 같습니다.

2개의 좋아요
...
    <telerik:RadListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel />
        </ItemsPanelTemplate>
    </telerik:RadListBox.ItemsPanel>
...

이 부분에서 WrapPanel 대신 아래 컨트롤을 사용해보세요.

NuGet Gallery | VirtualizingWrapPanel 1.5.7

VirtualizingWrapPanel/GettingStarted.md at v2 · sbaeumlisberger/VirtualizingWrapPanel · GitHub

Telerik에서도 유사한 기능을 제공하는 것 같습니다.
WPF ListBox - VirtualizingWrapPanel - Telerik UI for WPF

그리고 WrapPanel 레이아웃에서 Container.xamlRowDefinitionHeight값이 Auto로 지정되어 있으면 하위 요소들에 대한 Measure를 수행하야 하므로 레이아웃 성능에 성능에 불리합니다. 상위 컨테이너의 WidthHeight를 미리 특정할 수 있으면 성능에 도움이 될 것 같습니다.

    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="30" />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="30" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
1개의 좋아요