Adding “Loading”-image on top of ListView

前端 未结 1 678
生来不讨喜
生来不讨喜 2021-02-01 11:47

I\'d like to add a \"Loading\"-Image on the top of my ListView while all items are loading, if there are a lot of items being loaded, I still want a ni

相关标签:
1条回答
  • 2021-02-01 12:13

    Here's some XAML that I use to create an AJAX-like wait spinner for WPF. I uses geometry and animation rather than an animated GIF, and you can control the size and rate by tweaking the XAML:

    <!-- Style for AJAX-like wait spinners -->
    <Style x:Key="WaitSpinnerStyle" TargetType="Control">
        <Setter Property="Foreground" Value="#888" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Control">
                    <Viewbox Visibility="{TemplateBinding Visibility}">
                        <Canvas RenderTransformOrigin="0.5,0.5" Width="120" Height="120" >
                            <Ellipse Width="21.835" Height="21.862" Canvas.Left="20.1696" Canvas.Top="9.76358" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="1.0"/>
                            <Ellipse Width="20.835" Height="20.862" Canvas.Left="2.86816" Canvas.Top="29.9581" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.9"/>
                            <Ellipse Width="19.835" Height="19.862" Canvas.Left="0.00001" Canvas.Top="57.9341" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.8"/>
                            <Ellipse Width="17.835" Height="17.862" Canvas.Left="12.1203" Canvas.Top="83.3163" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.7"/>
                            <Ellipse Width="16.835" Height="16.862" Canvas.Left="36.5459" Canvas.Top="98.1380" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.6"/>
                            <Ellipse Width="14.835" Height="14.862" Canvas.Left="64.6723" Canvas.Top="96.8411" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.5"/>
                            <Ellipse Width="13.835" Height="13.862" Canvas.Left="87.6176" Canvas.Top="81.2783" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.4"/>
                            <Ellipse Width="12.835" Height="12.862" Canvas.Left="98.165"  Canvas.Top="54.4140" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.3"/>
                            <Ellipse Width="11.835" Height="11.862" Canvas.Left="92.9838" Canvas.Top="26.9938" Stretch="Fill" Fill="{TemplateBinding Foreground}" Opacity="0.2"/>
                            <Canvas.RenderTransform>
                                <RotateTransform x:Name="SpinnerRotate" Angle="0" />
                            </Canvas.RenderTransform>
                            <Canvas.Triggers>
                                <EventTrigger RoutedEvent="ContentControl.Loaded">
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <DoubleAnimation
                                                Storyboard.TargetName="SpinnerRotate"
                                                Storyboard.TargetProperty="Angle"
                                                From="0" To="360" Duration="0:0:01.3"
                                                RepeatBehavior="Forever" />
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </Canvas.Triggers>
                        </Canvas>
                    </Viewbox>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    

    You use it like this (specify the colour if you want to change it):

    <Control Style="{StaticResource WaitSpinnerStyle}" Width="35" />
    <Control Style="{StaticResource WaitSpinnerStyle}" Width="35" Foreground="Green" />
    

    The above XAML would look like this (you have to imagine them spinning!):


    To have a layer appear above your ListBox, wrap it in a Grid like this:

    <Grid>
        <!-- LOADING overlay (for async-load) -->
        <Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" IsHitTestVisible="True" 
                Background="#40000000" CornerRadius="4"
                Visibility="{Binding Path=IsLoading, Converter={StaticResource BooleanToVisibilityConverter}}">
            <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                <Control Style="{StaticResource WaitSpinnerStyle}" Width="35" Foreground="White" />
                <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="LOADING..." FontWeight="Bold" Margin="0,5" Foreground="White" FontSize="12" />
            </StackPanel>
        </Border>
        <ListBox />
    </Grid>
    

    Using a Grid means that the Border will appear on top of the ListBox. In this case, the layer will appear greyed out, and will steal any mouse actions, effectively disabling the underlying ListBox.

    Note that the binding here to IsLoaded connects to my view model. I set it to false when I start loading, then again to true when the loading completes. Note that I load my items off the dispatcher thread (on a worker thread) so that the UI updates while I'm doing this work.

    0 讨论(0)
提交回复
热议问题