• [WPF系列]Adorner应用-自定义控件ImageHotSpot


    引言

    项目中有时需要在图片上标注热区,在HTML中有<area>标签,但在WPF中目前还没现成的控件来实现这这一功能。至于图片热区功能有道词典的【图解词典】是个不错的例子,如图1:

    图 1

    什么是Adorner?

    Adoner 是一个绑定到某个UIElement自定义的FrameWorkElemnt 。Adoner被渲染在AdornerLayer,而AdornerLayer又被渲染在被装饰的Element或者Element集合上面。Adorner的渲染独立于它所装饰的UIElement。Adoner通常使用相对坐标来定位到它所装饰的Element上。    

    Adorner应用场景:

    • 为UIElement添加功能句柄,从而使用户能够通过某种方式操作改Element(如Resize,Rotate,Reposition等)
    • 可以提供多种状态提示或者响应许多事件
    • 在UIElement上叠加一些可视修饰(外观修饰)
    • 遮罩UIElement的部分或者全部 

    本文所涉及的功能一方面是要添加一个装饰元素去标记热区另一方面就是为该热区添加响应事件。    

    ImageWithHotSpot

       

    先看下效果图:

    当用户在图片上点击红色圆圈内部是,将会触发一个点击事件。

       

    实现思路:

    首先新建一个用户自定义控件ImageWithHotSpots.xaml并在其中添加一个Image控件来存放要添加热点的图片,为了在Image控件上添加热点Adorner,我新建了个ImageHotSpotAdorner类,为了方便控制热点的形状外观我独立定义了个ImageHotSpot类,另一方面在我们引用该自定义控件时不用关注具体的Adorner,而只需要关注热点本身就可以了。

    代码结构

    代码:

       

    ImageHotSpot Class code:

      public class ImageHotSpot
        {
            public int Id { get; set; }
            public Point Location { get; set; }
    
            public double With { get; set; }
    
            public double Height { get; set; }
    
            public Color BorderColor { get; set; }
    
            public double BorderThickness { get; set; }
    
            public event EventHandler MouseClick;
    
            public void InvokeMouseClickEvent()
            {
                if (MouseClick != null)
                {
                    MouseClick(this, EventArgs.Empty);
                }
            }
        }
    View Code

    ImageWithHotSpots.xaml

    <UserControl x:Class="WPFImageHotSopts.ImageWithHotSpots" 
    
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    
    mc:Ignorable="d" 
    
    d:DesignHeight="300" d:DesignWidth="300"> 
    
    <Grid> 
    
    <Image Name="ImageForHotSpot"/> 
    
    </Grid> 
    
    </UserControl> 
    View Code

    ImageWithHotSpots.cs

     /// <summary>
        /// Interaction logic for ImageWithHotSpots.xaml
        /// </summary>
        public partial class ImageWithHotSpots : UserControl
        {
            private List<ImageHotSpot> _imageHotSpotsList = new List<ImageHotSpot>();
    
            public ImageWithHotSpots()
            {
                InitializeComponent();
                Loaded += OnLoaded;
            }
    
            private void OnLoaded(object sender, RoutedEventArgs args)
            {
                foreach (var imageHotSpot in _imageHotSpotsList)
                {
                    AddImageHotSpot(imageHotSpot);
                }
            }
    
            public ImageSource Source
            {
                get { return ImageForHotSpot.Source; }
                set { ImageForHotSpot.Source = value; }
            }
    
            public List<ImageHotSpot> ImageHotSpots {
                get { return _imageHotSpotsList; }
            }
    
            public void AddImageHotSpot(ImageHotSpot hotSpot)
            {
                var adorner = new ImageHotSpotAdorner(ImageForHotSpot,hotSpot);
                _imageHotSpotsList.Add(hotSpot);
                var layer = AdornerLayer.GetAdornerLayer(ImageForHotSpot);
                layer.Add(adorner);
            }
    
    
            public void RemoveImageHotSpot(ImageHotSpot hotSpot)
            {
                var layer = AdornerLayer.GetAdornerLayer(ImageForHotSpot);
                var adorners=layer.GetAdorners(ImageForHotSpot);
                if (adorners != null)
                {
                    var adorner = adorners.FirstOrDefault(a => ((ImageHotSpot) a.Tag).Id == hotSpot.Id);
                    layer.Remove(adorner);
                }
            }
    
        }
    View Code

    ImageHotSpotAdorner.cs

       

    public class ImageHotSpotAdorner : Adorner 
    
    { 
    
    #region Data 
    
       
    
    private Ellipse _control; 
    
    private Point _location; 
    
    private ArrayList _logicalChildren; 
    
       
    
    #endregion Data 
    
       
    
    #region Constructor 
    
       
    
    public ImageHotSpotAdorner(Image adornedImage, ImageHotSpot hotSpot) 
    
    : base(adornedImage) 
    
    { 
    
    if (hotSpot == null) 
    
    throw new ArgumentNullException("hotSpot is null"); 
    
       
    
    _location = hotSpot.Location; 
    
       
    
    _control = new Ellipse(); 
    
       
    
    _control.Height = 0.1 * adornedImage.ActualHeight; 
    
    _control.Width = 0.1 * adornedImage.ActualWidth; 
    
    _control.Stroke = new SolidColorBrush(hotSpot.BorderColor); 
    
    _control.StrokeThickness = hotSpot.BorderThickness; 
    
    _control.Fill=new SolidColorBrush(Colors.Transparent); 
    
    _control.MouseLeftButtonUp += _control_MouseLeftButtonUp; 
    
    _control.MouseEnter += _control_MouseEnter; 
    
    _control.MouseLeave += _control_MouseLeave; 
    
    _control.Tag = hotSpot; 
    
    base.AddLogicalChild(_control); 
    
    base.AddVisualChild(_control); 
    
    } 
    
       
    
    void _control_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e) 
    
    { 
    
    this.Cursor=Cursors.Arrow; 
    
    } 
    
       
    
    void _control_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e) 
    
    { 
    
    this.Cursor = Cursors.Hand; 
    
    } 
    
       
    
    private void _control_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) 
    
    { 
    
    if (_control != null && e.ClickCount == 1) 
    
    { 
    
    var hotSpot = (ImageHotSpot)_control.Tag; 
    
    hotSpot.InvokeMouseClickEvent(); 
    
    } 
    
    } 
    
       
    
    #endregion Constructor 
    
       
    
       
    
    #region UpdateTextLocation 
    
       
    
    public void UpdateTextLocation(Point newLocation) 
    
    { 
    
    _location = newLocation; 
    
    _control.InvalidateArrange(); 
    
    } 
    
       
    
    #endregion UpdateTextLocation 
    
       
    
    #region Measure/Arrange 
    
       
    
    /// <summary> 
    
    /// Allows the control to determine how big it wants to be. 
    
    /// </summary> 
    
    /// <param name="constraint">A limiting size for the control.</param> 
    
    protected override Size MeasureOverride(Size constraint) 
    
    { 
    
    _control.Measure(constraint); 
    
    return _control.DesiredSize; 
    
    } 
    
       
    
    /// <summary> 
    
    /// Positions and sizes the control. 
    
    /// </summary> 
    
    /// <param name="finalSize">The actual size of the control.</param> 
    
    protected override Size ArrangeOverride(Size finalSize) 
    
    { 
    
    Rect rect = new Rect(_location, finalSize); 
    
       
    
    _control.Arrange(rect); 
    
       
    
    return finalSize; 
    
    } 
    
       
    
    #endregion Measure/Arrange 
    
       
    
    #region Visual Children 
    
       
    
    /// <summary> 
    
    /// Required for the element to be rendered. 
    
    /// </summary> 
    
    protected override int VisualChildrenCount 
    
    { 
    
    get { return 1; } 
    
    } 
    
       
    
    /// <summary> 
    
    /// Required for the element to be rendered. 
    
    /// </summary> 
    
    protected override Visual GetVisualChild(int index) 
    
    { 
    
    if (index != 0) 
    
    throw new ArgumentOutOfRangeException("index"); 
    
       
    
    return _control; 
    
    } 
    
       
    
    #endregion Visual Children 
    
       
    
    #region Logical Children 
    
       
    
    /// <summary> 
    
    /// Required for the displayed element to inherit property values 
    
    /// from the logical tree, such as FontSize. 
    
    /// </summary> 
    
    protected override IEnumerator LogicalChildren 
    
    { 
    
    get 
    
    { 
    
    if (_logicalChildren == null) 
    
    { 
    
    _logicalChildren = new ArrayList(); 
    
    _logicalChildren.Add(_control); 
    
    } 
    
       
    
    return _logicalChildren.GetEnumerator(); 
    
    } 
    
    } 
    
       
    
    #endregion Logical Children 
    
    } 
    View Code

     

    参考文档

       

    MSDN Adorners Overview http://msdn.microsoft.com/en-us/library/ms743737(v=vs.110).aspx

    Annotating an Image in WPF http://www.codeproject.com/Articles/20457/Annotating-an-Image-in-WPF

     

    源码下载:WPFImageHotSopts.rar

    作者:旭东
    出处:http://www.cnblogs.com/HQFZ
    关于作者:专注于微软平台项目架构、管理和企业解决方案。现主要从事WinForm、ASP.NET、WPF、WCF、等方面的项目开发、架构、管理。如有问题或建议,请不吝指教!
    本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。如有问题,可以联系我,非常感谢。
    如果您该文觉得不错或者对你有帮助,请点下推荐,让更多的朋友看到,谢谢!

  • 相关阅读:
    SpringCloud
    Linux
    SpringBoot
    秒杀系统设计
    设计模式
    数据库(mysql)
    Java web
    c#常用控件及简写
    C#常用的form窗体属性(最大化、最小化、窗体居中)
    C#中使用IndexOf()判断字符串在字符串数组中第一次出现的索引位置
  • 原文地址:https://www.cnblogs.com/HQFZ/p/4045964.html
Copyright © 2020-2023  润新知