none
WPF,如何实现弹出区域外点击,关闭弹出弹出内容。 RRS feed

  • 常规讨论

  • 1)控件

    1.1)T4PopupControl.cs

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Markup;
    using System.Windows.Media;

    namespace T4.Wpf
    {
        /// <summary>
        /// T4PopupControl,
        /// 支持弹出区域外点击自动关闭弹出内容的弹出控件。
        /// </summary>
        [ContentProperty("PopupContent")]
        public class T4PopupControl : Control
        {
            /// <summary>
            /// PopupContent,弹出内容。
            /// </summary>
            public FrameworkElement PopupContent
            {
                get { return (FrameworkElement)GetValue(PopupContentProperty); }
                set { SetValue(PopupContentProperty, value); }
            }
            /// <summary>
            /// PopupContent,弹出内容。
            /// </summary>
            public static readonly DependencyProperty PopupContentProperty =
                DependencyProperty.Register("PopupContent",
                typeof(FrameworkElement), typeof(T4PopupControl), new UIPropertyMetadata(null));

            /// <summary>
            /// IsOpen,是否显示弹出内容。
            /// </summary>
            public bool IsOpen
            {
                get { return (bool)GetValue(IsOpenProperty); }
                set { SetValue(IsOpenProperty, value); }
            }
            /// <summary>
            /// IsOpen,是否显示弹出内容,依赖属性。
            /// </summary>
            public static readonly DependencyProperty IsOpenProperty =
                DependencyProperty.Register("IsOpen",
                typeof(bool), typeof(T4PopupControl),
                new UIPropertyMetadata(false, IsOpen_Changed));
            private static void IsOpen_Changed(DependencyObject s, DependencyPropertyChangedEventArgs e)
            {
                var Owner = s as T4PopupControl; Owner.SetAdonersVisibility();
            }

            // Pri
            private CPri Pri = new CPri();
            private class CPri
            {
                public bool ThisLoadedIf = false;
                public AdornerLayer ThisAdornerLayer = null;
                public T4PopupControlOverlayAdorner OverlayAdorner = null;
                public T4PopupControlContentAdorner ContentAdorner = null;
            }
           
            /// <summary>
            /// T4PopupControl,构造函数。
            /// </summary>
            public T4PopupControl()
            {
                this.DefaultStyleKey = typeof(T4PopupControl);
                this.Loaded -= T4PopupControl_Loaded;
                this.Loaded += T4PopupControl_Loaded;
            }
            private void T4PopupControl_Loaded(object sender, RoutedEventArgs e)
            {
                Pri.ThisAdornerLayer = AdornerLayer.GetAdornerLayer(this);
                Pri.OverlayAdorner = new T4PopupControlOverlayAdorner(this);
                Pri.ContentAdorner = new T4PopupControlContentAdorner(this, this.PopupContent);
                Pri.ThisAdornerLayer.Add(Pri.OverlayAdorner);
                Pri.ThisAdornerLayer.Add(Pri.ContentAdorner);

                Pri.OverlayAdorner.MouseDown -= OverlayAdorner_MouseDown;
                Pri.OverlayAdorner.MouseDown += OverlayAdorner_MouseDown;
                Pri.ThisLoadedIf = true; SetAdonersVisibility();
            }
            private void OverlayAdorner_MouseDown(object sender, MouseButtonEventArgs e) { this.IsOpen = false; }

            private void SetAdonersVisibility()
            {
                if (Pri.ThisLoadedIf)
                {
                    if (this.IsOpen) { ShowAdorners(); }
                    else { HideAdorners(); }
                }
            }
            private void ShowAdorners()
            {
                Pri.OverlayAdorner.Visibility = Visibility.Visible;
                Pri.ContentAdorner.Visibility = Visibility.Visible;
            }
            private void HideAdorners()
            {
                Pri.OverlayAdorner.Visibility = Visibility.Collapsed;
                Pri.ContentAdorner.Visibility = Visibility.Collapsed;
            }
        }

        internal class T4PopupControlOverlayAdorner : Adorner
        {
            private CPri Pri = new CPri();
            private class CPri
            {
                public Grid OverlayGrid = null;
            }
            internal T4PopupControlOverlayAdorner(UIElement AdornedElement)
                : base(AdornedElement)
            {
                Pri.OverlayGrid = new Grid() { Background = new SolidColorBrush(Colors.Transparent), };
                this.IsHitTestVisible = true; this.AddVisualChild(Pri.OverlayGrid);
            }
            protected override int VisualChildrenCount { get { return 1; } }
            protected override Visual GetVisualChild(int index) { return this.Pri.OverlayGrid; }
            protected override Size MeasureOverride(Size constraint)
            {
                return constraint;
            }
            protected override Size ArrangeOverride(Size finalSize)
            {
                var Host = FindParent<Window>(this.AdornedElement);
                var Pos = this.AdornedElement.TranslatePoint(default(Point), Host);
                this.Pri.OverlayGrid.Arrange(new Rect()
                {
                    X = -Pos.X,
                    Y = -Pos.Y,
                    Width = finalSize.Width,
                    Height = finalSize.Height
                });
                return base.ArrangeOverride(finalSize);
            }
            private T FindParent<T>(DependencyObject Child) where T : DependencyObject
            {
                var Rlt = null as T;
                var Tmp = VisualTreeHelper.GetParent(Child);
                if (Tmp != null)
                {
                    if ((Tmp as T) != null) { Rlt = Tmp as T; }
                    else { Rlt = FindParent<T>(Tmp); }
                }
                return Rlt;
            }
        }

        internal class T4PopupControlContentAdorner : Adorner
        {
            private CPri Pri = new CPri();
            private class CPri
            {
                public FrameworkElement ContentVisual = null;
            }
            internal T4PopupControlContentAdorner(UIElement AdornedElement, FrameworkElement ContentVisual)
                : base(AdornedElement)
            {
                Pri.ContentVisual = ContentVisual;
                this.IsHitTestVisible = true;
                this.AddVisualChild(Pri.ContentVisual);
            }
            protected override int VisualChildrenCount { get { return 1; } }
            protected override Visual GetVisualChild(int index) { return this.Pri.ContentVisual; }
            protected override Size MeasureOverride(Size constraint)
            {
                Pri.ContentVisual.Measure(constraint);
                var NewSize = Pri.ContentVisual.DesiredSize;
                return NewSize;
            }
            protected override Size ArrangeOverride(Size finalSize)
            {
                this.Pri.ContentVisual.Arrange(new Rect()
                {
                    X = 0,
                    Y = 0,
                    Width = finalSize.Width,
                    Height = finalSize.Height
                });
                return base.ArrangeOverride(finalSize);
            }
        }
    }

    1.2)T4PopupControl.xaml

    <ResourceDictionary
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:t4="clr-namespace:T4.Wpf">

      <!-- T4PopupControl Default Style -->
      <Style
        TargetType="{x:Type t4:T4PopupControl}">
        <Setter
          Property="Template">
          <Setter.Value>
            <ControlTemplate
              TargetType="{x:Type t4:T4PopupControl}">
              <Grid
                Background="Transparent">
              </Grid>
            </ControlTemplate>
          </Setter.Value>
        </Setter>
      </Style>
    </ResourceDictionary>

    2) 测试

    2.1) MainPage.xaml

    <Window
      x:Class="T4Test.Wpf.MdiMain"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:t4="http://schemas.tfsoft.com/winfx/2013/xaml"
      WindowStartupLocation="CenterScreen"
      Title="T4PopupControl Test"
      Width="500"
      Height="300">

      <Grid>
        <Grid
          VerticalAlignment="Top"
          HorizontalAlignment="Left"
          Margin="50,50,0,0">
          <Button
            x:Name="BtnShowPopup"
            Content="Show Popup Box"
            Click="BtnShowPopup_Click"></Button>
          <t4:T4PopupControl
            Width="1"
            Height="1"
            VerticalAlignment="Bottom"
            HorizontalAlignment="Left"
            x:Name="PopPopupControl"
            IsOpen="True">
            <Border
              Background="AntiqueWhite"
              BorderBrush="Gray"
              BorderThickness="1"
              CornerRadius="2"
              Margin="0,4,0,0">
              <StackPanel
                Orientation="Vertical">
                <TextBlock
                  Margin="4"
                  Text="This is a sample popup box."></TextBlock>
                <TextBlock
                  Margin="4"
                  Text="Click any area outside this box will close this popup box."></TextBlock>
              </StackPanel>
            </Border>
          </t4:T4PopupControl>
        </Grid>
      </Grid>
    </Window>

    2.2)MainPage.cs

    using System.Windows;

    namespace T4Test.Wpf
    {
        public partial class MdiMain : Window
        {
            public MdiMain()
            {
                InitializeComponent();
            }

            private void BtnShowPopup_Click(object sender, RoutedEventArgs e)
            {
                this.PopPopupControl.IsOpen = true;
            }
        }
    }

    3. 效果


    • 已编辑 TFSoft 2013年7月12日 17:57
    • 已更改类型 Min ZhuModerator 2013年7月15日 7:04 not a question
    2013年7月12日 17:39