1

I've got about 300+ buttons that are represented in a grid. When I try to render this, it takes a good 5 seconds to load up all buttons. Is there any alternative? Functionality that already exists such as hover over, mouse enter, left button click etc are all needed... just wondering if there is a way to speed up button rendering.

Buttons are created dynamically in a grid, with an ItemsControl, that contains an ItemsPanelTemplate (that is just a grid definition of width and height), a DataTemplate in ItemsControl.Resources, where the ToggleButton(s) that are created dynamically (300+) are created.

The datatemplate in the ItemsControl.Resources looks like this:

<DataTemplate DataType="{x:Type engine:Weodel}">
    <ToggleButton
            Tag="{Binding}"
            IsChecked="{Binding IsSelected}"
            Height="{Binding ElementName=weItemControl, 
        Path=DataContext.ButtonHeightWidth}"
            Width="{Binding ElementName=weItemControl, 
        Path=DataContext.ButtonHeightWidth}"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            Margin="{Binding ElementName=weItemControl, 
        Path=DataContext.ButtonMarginToUse}"
            Padding="2"
            Style="{StaticResource WeButton}">
    </ToggleButton>
</DataTemplate>

The style of the button in resource dictionary:

<Style TargetType="{x:Type ToggleButton}" x:Key="WeButton">
    <Setter Property="Background" Value="White"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ToggleButton}">
                <Grid>
                    <Ellipse Fill="{TemplateBinding Background}" />
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextBlock.TextAlignment="Center">
                        <ContentPresenter.Resources>
                            <Style TargetType="{x:Type TextBlock}">
                                <Setter Property="TextWrapping" Value="Wrap"/>
                                <Setter Property="HorizontalAlignment" Value="Center"/>
                                <Setter Property="VerticalAlignment" Value="Center"/>
                                <Setter Property="TextAlignment" Value="Center"/>
                            </Style>
                        </ContentPresenter.Resources>
                    </ContentPresenter>
                </Grid>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsChecked" Value="true">
                        <Setter Property="Background" Value="{Binding GColour}"/>
                    </Trigger>
                    <Trigger Property="IsChecked" Value="False">
                        <Setter Property="Background" Value="{Binding GColour}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
uaswpff
  • 75
  • 6
  • How are these buttons declared? – Pavel Anikhouski Jan 28 '20 at 14:31
  • 1
    Once I've had similar issue, but on MFC C++ app. I've ended up using SDL as rendering and input framework. Had to rewrite all rendering and logic, but it was easily to handle 1k+ gui elements. My point is that regular form rendering just not made for displaying so many controls. – G0867532 Jan 28 '20 at 14:59
  • It's just that you're not utilizing virtualization features in your favor. Take a look at the answers here: [Is it possible to override the ItemsPresenter to use a Virtualizing StackPanel instead of a regular stack panel?](https://stackoverflow.com/q/9503433/3602352) – Aly Elhaddad Jan 28 '20 at 15:58
  • Hey aly, i saw this but i don't know where i'd put that – uaswpff Jan 28 '20 at 16:26
  • Note that virtualization only helps if a lot of your buttons are outside of the visible area of a scrollviewer. If all your 300+ buttons are visible at once (without needing to scroll them into view), virtualization doesn't change anything. – René Vogt Jan 28 '20 at 16:29
  • Hmm that's probably why i'm not seeing any change when virtualizing. Is there "no way" to render 300+ buttons more efficiently? Or is there an alternative type that can do all the above? – uaswpff Jan 28 '20 at 16:32
  • Are these DataTemplates of buttons declarated in Resource dictionaries? Data templates using inside (merged) Resource dictionary can cause slow initialization. Please use "cached" or "shared" resource dictionaries (Easy to find example implementation,just google these names) or you should separate your DataTemplates (as controls or styles) and avoid using of default merged Resource dictionaries with too many datatemplates. – Péter Hidvégi Jan 28 '20 at 20:16
  • Hey Peter, I posted the style of my buttons. Yes they are in a resource dictionary. The top of my XAML view has this: I'll look up how to transform this into cached or shared resource but not too sure how i can do that – uaswpff Jan 29 '20 at 09:50
  • I removed the style for the button and it still renders the same speed tho... – uaswpff Jan 29 '20 at 09:54
  • Removing style won't perform faster initialization. Your style seems good with template. You should just avoid using datatemplates inside ResourceDictionary.MergedDictionaries. For example You can use Shared or Cached ResourceDictionary instead of MergedDictionaries. Please google it. (Btw the simpliest but the nastyest solution to add your datatemplates to app.resources. Please just use it as temporary.) – Péter Hidvégi Jan 29 '20 at 14:04
  • Only problem with putting datatemplates into app.resources is that in your ItemsControl.ItemsTemplate you can't specify multiple datatemplates that way, only one. – uaswpff Jan 30 '20 at 15:41

0 Answers0