【问题标题】:Is It Possible To Draw a UI Element On Top of the Adorner Layer?是否可以在 Adorner 层之上绘制 UI 元素?
【发布时间】:2015-11-26 06:03:07
【问题描述】:

对于我的 WPF TreeView 用户控件,我想在 ToggleButton 周围显示一个进度环,以指示正在填充节点的子节点,如下所示:

(完全披露,我在一些开源软件中看到过这种行为,我只是不记得在哪里)。我仍然希望切换按钮具有交互性(即获取鼠标事件,例如悬停和单击),以便用户在不再希望等待更新完成时折叠节点。

我的第一个想法是将进度环作为装饰层添加到 ToggleButton。但是,由于 WPF 装饰层位于 Z 顺序的 UI 元素顶部,我似乎无法与进度环下方的切换按钮进行交互。有没有办法在装饰层顶部绘制切换按钮?或者在这种情况下,装饰层似乎不是正确的方法?在更新子项时触发一个属性来控制切换按钮的模板并绘制进度环和切换按钮会更好吗?感谢您的任何想法!

我正在利用的相关教程:

Working with Checkboxes in the WPF TreeView

WPF Loading Wait Adorner(有进度环和装饰器来源的链接)

【问题讨论】:

    标签: c# wpf uielement z-order adornerlayer


    【解决方案1】:

    您可以使用网格在扩展器(切换按钮)后面放置动画。 Grid 将按 z 顺序将元素堆叠在同一单元格中。动画可能始终存在,只是被隐藏,由您定义的某些触发器显示。

    【讨论】:

    • 感谢您的精彩提示。这种方法是@netaholic 在下面发布的方式。我选择他的答案只是因为它包含来源。
    【解决方案2】:

    我相信你不需要装饰者来实现你的愿望。 我已经通过 Blend 编辑了树视图模板,将带有繁忙动画的用户控件添加到树视图项目样式的扩展器按钮。有很多工作要做,但它可以向您展示方法。还有可能有更好的方法来更改指示器的可见性,而不是在可视化树中搜索它。

    我看到的方式是为treeview和treeviewitem创建自定义控件。覆盖它的样式并为 treeviewitem 添加一个“IsLoading”属性。切换此属性应该会改变用户控件的可见性。

    MainWindow.xaml

    <Window x:Class="WpfApplication17.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525" xmlns:local="clr-namespace:WpfApplication17">
        <Window.Resources>
    
            <Style x:Key="TreeViewItemFocusVisual">
                <Setter Property="Control.Template">
                    <Setter.Value>
                        <ControlTemplate>
                            <Rectangle/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Fill" Color="#FF595959"/>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Stroke" Color="#FF262626"/>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Stroke" Color="#FF1BBBFA"/>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Fill" Color="Transparent"/>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Stroke" Color="#FF262626"/>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Fill" Color="#FF595959"/>
            <PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Fill" Color="Transparent"/>
            <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Stroke" Color="#FF989898"/>
            <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
                <Setter Property="Focusable" Value="False"/>
                <Setter Property="Width" Value="16"/>
                <Setter Property="Height" Value="16"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ToggleButton}">
                            <Grid HorizontalAlignment="Left" Height="16" VerticalAlignment="Top" Width="16">
                                <Border Background="Transparent" Height="16" Padding="5,5,5,5" Width="16">
                                    <Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="{StaticResource TreeViewItem.TreeArrow.Static.Fill}" Stroke="{StaticResource TreeViewItem.TreeArrow.Static.Stroke}">
                                        <Path.RenderTransform>
                                            <RotateTransform Angle="135" CenterY="3" CenterX="3"/>
                                        </Path.RenderTransform>
                                    </Path>
                                </Border>
                                <local:UserControl1 Name="busyInd"/>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsChecked" Value="True">
                                    <Setter Property="RenderTransform" TargetName="ExpandPath">
                                        <Setter.Value>
                                            <RotateTransform Angle="180" CenterY="3" CenterX="3"/>
                                        </Setter.Value>
                                    </Setter>
                                    <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Fill}"/>
                                    <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Stroke}"/>
                                </Trigger>
                                <Trigger Property="IsMouseOver" Value="True">
                                    <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Stroke}"/>
                                    <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Fill}"/>
                                </Trigger>
                                <MultiTrigger>
                                    <MultiTrigger.Conditions>
                                        <Condition Property="IsMouseOver" Value="True"/>
                                        <Condition Property="IsChecked" Value="True"/>
                                    </MultiTrigger.Conditions>
                                    <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Stroke}"/>
                                    <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Fill}"/>
                                </MultiTrigger>
                            </ControlTemplate.Triggers>
    
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
            <Style x:Key="TreeViewItemStyle1" TargetType="{x:Type TreeViewItem}">
                <Setter Property="Background" Value="Transparent"/>
                <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
                <Setter Property="Padding" Value="1,0,0,0"/>
                <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type TreeViewItem}">
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition MinWidth="19" Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
                                <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="1" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                                    <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                </Border>
                                <ItemsPresenter x:Name="ItemsHost" Grid.ColumnSpan="2" Grid.Column="1" Grid.Row="1"/>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Property="IsExpanded" Value="false">
                                    <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                                </Trigger>
                                <Trigger Property="HasItems" Value="false">
                                    <Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
                                </Trigger>
                                <Trigger Property="IsSelected" Value="true">
                                    <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                                </Trigger>
                                <MultiTrigger>
                                    <MultiTrigger.Conditions>
                                        <Condition Property="IsSelected" Value="true"/>
                                        <Condition Property="IsSelectionActive" Value="false"/>
                                    </MultiTrigger.Conditions>
                                    <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                                </MultiTrigger>
                                <Trigger Property="IsEnabled" Value="false">
                                    <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                                </Trigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
                <Style.Triggers>
                    <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
                        <Setter Property="ItemsPanel">
                            <Setter.Value>
                                <ItemsPanelTemplate>
                                    <VirtualizingStackPanel/>
                                </ItemsPanelTemplate>
                            </Setter.Value>
                        </Setter>
                    </Trigger>
                </Style.Triggers>
            </Style>
            <Style x:Key="BusyInd" TargetType="{x:Type Grid}"/>
        </Window.Resources>
    
        <Grid>
            <TreeView Name="treeView" SelectedItemChanged="treeView_SelectedItemChanged" HorizontalAlignment="Left" Height="300" Margin="10,10,0,0" VerticalAlignment="Top" Width="497" ItemContainerStyle="{DynamicResource TreeViewItemStyle1}">
    
                <TreeViewItem Header="TreeViewItem" IsExpanded="True">
                    <TreeViewItem Header="TreeViewItem" HorizontalAlignment="Left" Width="474"/>
                    <TreeViewItem Header="TreeViewItem" HorizontalAlignment="Left" Width="474"/>
                </TreeViewItem>
                <TreeViewItem Header="TreeViewItem" IsExpanded="True">
                    <TreeViewItem Header="TreeViewItem" HorizontalAlignment="Left" Width="474"/>
                    <TreeViewItem Header="TreeViewItem" HorizontalAlignment="Left" Width="474"/>
                </TreeViewItem>
                <TreeViewItem Header="TreeViewItem" IsExpanded="True">
                    <TreeViewItem Header="TreeViewItem" HorizontalAlignment="Left" Width="474"/>
                </TreeViewItem>
            </TreeView>
    
        </Grid>
    </Window>
    

    MainWindow.cs

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
            }
    
            private void treeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
            {
                TreeViewItem item_container = (TreeViewItem)treeView.ItemContainerGenerator.ContainerFromItem(treeView.SelectedItem);
                var indicator = FindChild<UserControl1>(item_container, "busyInd");
                indicator.Visibility = Visibility.Visible;
                Task.Factory.StartNew(() =>
                {
                    Thread.Sleep(3000);
                    Dispatcher.Invoke(() => { indicator.Visibility = Visibility.Collapsed; });
                });
            }
    
            public static T FindChild<T>(DependencyObject parent, string childName)
               where T : DependencyObject
            {
                if (parent == null) return null;
    
                T foundChild = null;
    
                int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
                for (int i = 0; i < childrenCount; i++)
                {
                    var child = VisualTreeHelper.GetChild(parent, i);
                    // If the child is not of the request child type child
                    T childType = child as T;
                    if (childType == null)
                    {
                        // recursively drill down the tree
                        foundChild = FindChild<T>(child, childName);
    
                        // If the child is found, break so we do not overwrite the found child. 
                        if (foundChild != null) break;
                    }
                    else if (!string.IsNullOrEmpty(childName))
                    {
                        var frameworkElement = child as FrameworkElement;
                        // If the child's name is set for search
                        if (frameworkElement != null && frameworkElement.Name == childName)
                        {
                            // if the child's name is of the request name
                            foundChild = (T)child;
                            break;
                        }
                    }
                    else
                    {
                        // child element found.
                        foundChild = (T)child;
                        break;
                    }
                }
    
                return foundChild;
            }
        }
    

    UserControl1.xaml

    <UserControl x:Class="WpfApplication17.UserControl1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Height="Auto" Width="Auto" Background="Transparent" Visibility="Collapsed">
        <Viewbox Width="{Binding Width, ElementName=BusyIndicator}" Height="{Binding Height, ElementName=BusyIndicator}"      
            HorizontalAlignment="Center" VerticalAlignment="Center">
            <Grid Background="Transparent" ToolTip="Searching...." HorizontalAlignment="Center" VerticalAlignment="Center">
                <Canvas Name="Canvas1"  
             RenderTransformOrigin="0.5,0.5"  
             HorizontalAlignment="Center"         
             VerticalAlignment="Center" Width="120" Height="120">
                    <Canvas.RenderTransform>
                        <RotateTransform Angle="0" />
                    </Canvas.RenderTransform>
                    <Canvas.Style>
                        <Style TargetType="Canvas">
                            <Style.Triggers>
                                <Trigger Property="IsVisible" Value="True">
                                    <Trigger.EnterActions>
                                        <BeginStoryboard Name="Storyboard_Rotate">
                                            <Storyboard RepeatBehavior="Forever">
                                                <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle"   
                              From="0" To="360" Duration="0:0:2"/>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </Trigger.EnterActions>
                                    <Trigger.ExitActions>
                                        <StopStoryboard BeginStoryboardName="Storyboard_Rotate" />
                                    </Trigger.ExitActions>
                                </Trigger>
    
                            </Style.Triggers>
                        </Style>
                    </Canvas.Style>
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="1.0" Canvas.Left="50" Canvas.Top="0" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.9" Canvas.Left="20.6107373853764" Canvas.Top="9.54915028125262" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.8" Canvas.Left="2.44717418524233" Canvas.Top="34.5491502812526" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.7" Canvas.Left="2.44717418524232" Canvas.Top="65.4508497187474" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.6" Canvas.Left="20.6107373853763" Canvas.Top="90.4508497187474" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.5" Canvas.Left="50" Canvas.Top="100" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.4" Canvas.Left="79.3892626146236" Canvas.Top="90.4508497187474" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.3" Canvas.Left="97.5528258147577" Canvas.Top="65.4508497187474" />
                    <Ellipse Width="20" Height="20" Stretch="Fill" Fill="Black" Opacity="0.2" Canvas.Left="97.5528258147577" Canvas.Top="34.5491502812526" />
                </Canvas>
            </Grid>
        </Viewbox>
    </UserControl>
    

    【讨论】:

    • 很好的答案,感谢您的示例代码。效果很好!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    • 1970-01-01
    • 2021-05-18
    • 1970-01-01
    相关资源
    最近更新 更多