• (转WPF SDK)Popup my Control


    http://blogs.msdn.com/wpfsdk/archive/2007/04/27/popup-your-control.aspx

    Popup your control

    You want a custom control to behave like a Popup and appear over your application and other windows? So you should inherit from Popup, right? Not necessarily.

     

    Another approach is to create your custom control, add a Popup to it, and use the popup service. In fact, this is exactly what ContextMenu and ToolTip do. Popup, ContextMenu, and ToolTip all have the following properties defined, but the ContextMenu and ToolTip actually leave it up to the Popup to implement them.

     

    • Placement
    • PlacementTarget
    • PlacementRectangle
    • HorizontalOffset
    • VerticalOffset
    • IsOpen

     

    The ContextMenu and ToolTip call the Popup.CreateRootPopup which sets the Popup.Child property to the control and binds the six properties of the Popup to the control. 

     

    Doing the same for your custom control is easy enough. I created a control that accepts text and is editable. I could have added a TextBox to a control that inherits from Popup, but then I either hide the functionality of the TextBox from application developers, or have to expose TextBox through a property. Furthermore, Popup does not inherit from Control, so I wouldn’t have the ability to template the control. Instead, I inherited from TextBox. Below is the beginning of my control, EditablePopup.

     

        public partial class EditablePopup : System.Windows.Controls.TextBox

        {

            Popup _parentPopup;

     

            public EditablePopup()

                : base()

            {

            }

     

            static EditablePopup()

            {

                //This OverrideMetadata call tells the system that this element

                //wants to provide a style that is different than its base class.

                //This style is defined in themes"generic.xaml

                DefaultStyleKeyProperty.OverrideMetadata(typeof(EditablePopup),

                    new FrameworkPropertyMetadata(typeof(EditablePopup)));

            }

        }

     

     

    I don’t want my EditablePopup to look like a normal TextBox, so I define my Template to contain a border and a decorator.

     

     <Style TargetType="{x:Type local:EditablePopup}">

        <Setter Property="Margin" Value="1"/>

        <Setter Property="Template">

          <Setter.Value>

            <!--Create a TextBox that looks "flat".

                  The control template for a TextBox or RichTextBox must

                  include an element tagged as the content host. An element is

                  tagged as the content host element when it has the special name

                  PART_ContentHost. The content host element must be a ScrollViewer,

                  or an element that derives from Decorator. 

                  -->

            <ControlTemplate TargetType="{x:Type local:EditablePopup}">

              <Border Background="{TemplateBinding Background}"

                      BorderBrush="{TemplateBinding BorderBrush}"

                      BorderThickness="{TemplateBinding BorderThickness}">

                <Decorator x:Name="PART_ContentHost"/>

              </Border>

            </ControlTemplate>

          </Setter.Value>

        </Setter>

     </Style>

     

     

    Now I need to add the six properties I mentioned above to my control. Because Popup has these properties, creating the first five is pretty straightforward. You just need to call AddOwner on each DependencyProperty of the Popup and provide CLR Accessors. For more information about creating dependency properties, see Custom Dependency Properties in the SDK. Here are the declarations for Placement, PlacementTarget, PlacementRectangle, HorizontalOffset, and VerticalOffset:

     

            //Placement

            public static readonly DependencyProperty PlacementProperty =

                        Popup.PlacementProperty.AddOwner(typeof(EditablePopup));

     

            public PlacementMode Placement

            {

                get { return (PlacementMode)GetValue(PlacementProperty); }

                set { SetValue(PlacementProperty, value); }

            }

     

            //PlacementTarget

            public static readonly DependencyProperty PlacementTargetProperty =

               Popup.PlacementTargetProperty.AddOwner(typeof(EditablePopup));

     

            public UIElement PlacementTarget

            {

                get { return (UIElement)GetValue(PlacementTargetProperty); }

                set { SetValue(PlacementTargetProperty, value); }

            }

     

            //PlacementRectangle

            public static readonly DependencyProperty PlacementRectangleProperty =

                        Popup.PlacementRectangleProperty.AddOwner(typeof(EditablePopup));

     

            public Rect PlacementRectangle

            {

                get { return (Rect)GetValue(PlacementRectangleProperty); }

                set { SetValue(PlacementRectangleProperty, value); }

            }

     

            //HorizontalOffset

            public static readonly DependencyProperty HorizontalOffsetProperty =

                Popup.HorizontalOffsetProperty.AddOwner(typeof(EditablePopup));

     

            public double HorizontalOffset

            {

                get { return (double)GetValue(HorizontalOffsetProperty); }

                set { SetValue(HorizontalOffsetProperty, value); }

            }

     

            //VerticalOffset

            public static readonly DependencyProperty VerticalOffsetProperty =

                    Popup.VerticalOffsetProperty.AddOwner(typeof(EditablePopup));

     

            public double VerticalOffset

            {

                get { return (double)GetValue(VerticalOffsetProperty); }

                set { SetValue(VerticalOffsetProperty, value); }

            }

     

    Adding the IsOpen property is a little more involved, but isn’t that complex. When you define the DependenceProperty for IsOpen, you also need to provide a callback function when the value for IsOpen changes. When IsOpen is true, create the Popup and call Popup.CreateRootPopup.

     

            public static readonly DependencyProperty IsOpenProperty =

                    Popup.IsOpenProperty.AddOwner(

                            typeof(EditablePopup),

                            new FrameworkPropertyMetadata(

                                    false,

                                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,

                                    new PropertyChangedCallback(OnIsOpenChanged)));

     

            public bool IsOpen

            {

                get { return (bool)GetValue(IsOpenProperty); }

                set { SetValue(IsOpenProperty, value); }

            }

     

            private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

            {

                EditablePopup ctrl = (EditablePopup)d;

     

                if ((bool)e.NewValue)

                {

                    if (ctrl._parentPopup == null)

                    {

                        ctrl.HookupParentPopup();

                    }

                }

            }

     

            private void HookupParentPopup()

            {

     

                _parentPopup = new Popup();

     

                _parentPopup.AllowsTransparency = true;

     

                Popup.CreateRootPopup(_parentPopup, this);

            }

     

    Now that we’ve made the control, there are a few things to keep in mind before you use the control. First, set PlacementTarget before you call CreateRootPopup. If you call CreateRootPopup first, the PlacementTarget is ignored. Essentially this means you need to set PlacementTarget before setting IsOpen to true, just like you need to for a Popup.

     

    Second, CreateRootPopup sets the Child property of the Popup to your custom control. As a result, your custom control cannot have a logical or visual parent and the following doesn’t work:

     

        <WrapPanel>

          <src:EditablePopup IsOpen="True">Hello</src:EditablePopup>

        </WrapPanel>

     

    Instead, you need to create your control as a resource, or create it in code. In my project, I created the EditablePopup controls in code.

     

                budapestDesc = new EditablePopup();

                budapestDesc.Text = "Title:"tBudapest, Hungary"n" +

                                    "Description:"n"tHungarian Parliament Building and the Danube River";

                budapestDesc.PlacementTarget = budapestPic;

     

    Now I can position the EditablePopup, just like I would a Popup, ContextMenu, or ToolTip, by setting the Placement, PlacementRectangle, HorizontalOffset, and VerticalOffset properties.

     

    I’ve attached the EditablePopup zip file so you can download and experiment with it.

    Published Friday, April 27, 2007 2:58 PM by wcsdkteam
    Attachment(s): EditablePopup.zip
  • 相关阅读:
    2013第49周四开发一定要细心
    2013第49周三IE9文档模式
    2013第49周二要转变
    2013第49周一jsp标签
    2013第48周11月工作小结
    2013第48周六记
    2013第48周五开发日记
    BZOJ 1269 文本编辑器 Splay
    审批流程设计方案-介绍(一)
    Web挖掘技术
  • 原文地址:https://www.cnblogs.com/liangouyang/p/1324231.html
Copyright © 2020-2023  润新知