介绍 应用程序中的可视空间是一种优势。即使是在分辨率惊人的4K显示器时代,设计师和开发人员也总是被迫在更小的区域显示更多的信息。多年来,出现了一些新的技术来满足这些需求,例如对话框、弹出框等。向用户显示附加信息的另一种方法是使用Adorner类。Adorner类与其他控件的不同之处在于它显示在Adorner层中,该层位于应用程序中所有其他uielement的顶部。使用装饰器的困难在于没有现成的方法来显示供用户交互的控件。下面是如何克服这个小缺点的方法。可能有更优雅的解决方案,但这一个可以完成任务。 背景 有时,有些数据结构可以用简单的描述表示,但实际上包含了更广泛的数据,这会占用宝贵的屏幕空间。在过去,这是使用多文档接口(MDI)处理的,允许用户访问数据。通过WPF提供的可视化支持,我们可以通过单击显示或隐藏所有附加信息,所有这些都在应用程序的可视化显示区域内。 的PopupAdorner PopupAdorner类充当需要显示的任何附加信息的可视化容器。为了使本文简短,我没有包括任何检查装饰器在窗口中的位置的代码。 隐藏,收缩,复制Code
using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; namespace UI { public class PopupAdorner : Adorner { private VisualCollection _visuals; private ContentPresenter _presenter; /// <summary> /// Creates a new popup adorner with the specified content. /// </summary> /// <paramname="adornedElement">The UIElement that will be adorned</param> /// <paramname="content">The content that will be display inside the popup</param> /// <paramname="offset">The popup position in regards to the adorned element</param> public PopupAdorner(UIElement adornedElement, UIElement content, Vector offset) : base(adornedElement) { _visuals = new VisualCollection(this); _presenter = new ContentPresenter(); _visuals.Add(_presenter); _presenter.Content = content; Margin = new Thickness(offset.X, offset.Y, 0, 0); } protected override Size MeasureOverride(Size constraint) { _presenter.Measure(constraint); return _presenter.DesiredSize; } protected override Size ArrangeOverride(Size finalSize) { _presenter.Arrange(new Rect(0, 0, finalSize.Width, finalSize.Height)); return _presenter.RenderSize; } protected override Visual GetVisualChild(int index) { return _visuals[index]; } protected override int VisualChildrenCount { get { return _visuals.Count; } } /// <summary> /// Brings the popup into view. /// </summary> public void Show() { AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement); adornerLayer.Add(this); } /// <summary> /// Removes the popup into view. /// </summary> public void Hide() { AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(AdornedElement); adornerLayer.Remove(this); } } }
使用VisualCollection类,我们可以克服Adorner类的开箱即用设计。通过重写默认的呈现行为,我们可以在装饰器中包含任何类型的控件及其子控件。限制是我们只能有一个父对象。 定义装饰器内容 构建内容有两种方法,自定义用户控件或通过背后的代码。由于使用VS构建自定义用户控件非常简单,所以我将演示如何通过编程方式构建一个简单的控件。 隐藏,收缩,复制Code
using System.Windows; using System.Windows.Controls; using System.Windows.Media; namespace UI { public static class DynamicAdornerContent { public static Border GetSimpleInfoPopup(string[] textInfo) { Border popupBorder = new Border() { BorderBrush = Brushes.Black, BorderThickness = new Thickness(1D) }; Grid container = new Grid() { Background = Brushes.White }; Style txtStyle = new Style(); txtStyle.TargetType = typeof(TextBlock); txtStyle.Setters.Add(new Setter() { Property = FrameworkElement.HorizontalAlignmentProperty, Value = HorizontalAlignment.Left }); txtStyle.Setters.Add(new Setter() { Property = FrameworkElement.VerticalAlignmentProperty, Value = VerticalAlignment.Center }); for (int i = 0; i < textInfo.Length; ++i) { container.RowDefintions.Add(new RowDefinition() { Height = new GridLength(26D) }; var tbox = new TextBlock(); tbox.Style = txtStyle; tbox.Text = textInfo[i]; Grid.SetRow(tbox, i); container.Children.Add(tbox); } popupBorder.Child = container; return popupBorder; } } }
使用PopupAdorner 装饰器可以用来装饰任何类型的UIElement。为此,我将构建一个自定义用户控件,其中包含一个TextBlock和一个简单的箭头图像,用户可以单击它来展开或折叠弹出装饰器。 XAML 隐藏,收缩,复制Code
<UserControl> <UserControl.Resources> <DrawingImagex:Key="img_Arrow"> <DrawingImage.Drawing> <DrawingGroup> <GeometryDrawingBrush="Gray"> <GeometryDrawing.Pen> <PenBrush="DarkGray"EndLineCap="Round"LineJoin="Round"StartLineCap="Round"Thickness="1"/> </GeometryDrawing.Pen> <GeometryDrawing.Geometry> <PathGeometry> <PathFigureIsFilled="True"StartPoint="0,5"> <PathFigure.Segments> <LineSegmentPoint="5,0"/> <LineSegmentPoint="5,10"/> <LineSegmentPoint="0,5"/> </Pathfigure.Segments> </PathFigure> </PathGeometry> </GeometryDrawing.Geometry> </GeometryDrawing> </DrawingGroup> </DrawingImage.Drawing> </DrawingImage> </UserControl.Resources> <GridBackground="White"Height="28"Width="300"x:Name="grid_Container"> <Grid.ColumnDefinitions> <ColumnDefinitionWidth="1*"/> <ColumnDefinitionWidth="20"/> </Grid.ColumnDefinitions> <TextBlockGrid.Column="0"HorizontalAlignment="Stretch"TextTrimming="CharacterEllipsis"TextWrapping="NoWrap"VerticalAlignment="Center"x:Name="txt_DisplayText"/> <ImageGrid.Column="1"Height="18"MouseDown="TogglePopup"Source="{StaticResource ResourceKey=img_Arrow}"ToolTip="Expand"Width="16"x:Name="ctl_Expander"/> </Grid> </UserControl>
后面的代码 隐藏,收缩,复制Code
using System; using System.Windows; using System.Windows.Controls; using System.Widnows.Input; using System.Windows.Media; using System.Windows.Media.Animation; namespace UI { public class ControlWithPopup : UserControl { private Border _infoContainer; private PopupAdorner _infoPopup; private bool _isExpanded; public ControlWithPopup(string displayText, string[] additionalInfo) { InitializeComponent(); _displayText.Text = displayText; _infoContainer = DynamicAdornerContent.GetSimpleInfoPopup(additionalInfo); } private TogglePopup(sender object, MouseButtonEventArgs e) { if (_isExpanded) { _infoPopup.Hide(); _isExpanded = false; } else { if (_infoPopup == null) { _infoPopup = new PopupAdorner( grid_Container, _infoContainer, new Vector(0, 29)); } _infoPopup.Show(); _isExpanded = true; } } } }
这样,当用户单击箭头图像时,提供的附加信息将弹出到自定义用户控件下方的视图中,然后在再次单击箭头时从视图中消失。 添加动画 此时,控件除了显示和隐藏附加信息外,并没有做任何可视化工作。我们需要的是一些动画,使过渡在视觉上更吸引人。 隐藏,收缩,复制Code
// add these animations, transforms, and method to the ControlWithPopup class private DoubleAnimation _extendAnimation; private DoubleAnimation _collapseAnimation; private DoubleAnimation _extendArrowAnimation; private DoubleAnimation _collapseArrowAnimation; private RotateTransform _extendArrowTransform; private RotateTransform _collapseArrowTransform; // call this in the constructor to build the animations // for rotating the arrow in response to user interactions private void InitializeAnimations() { _extendArrowAnimation = new DoubleAnimation(0.0, -90.0, new Duration(TimeSpan.FromSeconds(0.25))); _collapseArrowAnimation = new DoubleAnimation(-90.0, 0.0, new Duration(TimeSpan.FromSeconds(0.25))); _extendArrowTransform = new RotateTransform() { Angle = -90, CenterX = 0.5, CenterY = 0.5 }; _collapseArrowTransform = new RotateTransform() { Angle = 0, CenterX = 0.5, CenterY = 0.5 }; } // alter the TogglePopup function to include animation calls private TogglePopup(sender object, MouseButtonEventArgs e) { ctl_Expander.RenderTransformOrigin = new Point(0.5, 0.5); if (_isExpanded) { ctl_Expander.RenderTransform = _collapseArrowTransform; ctl_Expander.BeginAnimation(RotateTransform.AngleProperty, _collapseArrowAnimation); _collapseAnimation = new DoubleAnimation( _infoContainer.ActualHeight, 0.0, new Duration(TimeSpan.FromSeconds(0.25)), FillBehavior.Stop); // this next line will prevent the popup from being removed from the // AdornerLayer until the animation completes _collapseAnimation.Completed += (s, ev) => { _infoPopup.Hide(); }; _infoPopup.BeginAnimation(HeightProperty, _collapseAnimation); _isExpanded = false; } else { if (_infoPopup == null) { _infoPopup = new PopupAdorner(grid_Container, _infoContainer, new Vector(0, 29)); _infoContainer.Measure (new Size(Double.PositiveInfinity, Double.PositiveInifity)); _extendAnimation = new DoubleAnimation( 0.0, _infoContainer.DesiredSize.Height, new Duration(TimeSpan.FromSeconds(0.25)), FillBehavior.Stop); // this line will cause the extend animation to begin after the container // information is loaded _infoContainer.Loaded += (s, ev) => { _infoContainer.BeginAnimation(HeightProperty, _extendAnimation; } } ctl_Expander.RenderTransform = extendArrowTransform; ctl_Expander.BeginAnimation(RotateTransform.AngleProperty, _extendArrowAnimation); _infoPopup.Show(); _isExpanded = true; } }
这里添加的是四个DoubleAnimation对象和两个RotateTransform对象。这些动画和转换负责根据用户的需要改变视觉效果。当用户单击扩展箭头时,箭头将旋转指向下方,装饰器弹出窗口将向下滑动到视图中。当再次点击时,箭头旋转回原来的位置,弹出的装饰器滑回并退出视图,当关闭动画结束时,装饰器从装饰器层删除自己。我没有包含任何代码来检查喜欢点击的用户,如果在转换过程中单击了展开箭头,它将出错。 特殊的识别 我只是想包括链接到所有的数据来源,帮助我在这个项目: http://www.codeproject.com/articles/54472/defining - wpf装饰器- - xaml http://www.codeproject.com/articles/17696/spelling -建议-在-一个wpf文本框https://social.msdn.microsoft.com/forums/vstudio/en us/81eca7d5 - 88 d7 - 477 a - 8国开行- cfb9e8b75379/how -添加-控制- adorner?论坛= wpf http://stackoverflow.com/questions/9998691/wpf-adorner-with-controls-inside http://stackoverflow.com/questions/8576594/drawingcontext-adorner-possible-to-draw-stackpanel 历史 10/13/2016初版10/14/2016修正错误;添加示例项目 本文转载于:http://www.diyabc.com/frontweb/news455.html