GridViewColumnHeader.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / GridViewColumnHeader.cs / 1407647 / GridViewColumnHeader.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

 
using System.ComponentModel; 
using System.Diagnostics;
using System.Runtime.InteropServices;       // SafeHandle 
using System.Security;                      // [SecurityCritical]
using System.Security.Permissions;
using System.Windows.Automation.Peers;      // AutomationPeer
using System.Windows.Controls.Primitives;   // ButtonBase 
using System.Windows.Input;                 // MouseButtonEventArgs
using System.Windows.Media;                 // VisualBrush 
 
using MS.Internal;                          // DoubleUtil
using MS.Internal.KnownBoxes;               // BooleanBoxes 
using MS.Win32;                             // SafeNativeMethods


namespace System.Windows.Controls 
{
    ///  
    /// Defines the different roles of GridViewColumnHeaders 
    /// 
    public enum GridViewColumnHeaderRole 
    {
        /// 
        /// The normal header
        ///  
        Normal,
        ///  
        /// The floating header (when dragging a header) 
        /// 
        Floating, 
        /// 
        /// The padding header (the very last header in header bar)
        /// 
        Padding 
    }
 
    ///  
    /// column header of GridView
    ///  
#if OLD_AUTOMATION
    [Automation(AccessibilityControlType = "Button")]
#endif
    [TemplatePart(Name = "PART_HeaderGripper", Type = typeof(Thumb))] 
    [TemplatePart(Name = "PART_FloatingHeaderCanvas", Type = typeof(Canvas))]
    public class GridViewColumnHeader : ButtonBase 
#if OLD_AUTOMATION 
    , IInvokeProvider
#endif 
    {
        //-------------------------------------------------------------------
        //
        //  Constructors 
        //
        //------------------------------------------------------------------- 
 
        #region Constructor
 
        static GridViewColumnHeader()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(typeof(GridViewColumnHeader)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(GridViewColumnHeader)); 

            FocusableProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 
 
            // hookup property change event.
            StyleProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged))); 
            ContentTemplateProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged)));
            ContentTemplateSelectorProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged)));
            ContextMenuProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged)));
            ToolTipProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged))); 
        }
 
        #endregion 

        //-------------------------------------------------------------------- 
        //
        //  Public Methods
        //
        //------------------------------------------------------------------- 

        #region Public Methods 
 
        /// 
        /// Called when the Template's tree has been generated 
        /// 
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate(); 

            GridViewColumnHeaderRole role = Role; 
 
            if (role == GridViewColumnHeaderRole.Normal)
            { 
                HookupGripperEvents();
            }
            else if (role == GridViewColumnHeaderRole.Floating)
            { 
                // if this is a floating header, try to find the FloatingHeaderCanvas,
                // and copy source header's visual to it 
                _floatingHeaderCanvas = GetTemplateChild(FloatingHeaderCanvasTemplateName) as Canvas; 

                UpdateFloatingHeaderCanvas(); 
            }
        }

        #endregion 

        //-------------------------------------------------------------------- 
        // 
        //  Public Properties
        // 
        //--------------------------------------------------------------------

        #region Public Properties
 
        /// 
        /// The key for Column (read-only property) 
        ///  
        internal static readonly DependencyPropertyKey ColumnPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "Column",
                        typeof(GridViewColumn),
                        typeof(GridViewColumnHeader),
                        null); 

        ///  
        /// The DependencyProperty for the Column property. 
        /// 
        public static readonly DependencyProperty ColumnProperty = 
                ColumnPropertyKey.DependencyProperty;

        /// 
        /// Column associated with this header 
        /// 
        public GridViewColumn Column 
        { 
            get { return (GridViewColumn)GetValue(ColumnProperty); }
        } 

        /// 
        /// The key for Role (read-only property)
        ///  
        internal static readonly DependencyPropertyKey RolePropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "Role", 
                        typeof(GridViewColumnHeaderRole),
                        typeof(GridViewColumnHeader), 
                        new FrameworkPropertyMetadata(GridViewColumnHeaderRole.Normal));

        /// 
        /// The DependencyProperty for the Role property. 
        /// 
        public static readonly DependencyProperty RoleProperty = 
                RolePropertyKey.DependencyProperty; 

        ///  
        /// What the role of the header is: Normal, Floating, Padding.
        /// 
        [Category("Behavior")]
        public GridViewColumnHeaderRole Role 
        {
            get { return (GridViewColumnHeaderRole)GetValue(RoleProperty); } 
        } 

        #endregion Public Properties 

#if OLD_AUTOMATION
        //-------------------------------------------------------------------
        // 
        //  IInvodeProvider
        // 
        //-------------------------------------------------------------------- 

        void IInvokeProvider.Invoke() 
        {
            IsAccessKeyOrAutomation = true;
            OnClick();
        } 
#endif
        //------------------------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //-------------------------------------------------------------------

        #region Protected Methods
 
        /// 
        /// This is the method that responds to the MouseButtonEvent event. 
        ///  
        /// Event arguments
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) 
        {
            base.OnMouseLeftButtonUp(e);

            // give parent a chance to handle MouseButtonEvent (for GridViewHeaderRowPresenter by default) 
            e.Handled = false;
 
            if (ClickMode == ClickMode.Hover && IsMouseCaptured) 
            {
                ReleaseMouseCapture(); 
            }
        }

        ///  
        /// This is the method that responds to the MouseButtonEvent event.
        ///  
        /// Event arguments 
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        { 
            base.OnMouseLeftButtonDown(e);

            // give parent a chance to handle MouseButtonEvent (for GridViewHeaderRowPresenter by default)
            e.Handled = false; 

            //If ClickMode is Hover, we must capture mouse in order to let column reorder work correctly (Bug#1496673) 
            if (ClickMode == ClickMode.Hover && e.ButtonState == MouseButtonState.Pressed) 
            {
                CaptureMouse(); 
            }
        }

        ///  
        /// This is the method that responds to the MouseMoveEvent event.
        ///  
        /// Event arguments 
        protected override void OnMouseMove(MouseEventArgs e)
        { 
            base.OnMouseMove(e);

            // Override base method: if left mouse is pressed, always set IsPressed as true
            if ((ClickMode != ClickMode.Hover) && 
                (IsMouseCaptured && (Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed)))
            { 
                SetValue(ButtonBase.IsPressedPropertyKey, BooleanBoxes.TrueBox); 
            }
 
            e.Handled = false;
        }

        ///  
        /// Override for 
        ///  
        protected internal override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) 
        {
            base.OnRenderSizeChanged(sizeInfo); 

            // when render size is changed, check to hide the previous header's right half gripper
            CheckWidthForPreviousHeaderGripper();
        } 

        ///  
        /// Override base method: raises the Click event only when not re-ordering 
        /// 
        protected override void OnClick() 
        {
            // if not suppress click event
            if (!SuppressClickEvent)
            { 
                // if is clicked by access key or automation,
                // otherwise should be clicked by mouse 
                if (IsAccessKeyOrAutomation || !IsMouseOutside()) 
                {
                    IsAccessKeyOrAutomation = false; 
                    ClickImplement();
                    MakeParentGotFocus();
                }
            } 
        }
 
        ///  
        /// The Access key for this control was invoked.
        ///  
        protected override void OnAccessKey(AccessKeyEventArgs e)
        {
            IsAccessKeyOrAutomation = true;
 
            base.OnAccessKey(e);
        } 
 
        /// 
        /// Stop Style, ContentTemplate , ContentTemplateSelector, ContextMenu and ToolTip properties 
        /// from been serialized in case the value are pushed from GridView or GridViewHeaderRowPresenter.
        /// 
        protected internal override bool ShouldSerializeProperty(DependencyProperty dp)
        { 
            if (IsInternalGenerated)
            { 
                // we should never reach here since this header is instantiated by HeaderRowPresenter. 
                Debug.Assert(false, "Method ShouldSerializeProperty is called on an internally generated GridViewColumnHeader.");
 
                // nothing should be serialized from this object.
                return false;
            }
 
            Flags flag, ignoreFlag;
            PropertyToFlags(dp, out flag, out ignoreFlag); //ignoreFlag is never used in this method. 
 
            return ((flag == Flags.None) || GetFlag(flag))
                && base.ShouldSerializeProperty(dp); 
        }

        /// 
        /// An event reporting the mouse entered this element. 
        /// 
        /// Event arguments 
        //Override OnMouseEnter/Leave to process the ClickMode == Hover case 
        protected override void OnMouseEnter(MouseEventArgs e)
        { 
            if (HandleIsMouseOverChanged())
            {
                e.Handled = true;
            } 
        }
 
        ///  
        /// An event reporting the mouse left this element.
        ///  
        /// Event arguments
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            if (HandleIsMouseOverChanged()) 
            {
                e.Handled = true; 
            } 
        }
 
        /// 
        ///     An event announcing that the keyboard is no longer focused
        /// 
        /// Event arguments 
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        { 
            base.OnLostKeyboardFocus(e); 

            if (ClickMode == ClickMode.Hover && IsMouseCaptured) 
            {
                ReleaseMouseCapture();
            }
        } 

        #endregion Protected Methods 
 
        //-------------------------------------------------------------------
        // 
        //  Internal Methods
        //
        //--------------------------------------------------------------------
 
        #region Internal Methods
 
        ///  
        /// This method is called when column header is clicked via IInvokeProvider.
        ///  
        internal void AutomationClick()
        {
            IsAccessKeyOrAutomation = true;
            OnClick(); 
        }
 
        // cancel resizing if Escape key down. 
        internal void OnColumnHeaderKeyDown(object sender, KeyEventArgs e)
        { 
            if (e.Key == Key.Escape && _headerGripper != null && _headerGripper.IsDragging)
            {
                // NOTE: this will cause Thumb to complete the dragging and fire drag
                // complete event with the Canceled property as 'True'. Handler 
                // OnColumnHeaderGripperDragCompleted will restore the width.
                _headerGripper.CancelDrag(); 
                e.Handled = true; 
            }
        } 

        // Check to see if hide previous header's right half gripper
        internal void CheckWidthForPreviousHeaderGripper()
        { 
            bool hideGripperRightHalf = false;
 
            if (_headerGripper != null) 
            {
                // when header's width is less than gripper's width, 
                // hide the right half of the left header's gripper
                hideGripperRightHalf = DoubleUtil.LessThan(ActualWidth, _headerGripper.Width);
            }
 
            if (_previousHeader != null)
            { 
                _previousHeader.HideGripperRightHalf(hideGripperRightHalf); 
            }
 
            UpdateGripperCursor();
        }

        // Fix for bug 1269757 in Windows OS Bugs.  Reset the background visual brush ref to 
        // avoid keeping it alive.  Keeping a VisualBrush alive causes us to assume that the
        // entire Visual tree is a graph, preventing an optimized render walk of only 
        // the dirty subtree.  We would end up rendering all of our realizations on each 
        // frame, causing high CPU consumption when a large realization tree is present.
        internal void ResetFloatingHeaderCanvasBackground() 
        {
            if (_floatingHeaderCanvas != null)
            {
                _floatingHeaderCanvas.Background = null; 
            }
        } 
 
        /// 
        /// This method is called iff related properties are passed from GirdView/GridViewColumn to header. 
        /// And must use this method to update property from GirdView/GridViewColumn to header.
        ///
        /// If this header is instantiated by user, before actually update the property,
        /// this method will turn on the IgnoreXXX flag. And the PropertyChangeCallBack 
        /// will check this flag, and know that this update is an internal operation. By
        /// doing this, we can distinguish {the property change by user} from {the change 
        /// by HeaderRowPresenter}. 
        /// 
        /// the property you want to update 
        /// a null value will result in ClearValue operation
        internal void UpdateProperty(DependencyProperty dp, object value)
        {
            Flags ignoreFlag = Flags.None; 

            if (!IsInternalGenerated) 
            { 
                Flags flag;
                PropertyToFlags(dp, out flag, out ignoreFlag); 
                Debug.Assert(flag != Flags.None && ignoreFlag != Flags.None, "Invalid parameter dp.");

                if (GetFlag(flag)) /* user has provided value for the property */
                { 
                    return;
                } 
                else 
                {
                    SetFlag(ignoreFlag, true); 
                }
            }

            if (value != null) 
            {
                SetValue(dp, value); 
            } 
            else
            { 
                ClearValue(dp);
            }

            SetFlag(ignoreFlag, false); 
        }
 
        #endregion Internal Methods 

        //------------------------------------------------------------------- 
        //
        //  Internal Properties
        //
        //-------------------------------------------------------------------- 

        #region Internal Properties 
 
        #region DTypeThemeStyleKey
 
        // Returns the DependencyObjectType for the registered ThemeStyleKey's default
        // value. Controls will override this method to return approriate types.
        internal override DependencyObjectType DTypeThemeStyleKey
        { 
            get { return _dType; }
        } 
 
        private static DependencyObjectType _dType;
 
        #endregion DTypeThemeStyleKey

        #region PreviousVisualHeader
 
        // Link to the previous visual column header, the value is filled by GridViewHeaderRowPresenter
        internal GridViewColumnHeader PreviousVisualHeader 
        { 
            get { return _previousHeader; }
            set { _previousHeader = value; } 
        }

        private GridViewColumnHeader _previousHeader;
 
        #endregion PreviousVisualHeader
 
        #region SuppressClickEvent 

        // indicating whether to fire click event 
        internal bool SuppressClickEvent
        {
            get { return GetFlag(Flags.SuppressClickEvent); }
            set { SetFlag(Flags.SuppressClickEvent, value); } 
        }
 
        #endregion SuppressClickEvent 

        // the source header for floating 
        // This property is only used to create VisualBrush for floating header,
        // and will be set to null when VisualBrush is created. Set to null for GC.
        internal GridViewColumnHeader FloatSourceHeader
        { 
            get { return _srcHeader; }
            set { _srcHeader = value; } 
        } 

        // whether this header is generated by GVHeaderRowPresenter or user 
        internal bool IsInternalGenerated
        {
            get { return GetFlag(Flags.IsInternalGenerated); }
            set { SetFlag(Flags.IsInternalGenerated, value); } 
        }
 
        #endregion Internal Properties 

        //-------------------------------------------------------------------- 
        //
        //  Accessibility
        //
        //------------------------------------------------------------------- 

        #region Accessibility 
 
        /// 
        /// Creates AutomationPeer () 
        /// 
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new GridViewColumnHeaderAutomationPeer(this); 
        }
 
        #endregion 

        //-------------------------------------------------------------------- 
        //
        //  Private Methods
        //
        //------------------------------------------------------------------- 

        #region Private Methods 
 
        private static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            GridViewColumnHeader header = (GridViewColumnHeader)d;
            if (!header.IsInternalGenerated)
            {
                Flags flag, ignoreFlag; 
                PropertyToFlags(e.Property, out flag, out ignoreFlag);
 
                if (!header.GetFlag(ignoreFlag)) // value is updated by user 
                {
                    if (e.NewValueSource == BaseValueSourceInternal.Local) 
                    {
                        header.SetFlag(flag, true);
                    }
                    else 
                    {
                        header.SetFlag(flag, false); 
 
                        GridViewHeaderRowPresenter headerRowPresenter = header.Parent as GridViewHeaderRowPresenter;
                        if (headerRowPresenter != null) 
                        {
                            headerRowPresenter.UpdateHeaderProperty(header, e.Property);
                        }
                    } 
                }
            } 
        } 

        private static void PropertyToFlags(DependencyProperty dp, out Flags flag, out Flags ignoreFlag) 
        {
            if (dp == GridViewColumnHeader.StyleProperty)
            {
                flag = Flags.StyleSetByUser; 
                ignoreFlag = Flags.IgnoreStyle;
            } 
            else if (dp == GridViewColumnHeader.ContentTemplateProperty) 
            {
                flag = Flags.ContentTemplateSetByUser; 
                ignoreFlag = Flags.IgnoreContentTemplate;
            }
            else if (dp == GridViewColumnHeader.ContentTemplateSelectorProperty)
            { 
                flag = Flags.ContentTemplateSelectorSetByUser;
                ignoreFlag = Flags.IgnoreContentTemplateSelector; 
            } 
            else if (dp == GridViewColumnHeader.ContentStringFormatProperty)
            { 
                flag = Flags.ContentStringFormatSetByUser;
                ignoreFlag = Flags.IgnoreContentStringFormat;
            }
            else if (dp == GridViewColumnHeader.ContextMenuProperty) 
            {
                flag = Flags.ContextMenuSetByUser; 
                ignoreFlag = Flags.IgnoreContextMenu; 
            }
            else if (dp == GridViewColumnHeader.ToolTipProperty) 
            {
                flag = Flags.ToolTipSetByUser;
                ignoreFlag = Flags.IgnoreToolTip;
            } 
            else
            { 
                flag = ignoreFlag = Flags.None; 
            }
        } 

        /// 
        /// Hide the right half of gripper
        /// +-----------------+ 
        /// +            +----+
        /// +  Header    + Re + 
        /// +            +    + 
        /// +            +----+
        /// +-----------------+ 
        /// 
        /// 
        private void HideGripperRightHalf(bool hide)
        { 
            if (_headerGripper != null)
            { 
                // hide gripper's right half by setting Parent.ClipToBounds=true 
                FrameworkElement gripperContainer = _headerGripper.Parent as FrameworkElement;
                if (gripperContainer != null) 
                {
                    gripperContainer.ClipToBounds = hide;
                }
            } 
        }
 
        // Save the original width before header resize 
        private void OnColumnHeaderGripperDragStarted(object sender, DragStartedEventArgs e)
        { 
            MakeParentGotFocus();
            _originalWidth = ColumnActualWidth;
            e.Handled = true;
        } 

        //Because ColumnHeader isn't focusable, we must forward focus to ListView when user invoke the header by access key 
        private void MakeParentGotFocus() 
        {
            GridViewHeaderRowPresenter headerRP = this.Parent as GridViewHeaderRowPresenter; 
            if (headerRP != null)
            {
                headerRP.MakeParentItemsControlGotFocus();
            } 
        }
 
        // Resize the header 
        private void OnColumnHeaderResize(object sender, DragDeltaEventArgs e)
        { 
            double width = ColumnActualWidth + e.HorizontalChange;
            if (DoubleUtil.LessThanOrClose(width, 0.0))
            {
                width = 0.0; 
            }
 
            UpdateColumnHeaderWidth(width); 
            e.Handled = true;
        } 

        private void OnColumnHeaderGripperDragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (e.Canceled) 
            {
                // restore to original width 
                UpdateColumnHeaderWidth(_originalWidth); 
            }
 
            UpdateGripperCursor();
            e.Handled = true;
        }
 
        /// 
        /// Find gripper and register drag event 
        /// 
        /// The default style for GridViewColumnHeader is
        /// +-----------------+ 
        /// +            +----------+
        /// +  Header    + Gripper  +
        /// +            +          +
        /// +            +----------+ 
        /// +-----------------+
        ///  
        private void HookupGripperEvents() 
        {
            UnhookGripperEvents(); 

            _headerGripper = GetTemplateChild(HeaderGripperTemplateName) as Thumb;

            if (_headerGripper != null) 
            {
                _headerGripper.DragStarted += new DragStartedEventHandler(OnColumnHeaderGripperDragStarted); 
                _headerGripper.DragDelta += new DragDeltaEventHandler(OnColumnHeaderResize); 
                _headerGripper.DragCompleted += new DragCompletedEventHandler(OnColumnHeaderGripperDragCompleted);
                _headerGripper.MouseDoubleClick += new MouseButtonEventHandler(OnGripperDoubleClicked); 
                _headerGripper.MouseEnter += new MouseEventHandler(OnGripperMouseEnterLeave);
                _headerGripper.MouseLeave += new MouseEventHandler(OnGripperMouseEnterLeave);

                _headerGripper.Cursor = SplitCursor; 
            }
        } 
 
        private void OnGripperDoubleClicked(object sender, MouseButtonEventArgs e)
        { 
            if (Column != null)
            {
                if (Double.IsNaN(Column.Width))
                { 
                    // force update will be triggered
                    Column.Width = Column.ActualWidth; 
                } 

                Column.Width = Double.NaN; 

                e.Handled = true;
            }
        } 

        ///  
        /// Clear gripper event 
        /// 
        private void UnhookGripperEvents() 
        {
            if (_headerGripper != null)
            {
                _headerGripper.DragStarted -= new DragStartedEventHandler(OnColumnHeaderGripperDragStarted); 
                _headerGripper.DragDelta -= new DragDeltaEventHandler(OnColumnHeaderResize);
                _headerGripper.DragCompleted -= new DragCompletedEventHandler(OnColumnHeaderGripperDragCompleted); 
                _headerGripper.MouseDoubleClick -= new MouseButtonEventHandler(OnGripperDoubleClicked); 
                _headerGripper.MouseEnter -= new MouseEventHandler(OnGripperMouseEnterLeave);
                _headerGripper.MouseLeave -= new MouseEventHandler(OnGripperMouseEnterLeave); 
                _headerGripper = null;
            }
        }
 
        /// 
        /// Critical - Asserts permissions required to call Cursor constructor in partial trust 
        /// TreatAsSafe - Can only be used to create one of two specific cursors (which are embedded resources within assembly). 
        /// The following Permissions are required to invoke Cursor.LoadFromStream method which writes stream to a temporary file and loads the Cursor from that file.
        /// The Environment permission is safe because even if the caller sets the %TEMP% variable to a critical location 
        /// before executing the method, the caller does not choose the filename that is written to.
        /// Additionally the temp filename algorithm tries to avoid name collisions.
        /// Therefore it is reasonably unlikely that the caller can use this method to overwrite a critical file.
        /// The FileIO write permission is safe because from the above justification the file being written to is reasonably safe. 
        /// The Unmanaged code permission is safe because it is used for a safe p-invoke to load a cursor from a file
        /// (the bytes read are never exposed to the caller) 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private Cursor GetCursor(int cursorID) 
        {
            Invariant.Assert(cursorID == c_SPLIT || cursorID == c_SPLITOPEN, "incorrect cursor type");

            Cursor cursor = null; 
            System.IO.Stream stream = null;
            System.Reflection.Assembly assembly = this.GetType().Assembly; 
 
            if (cursorID == c_SPLIT)
            { 
                stream = assembly.GetManifestResourceStream("split.cur");
            }
            else if (cursorID == c_SPLITOPEN)
            { 
                stream = assembly.GetManifestResourceStream("splitopen.cur");
            } 
 
            Debug.Assert(stream != null, "stream is null");
            if (stream != null) 
            {
                PermissionSet permissions = new PermissionSet(null);

                FileIOPermission filePermission = new FileIOPermission(PermissionState.None); 
                filePermission.AllLocalFiles = FileIOPermissionAccess.Write;
                permissions.AddPermission(filePermission); 
 
                permissions.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
                permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)); 
                permissions.Assert();

                try
                { 
                    cursor = new Cursor(stream);
                } 
                finally 
                {
                    CodeAccessPermission.RevertAssert(); 
                }
            }

            return cursor; 
        }
 
        private void UpdateGripperCursor() 
        {
            if (_headerGripper != null && !_headerGripper.IsDragging) 
            {
                Cursor gripperCursor;

                if (DoubleUtil.IsZero(ActualWidth)) 
                {
                    gripperCursor = SplitOpenCursor; 
                } 
                else
                { 
                    gripperCursor = SplitCursor;
                }

                Debug.Assert(gripperCursor != null, "gripper cursor is null"); 
                if (gripperCursor != null)
                { 
                    _headerGripper.Cursor = gripperCursor; 
                }
            } 
        }

        // Set column header width and associated column width
        private void UpdateColumnHeaderWidth(double width) 
        {
            if (Column != null) 
            { 
                Column.Width = width;
            } 
            else
            {
                Width = width;
            } 
        }
 
        private bool IsMouseOutside() 
        {
            Point pos = Mouse.PrimaryDevice.GetPosition(this); 

            return !((pos.X >= 0) && (pos.X <= ActualWidth) && (pos.Y >= 0) && (pos.Y <= ActualHeight));
        }
 
        private void ClickImplement()
        { 
            if (AutomationPeer.ListenerExists(AutomationEvents.InvokePatternOnInvoked)) 
            {
                AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this); 
                if (peer != null)
                    peer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked);
            }
 
            base.OnClick();
        } 
 
        private bool GetFlag(Flags flag)
        { 
            return (_flags & flag) == flag;
        }

        private void SetFlag(Flags flag, bool set) 
        {
            if (set) 
            { 
                _flags |= flag;
            } 
            else
            {
                _flags &= (~flag);
            } 
        }
 
        // update the background visual brush 
        private void UpdateFloatingHeaderCanvas()
        { 
            if (_floatingHeaderCanvas != null
                && FloatSourceHeader != null)
            {
                // because the gripper is partially positioned out of the header, we need to 
                // map the appropriate area(viewbox) in the source header to visual brush
                // to avoid a distorded image on the floating header. 
                Vector offsetVector = VisualTreeHelper.GetOffset(FloatSourceHeader); 
                VisualBrush visualBrush = new VisualBrush(FloatSourceHeader);
 
                // set visual brush's mapping
                visualBrush.ViewboxUnits = BrushMappingMode.Absolute;
                visualBrush.Viewbox = new Rect(offsetVector.X, offsetVector.Y, FloatSourceHeader.ActualWidth, FloatSourceHeader.ActualHeight);
 
                _floatingHeaderCanvas.Background = visualBrush;
                FloatSourceHeader = null; 
            } 
        }
 
        /// 
        /// Handle IsMouseOverChanged when ClickMode is Hover
        /// 
        // Note: When ClickMode is Hover, ColumnHeader will be click when mouse is over it 
        // Here are 2 cases:
        // 1) Mouse is over column header 
        //    OnClick will be called 
        // 2) Mouse is over gripper
        //    OnClick won't be called, only when the mouse leaves the gripper and move to header, OnClick will be called. 
        private bool HandleIsMouseOverChanged()
        {
            if (ClickMode == ClickMode.Hover)
            { 
                if (IsMouseOver &&
                    //1) Gripper doesn't exist; 2) Gripper exists and Mouse isn't on Gripper; 
                    (_headerGripper == null || !_headerGripper.IsMouseOver)) 
                {
                    // Hovering over the button will click in the OnHover click mode 
                    SetValue(IsPressedPropertyKey, BooleanBoxes.Box(true));
                    OnClick();
                }
                else 
                {
                    ClearValue(IsPressedPropertyKey); 
                } 
                return true;
            } 
            return false;
        }

        // When mouse enters/leaves gripper, recall HandleIsMouseOverChanged to verify is mouse over header or not 
        private void OnGripperMouseEnterLeave(object sender, MouseEventArgs e)
        { 
            HandleIsMouseOverChanged(); 
        }
 
        #endregion Private Methods

        //-------------------------------------------------------------------
        // 
        //  Private Properties
        // 
        //------------------------------------------------------------------- 

        #region Private Properties 

        #region SplitCursor

        private Cursor SplitCursor 
        {
            get 
            { 
                if (_splitCursorCache == null)
                { 
                    _splitCursorCache = GetCursor(c_SPLIT);
                }
                return _splitCursorCache;
            } 
        }
 
        static private Cursor _splitCursorCache = null; 

        #endregion SplitCursor 

        #region SplitOpenCursor

        private Cursor SplitOpenCursor 
        {
            get 
            { 
                if (_splitOpenCursorCache == null)
                { 
                    _splitOpenCursorCache = GetCursor(c_SPLITOPEN);
                }
                return _splitOpenCursorCache;
            } 
        }
 
        static private Cursor _splitOpenCursorCache = null; 

        #endregion SplitOpenCursor 

        // is clicked by access key or automation
        private bool IsAccessKeyOrAutomation
        { 
            get { return GetFlag(Flags.IsAccessKeyOrAutomation); }
            set { SetFlag(Flags.IsAccessKeyOrAutomation, value); } 
        } 

        private double ColumnActualWidth 
        {
            get { return (Column != null ? Column.ActualWidth : ActualWidth); }
        }
 
        #endregion Private Properties
 
        //-------------------------------------------------------------------- 
        //
        //  Private Fields 
        //
        //-------------------------------------------------------------------

        #region Private Fields 

        ///  
        /// StyleSetByUser: the value of Style property is set by user. 
        /// IgnoreStyle: the OnStyleChanged is triggered by HeaderRowPresenter,
        /// not by user. Don't turn on the StyleSetByUser flag. 
        /// And so on
        /// (Only for user provided header. Ignored for internal generated header)
        ///
        /// Go to UpdateProperty and OnPropetyChanged for how these flags work. 
        /// 
        [Flags] 
        private enum Flags 
        {
            // IgnoreXXX can't be combined into one flag. 
            // Reason:
            // Define a Style with ContentTemplate and assign it to GridViewColumn.HeaderContainerStyle property. GridViewColumnHeader.OnPropertyChagned method will be called twice.
            // The first call is for ContentTemplate property. In this call, IgnoreContentTemplate is false.
            // The second call is for Style property. In this call, IgnoreStyle is true. 
            // One flag can’t distinguish them.
            None                                = 0, 
            StyleSetByUser                      = 0x00000001, 
            IgnoreStyle                         = 0x00000002,
            ContentTemplateSetByUser            = 0x00000004, 
            IgnoreContentTemplate               = 0x00000008,
            ContentTemplateSelectorSetByUser    = 0x00000010,
            IgnoreContentTemplateSelector       = 0x00000020,
            ContextMenuSetByUser                = 0x00000040, 
            IgnoreContextMenu                   = 0x00000080,
            ToolTipSetByUser                    = 0x00000100, 
            IgnoreToolTip                       = 0x00000200, 

            SuppressClickEvent                  = 0x00000400, 
            IsInternalGenerated                 = 0x00000800,
            IsAccessKeyOrAutomation             = 0x00001000,

            ContentStringFormatSetByUser        = 0x00002000, 
            IgnoreContentStringFormat           = 0x00004000,
        } 
 
        private Flags _flags;
 
        private Thumb _headerGripper;

        private double _originalWidth;
 
        // canvas for floating header
        private Canvas _floatingHeaderCanvas; 
 
        private GridViewColumnHeader _srcHeader;
 
        // cursor id in embedded win32 resource
        private const int c_SPLIT = 100;
        private const int c_SPLITOPEN = 101;
 
        // Part name used in the style. The class TemplatePartAttribute should use the same name
        private const string HeaderGripperTemplateName = "PART_HeaderGripper"; 
        private const string FloatingHeaderCanvasTemplateName = "PART_FloatingHeaderCanvas"; 

        #endregion Private Fields 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

 
using System.ComponentModel; 
using System.Diagnostics;
using System.Runtime.InteropServices;       // SafeHandle 
using System.Security;                      // [SecurityCritical]
using System.Security.Permissions;
using System.Windows.Automation.Peers;      // AutomationPeer
using System.Windows.Controls.Primitives;   // ButtonBase 
using System.Windows.Input;                 // MouseButtonEventArgs
using System.Windows.Media;                 // VisualBrush 
 
using MS.Internal;                          // DoubleUtil
using MS.Internal.KnownBoxes;               // BooleanBoxes 
using MS.Win32;                             // SafeNativeMethods


namespace System.Windows.Controls 
{
    ///  
    /// Defines the different roles of GridViewColumnHeaders 
    /// 
    public enum GridViewColumnHeaderRole 
    {
        /// 
        /// The normal header
        ///  
        Normal,
        ///  
        /// The floating header (when dragging a header) 
        /// 
        Floating, 
        /// 
        /// The padding header (the very last header in header bar)
        /// 
        Padding 
    }
 
    ///  
    /// column header of GridView
    ///  
#if OLD_AUTOMATION
    [Automation(AccessibilityControlType = "Button")]
#endif
    [TemplatePart(Name = "PART_HeaderGripper", Type = typeof(Thumb))] 
    [TemplatePart(Name = "PART_FloatingHeaderCanvas", Type = typeof(Canvas))]
    public class GridViewColumnHeader : ButtonBase 
#if OLD_AUTOMATION 
    , IInvokeProvider
#endif 
    {
        //-------------------------------------------------------------------
        //
        //  Constructors 
        //
        //------------------------------------------------------------------- 
 
        #region Constructor
 
        static GridViewColumnHeader()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(typeof(GridViewColumnHeader)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(GridViewColumnHeader)); 

            FocusableProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 
 
            // hookup property change event.
            StyleProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged))); 
            ContentTemplateProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged)));
            ContentTemplateSelectorProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged)));
            ContextMenuProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged)));
            ToolTipProperty.OverrideMetadata(typeof(GridViewColumnHeader), new FrameworkPropertyMetadata(new PropertyChangedCallback(PropertyChanged))); 
        }
 
        #endregion 

        //-------------------------------------------------------------------- 
        //
        //  Public Methods
        //
        //------------------------------------------------------------------- 

        #region Public Methods 
 
        /// 
        /// Called when the Template's tree has been generated 
        /// 
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate(); 

            GridViewColumnHeaderRole role = Role; 
 
            if (role == GridViewColumnHeaderRole.Normal)
            { 
                HookupGripperEvents();
            }
            else if (role == GridViewColumnHeaderRole.Floating)
            { 
                // if this is a floating header, try to find the FloatingHeaderCanvas,
                // and copy source header's visual to it 
                _floatingHeaderCanvas = GetTemplateChild(FloatingHeaderCanvasTemplateName) as Canvas; 

                UpdateFloatingHeaderCanvas(); 
            }
        }

        #endregion 

        //-------------------------------------------------------------------- 
        // 
        //  Public Properties
        // 
        //--------------------------------------------------------------------

        #region Public Properties
 
        /// 
        /// The key for Column (read-only property) 
        ///  
        internal static readonly DependencyPropertyKey ColumnPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "Column",
                        typeof(GridViewColumn),
                        typeof(GridViewColumnHeader),
                        null); 

        ///  
        /// The DependencyProperty for the Column property. 
        /// 
        public static readonly DependencyProperty ColumnProperty = 
                ColumnPropertyKey.DependencyProperty;

        /// 
        /// Column associated with this header 
        /// 
        public GridViewColumn Column 
        { 
            get { return (GridViewColumn)GetValue(ColumnProperty); }
        } 

        /// 
        /// The key for Role (read-only property)
        ///  
        internal static readonly DependencyPropertyKey RolePropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "Role", 
                        typeof(GridViewColumnHeaderRole),
                        typeof(GridViewColumnHeader), 
                        new FrameworkPropertyMetadata(GridViewColumnHeaderRole.Normal));

        /// 
        /// The DependencyProperty for the Role property. 
        /// 
        public static readonly DependencyProperty RoleProperty = 
                RolePropertyKey.DependencyProperty; 

        ///  
        /// What the role of the header is: Normal, Floating, Padding.
        /// 
        [Category("Behavior")]
        public GridViewColumnHeaderRole Role 
        {
            get { return (GridViewColumnHeaderRole)GetValue(RoleProperty); } 
        } 

        #endregion Public Properties 

#if OLD_AUTOMATION
        //-------------------------------------------------------------------
        // 
        //  IInvodeProvider
        // 
        //-------------------------------------------------------------------- 

        void IInvokeProvider.Invoke() 
        {
            IsAccessKeyOrAutomation = true;
            OnClick();
        } 
#endif
        //------------------------------------------------------------------- 
        // 
        //  Protected Methods
        // 
        //-------------------------------------------------------------------

        #region Protected Methods
 
        /// 
        /// This is the method that responds to the MouseButtonEvent event. 
        ///  
        /// Event arguments
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e) 
        {
            base.OnMouseLeftButtonUp(e);

            // give parent a chance to handle MouseButtonEvent (for GridViewHeaderRowPresenter by default) 
            e.Handled = false;
 
            if (ClickMode == ClickMode.Hover && IsMouseCaptured) 
            {
                ReleaseMouseCapture(); 
            }
        }

        ///  
        /// This is the method that responds to the MouseButtonEvent event.
        ///  
        /// Event arguments 
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        { 
            base.OnMouseLeftButtonDown(e);

            // give parent a chance to handle MouseButtonEvent (for GridViewHeaderRowPresenter by default)
            e.Handled = false; 

            //If ClickMode is Hover, we must capture mouse in order to let column reorder work correctly (Bug#1496673) 
            if (ClickMode == ClickMode.Hover && e.ButtonState == MouseButtonState.Pressed) 
            {
                CaptureMouse(); 
            }
        }

        ///  
        /// This is the method that responds to the MouseMoveEvent event.
        ///  
        /// Event arguments 
        protected override void OnMouseMove(MouseEventArgs e)
        { 
            base.OnMouseMove(e);

            // Override base method: if left mouse is pressed, always set IsPressed as true
            if ((ClickMode != ClickMode.Hover) && 
                (IsMouseCaptured && (Mouse.PrimaryDevice.LeftButton == MouseButtonState.Pressed)))
            { 
                SetValue(ButtonBase.IsPressedPropertyKey, BooleanBoxes.TrueBox); 
            }
 
            e.Handled = false;
        }

        ///  
        /// Override for 
        ///  
        protected internal override void OnRenderSizeChanged(SizeChangedInfo sizeInfo) 
        {
            base.OnRenderSizeChanged(sizeInfo); 

            // when render size is changed, check to hide the previous header's right half gripper
            CheckWidthForPreviousHeaderGripper();
        } 

        ///  
        /// Override base method: raises the Click event only when not re-ordering 
        /// 
        protected override void OnClick() 
        {
            // if not suppress click event
            if (!SuppressClickEvent)
            { 
                // if is clicked by access key or automation,
                // otherwise should be clicked by mouse 
                if (IsAccessKeyOrAutomation || !IsMouseOutside()) 
                {
                    IsAccessKeyOrAutomation = false; 
                    ClickImplement();
                    MakeParentGotFocus();
                }
            } 
        }
 
        ///  
        /// The Access key for this control was invoked.
        ///  
        protected override void OnAccessKey(AccessKeyEventArgs e)
        {
            IsAccessKeyOrAutomation = true;
 
            base.OnAccessKey(e);
        } 
 
        /// 
        /// Stop Style, ContentTemplate , ContentTemplateSelector, ContextMenu and ToolTip properties 
        /// from been serialized in case the value are pushed from GridView or GridViewHeaderRowPresenter.
        /// 
        protected internal override bool ShouldSerializeProperty(DependencyProperty dp)
        { 
            if (IsInternalGenerated)
            { 
                // we should never reach here since this header is instantiated by HeaderRowPresenter. 
                Debug.Assert(false, "Method ShouldSerializeProperty is called on an internally generated GridViewColumnHeader.");
 
                // nothing should be serialized from this object.
                return false;
            }
 
            Flags flag, ignoreFlag;
            PropertyToFlags(dp, out flag, out ignoreFlag); //ignoreFlag is never used in this method. 
 
            return ((flag == Flags.None) || GetFlag(flag))
                && base.ShouldSerializeProperty(dp); 
        }

        /// 
        /// An event reporting the mouse entered this element. 
        /// 
        /// Event arguments 
        //Override OnMouseEnter/Leave to process the ClickMode == Hover case 
        protected override void OnMouseEnter(MouseEventArgs e)
        { 
            if (HandleIsMouseOverChanged())
            {
                e.Handled = true;
            } 
        }
 
        ///  
        /// An event reporting the mouse left this element.
        ///  
        /// Event arguments
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            if (HandleIsMouseOverChanged()) 
            {
                e.Handled = true; 
            } 
        }
 
        /// 
        ///     An event announcing that the keyboard is no longer focused
        /// 
        /// Event arguments 
        protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
        { 
            base.OnLostKeyboardFocus(e); 

            if (ClickMode == ClickMode.Hover && IsMouseCaptured) 
            {
                ReleaseMouseCapture();
            }
        } 

        #endregion Protected Methods 
 
        //-------------------------------------------------------------------
        // 
        //  Internal Methods
        //
        //--------------------------------------------------------------------
 
        #region Internal Methods
 
        ///  
        /// This method is called when column header is clicked via IInvokeProvider.
        ///  
        internal void AutomationClick()
        {
            IsAccessKeyOrAutomation = true;
            OnClick(); 
        }
 
        // cancel resizing if Escape key down. 
        internal void OnColumnHeaderKeyDown(object sender, KeyEventArgs e)
        { 
            if (e.Key == Key.Escape && _headerGripper != null && _headerGripper.IsDragging)
            {
                // NOTE: this will cause Thumb to complete the dragging and fire drag
                // complete event with the Canceled property as 'True'. Handler 
                // OnColumnHeaderGripperDragCompleted will restore the width.
                _headerGripper.CancelDrag(); 
                e.Handled = true; 
            }
        } 

        // Check to see if hide previous header's right half gripper
        internal void CheckWidthForPreviousHeaderGripper()
        { 
            bool hideGripperRightHalf = false;
 
            if (_headerGripper != null) 
            {
                // when header's width is less than gripper's width, 
                // hide the right half of the left header's gripper
                hideGripperRightHalf = DoubleUtil.LessThan(ActualWidth, _headerGripper.Width);
            }
 
            if (_previousHeader != null)
            { 
                _previousHeader.HideGripperRightHalf(hideGripperRightHalf); 
            }
 
            UpdateGripperCursor();
        }

        // Fix for bug 1269757 in Windows OS Bugs.  Reset the background visual brush ref to 
        // avoid keeping it alive.  Keeping a VisualBrush alive causes us to assume that the
        // entire Visual tree is a graph, preventing an optimized render walk of only 
        // the dirty subtree.  We would end up rendering all of our realizations on each 
        // frame, causing high CPU consumption when a large realization tree is present.
        internal void ResetFloatingHeaderCanvasBackground() 
        {
            if (_floatingHeaderCanvas != null)
            {
                _floatingHeaderCanvas.Background = null; 
            }
        } 
 
        /// 
        /// This method is called iff related properties are passed from GirdView/GridViewColumn to header. 
        /// And must use this method to update property from GirdView/GridViewColumn to header.
        ///
        /// If this header is instantiated by user, before actually update the property,
        /// this method will turn on the IgnoreXXX flag. And the PropertyChangeCallBack 
        /// will check this flag, and know that this update is an internal operation. By
        /// doing this, we can distinguish {the property change by user} from {the change 
        /// by HeaderRowPresenter}. 
        /// 
        /// the property you want to update 
        /// a null value will result in ClearValue operation
        internal void UpdateProperty(DependencyProperty dp, object value)
        {
            Flags ignoreFlag = Flags.None; 

            if (!IsInternalGenerated) 
            { 
                Flags flag;
                PropertyToFlags(dp, out flag, out ignoreFlag); 
                Debug.Assert(flag != Flags.None && ignoreFlag != Flags.None, "Invalid parameter dp.");

                if (GetFlag(flag)) /* user has provided value for the property */
                { 
                    return;
                } 
                else 
                {
                    SetFlag(ignoreFlag, true); 
                }
            }

            if (value != null) 
            {
                SetValue(dp, value); 
            } 
            else
            { 
                ClearValue(dp);
            }

            SetFlag(ignoreFlag, false); 
        }
 
        #endregion Internal Methods 

        //------------------------------------------------------------------- 
        //
        //  Internal Properties
        //
        //-------------------------------------------------------------------- 

        #region Internal Properties 
 
        #region DTypeThemeStyleKey
 
        // Returns the DependencyObjectType for the registered ThemeStyleKey's default
        // value. Controls will override this method to return approriate types.
        internal override DependencyObjectType DTypeThemeStyleKey
        { 
            get { return _dType; }
        } 
 
        private static DependencyObjectType _dType;
 
        #endregion DTypeThemeStyleKey

        #region PreviousVisualHeader
 
        // Link to the previous visual column header, the value is filled by GridViewHeaderRowPresenter
        internal GridViewColumnHeader PreviousVisualHeader 
        { 
            get { return _previousHeader; }
            set { _previousHeader = value; } 
        }

        private GridViewColumnHeader _previousHeader;
 
        #endregion PreviousVisualHeader
 
        #region SuppressClickEvent 

        // indicating whether to fire click event 
        internal bool SuppressClickEvent
        {
            get { return GetFlag(Flags.SuppressClickEvent); }
            set { SetFlag(Flags.SuppressClickEvent, value); } 
        }
 
        #endregion SuppressClickEvent 

        // the source header for floating 
        // This property is only used to create VisualBrush for floating header,
        // and will be set to null when VisualBrush is created. Set to null for GC.
        internal GridViewColumnHeader FloatSourceHeader
        { 
            get { return _srcHeader; }
            set { _srcHeader = value; } 
        } 

        // whether this header is generated by GVHeaderRowPresenter or user 
        internal bool IsInternalGenerated
        {
            get { return GetFlag(Flags.IsInternalGenerated); }
            set { SetFlag(Flags.IsInternalGenerated, value); } 
        }
 
        #endregion Internal Properties 

        //-------------------------------------------------------------------- 
        //
        //  Accessibility
        //
        //------------------------------------------------------------------- 

        #region Accessibility 
 
        /// 
        /// Creates AutomationPeer () 
        /// 
        protected override AutomationPeer OnCreateAutomationPeer()
        {
            return new GridViewColumnHeaderAutomationPeer(this); 
        }
 
        #endregion 

        //-------------------------------------------------------------------- 
        //
        //  Private Methods
        //
        //------------------------------------------------------------------- 

        #region Private Methods 
 
        private static void PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            GridViewColumnHeader header = (GridViewColumnHeader)d;
            if (!header.IsInternalGenerated)
            {
                Flags flag, ignoreFlag; 
                PropertyToFlags(e.Property, out flag, out ignoreFlag);
 
                if (!header.GetFlag(ignoreFlag)) // value is updated by user 
                {
                    if (e.NewValueSource == BaseValueSourceInternal.Local) 
                    {
                        header.SetFlag(flag, true);
                    }
                    else 
                    {
                        header.SetFlag(flag, false); 
 
                        GridViewHeaderRowPresenter headerRowPresenter = header.Parent as GridViewHeaderRowPresenter;
                        if (headerRowPresenter != null) 
                        {
                            headerRowPresenter.UpdateHeaderProperty(header, e.Property);
                        }
                    } 
                }
            } 
        } 

        private static void PropertyToFlags(DependencyProperty dp, out Flags flag, out Flags ignoreFlag) 
        {
            if (dp == GridViewColumnHeader.StyleProperty)
            {
                flag = Flags.StyleSetByUser; 
                ignoreFlag = Flags.IgnoreStyle;
            } 
            else if (dp == GridViewColumnHeader.ContentTemplateProperty) 
            {
                flag = Flags.ContentTemplateSetByUser; 
                ignoreFlag = Flags.IgnoreContentTemplate;
            }
            else if (dp == GridViewColumnHeader.ContentTemplateSelectorProperty)
            { 
                flag = Flags.ContentTemplateSelectorSetByUser;
                ignoreFlag = Flags.IgnoreContentTemplateSelector; 
            } 
            else if (dp == GridViewColumnHeader.ContentStringFormatProperty)
            { 
                flag = Flags.ContentStringFormatSetByUser;
                ignoreFlag = Flags.IgnoreContentStringFormat;
            }
            else if (dp == GridViewColumnHeader.ContextMenuProperty) 
            {
                flag = Flags.ContextMenuSetByUser; 
                ignoreFlag = Flags.IgnoreContextMenu; 
            }
            else if (dp == GridViewColumnHeader.ToolTipProperty) 
            {
                flag = Flags.ToolTipSetByUser;
                ignoreFlag = Flags.IgnoreToolTip;
            } 
            else
            { 
                flag = ignoreFlag = Flags.None; 
            }
        } 

        /// 
        /// Hide the right half of gripper
        /// +-----------------+ 
        /// +            +----+
        /// +  Header    + Re + 
        /// +            +    + 
        /// +            +----+
        /// +-----------------+ 
        /// 
        /// 
        private void HideGripperRightHalf(bool hide)
        { 
            if (_headerGripper != null)
            { 
                // hide gripper's right half by setting Parent.ClipToBounds=true 
                FrameworkElement gripperContainer = _headerGripper.Parent as FrameworkElement;
                if (gripperContainer != null) 
                {
                    gripperContainer.ClipToBounds = hide;
                }
            } 
        }
 
        // Save the original width before header resize 
        private void OnColumnHeaderGripperDragStarted(object sender, DragStartedEventArgs e)
        { 
            MakeParentGotFocus();
            _originalWidth = ColumnActualWidth;
            e.Handled = true;
        } 

        //Because ColumnHeader isn't focusable, we must forward focus to ListView when user invoke the header by access key 
        private void MakeParentGotFocus() 
        {
            GridViewHeaderRowPresenter headerRP = this.Parent as GridViewHeaderRowPresenter; 
            if (headerRP != null)
            {
                headerRP.MakeParentItemsControlGotFocus();
            } 
        }
 
        // Resize the header 
        private void OnColumnHeaderResize(object sender, DragDeltaEventArgs e)
        { 
            double width = ColumnActualWidth + e.HorizontalChange;
            if (DoubleUtil.LessThanOrClose(width, 0.0))
            {
                width = 0.0; 
            }
 
            UpdateColumnHeaderWidth(width); 
            e.Handled = true;
        } 

        private void OnColumnHeaderGripperDragCompleted(object sender, DragCompletedEventArgs e)
        {
            if (e.Canceled) 
            {
                // restore to original width 
                UpdateColumnHeaderWidth(_originalWidth); 
            }
 
            UpdateGripperCursor();
            e.Handled = true;
        }
 
        /// 
        /// Find gripper and register drag event 
        /// 
        /// The default style for GridViewColumnHeader is
        /// +-----------------+ 
        /// +            +----------+
        /// +  Header    + Gripper  +
        /// +            +          +
        /// +            +----------+ 
        /// +-----------------+
        ///  
        private void HookupGripperEvents() 
        {
            UnhookGripperEvents(); 

            _headerGripper = GetTemplateChild(HeaderGripperTemplateName) as Thumb;

            if (_headerGripper != null) 
            {
                _headerGripper.DragStarted += new DragStartedEventHandler(OnColumnHeaderGripperDragStarted); 
                _headerGripper.DragDelta += new DragDeltaEventHandler(OnColumnHeaderResize); 
                _headerGripper.DragCompleted += new DragCompletedEventHandler(OnColumnHeaderGripperDragCompleted);
                _headerGripper.MouseDoubleClick += new MouseButtonEventHandler(OnGripperDoubleClicked); 
                _headerGripper.MouseEnter += new MouseEventHandler(OnGripperMouseEnterLeave);
                _headerGripper.MouseLeave += new MouseEventHandler(OnGripperMouseEnterLeave);

                _headerGripper.Cursor = SplitCursor; 
            }
        } 
 
        private void OnGripperDoubleClicked(object sender, MouseButtonEventArgs e)
        { 
            if (Column != null)
            {
                if (Double.IsNaN(Column.Width))
                { 
                    // force update will be triggered
                    Column.Width = Column.ActualWidth; 
                } 

                Column.Width = Double.NaN; 

                e.Handled = true;
            }
        } 

        ///  
        /// Clear gripper event 
        /// 
        private void UnhookGripperEvents() 
        {
            if (_headerGripper != null)
            {
                _headerGripper.DragStarted -= new DragStartedEventHandler(OnColumnHeaderGripperDragStarted); 
                _headerGripper.DragDelta -= new DragDeltaEventHandler(OnColumnHeaderResize);
                _headerGripper.DragCompleted -= new DragCompletedEventHandler(OnColumnHeaderGripperDragCompleted); 
                _headerGripper.MouseDoubleClick -= new MouseButtonEventHandler(OnGripperDoubleClicked); 
                _headerGripper.MouseEnter -= new MouseEventHandler(OnGripperMouseEnterLeave);
                _headerGripper.MouseLeave -= new MouseEventHandler(OnGripperMouseEnterLeave); 
                _headerGripper = null;
            }
        }
 
        /// 
        /// Critical - Asserts permissions required to call Cursor constructor in partial trust 
        /// TreatAsSafe - Can only be used to create one of two specific cursors (which are embedded resources within assembly). 
        /// The following Permissions are required to invoke Cursor.LoadFromStream method which writes stream to a temporary file and loads the Cursor from that file.
        /// The Environment permission is safe because even if the caller sets the %TEMP% variable to a critical location 
        /// before executing the method, the caller does not choose the filename that is written to.
        /// Additionally the temp filename algorithm tries to avoid name collisions.
        /// Therefore it is reasonably unlikely that the caller can use this method to overwrite a critical file.
        /// The FileIO write permission is safe because from the above justification the file being written to is reasonably safe. 
        /// The Unmanaged code permission is safe because it is used for a safe p-invoke to load a cursor from a file
        /// (the bytes read are never exposed to the caller) 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        private Cursor GetCursor(int cursorID) 
        {
            Invariant.Assert(cursorID == c_SPLIT || cursorID == c_SPLITOPEN, "incorrect cursor type");

            Cursor cursor = null; 
            System.IO.Stream stream = null;
            System.Reflection.Assembly assembly = this.GetType().Assembly; 
 
            if (cursorID == c_SPLIT)
            { 
                stream = assembly.GetManifestResourceStream("split.cur");
            }
            else if (cursorID == c_SPLITOPEN)
            { 
                stream = assembly.GetManifestResourceStream("splitopen.cur");
            } 
 
            Debug.Assert(stream != null, "stream is null");
            if (stream != null) 
            {
                PermissionSet permissions = new PermissionSet(null);

                FileIOPermission filePermission = new FileIOPermission(PermissionState.None); 
                filePermission.AllLocalFiles = FileIOPermissionAccess.Write;
                permissions.AddPermission(filePermission); 
 
                permissions.AddPermission(new EnvironmentPermission(PermissionState.Unrestricted));
                permissions.AddPermission(new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)); 
                permissions.Assert();

                try
                { 
                    cursor = new Cursor(stream);
                } 
                finally 
                {
                    CodeAccessPermission.RevertAssert(); 
                }
            }

            return cursor; 
        }
 
        private void UpdateGripperCursor() 
        {
            if (_headerGripper != null && !_headerGripper.IsDragging) 
            {
                Cursor gripperCursor;

                if (DoubleUtil.IsZero(ActualWidth)) 
                {
                    gripperCursor = SplitOpenCursor; 
                } 
                else
                { 
                    gripperCursor = SplitCursor;
                }

                Debug.Assert(gripperCursor != null, "gripper cursor is null"); 
                if (gripperCursor != null)
                { 
                    _headerGripper.Cursor = gripperCursor; 
                }
            } 
        }

        // Set column header width and associated column width
        private void UpdateColumnHeaderWidth(double width) 
        {
            if (Column != null) 
            { 
                Column.Width = width;
            } 
            else
            {
                Width = width;
            } 
        }
 
        private bool IsMouseOutside() 
        {
            Point pos = Mouse.PrimaryDevice.GetPosition(this); 

            return !((pos.X >= 0) && (pos.X <= ActualWidth) && (pos.Y >= 0) && (pos.Y <= ActualHeight));
        }
 
        private void ClickImplement()
        { 
            if (AutomationPeer.ListenerExists(AutomationEvents.InvokePatternOnInvoked)) 
            {
                AutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this); 
                if (peer != null)
                    peer.RaiseAutomationEvent(AutomationEvents.InvokePatternOnInvoked);
            }
 
            base.OnClick();
        } 
 
        private bool GetFlag(Flags flag)
        { 
            return (_flags & flag) == flag;
        }

        private void SetFlag(Flags flag, bool set) 
        {
            if (set) 
            { 
                _flags |= flag;
            } 
            else
            {
                _flags &= (~flag);
            } 
        }
 
        // update the background visual brush 
        private void UpdateFloatingHeaderCanvas()
        { 
            if (_floatingHeaderCanvas != null
                && FloatSourceHeader != null)
            {
                // because the gripper is partially positioned out of the header, we need to 
                // map the appropriate area(viewbox) in the source header to visual brush
                // to avoid a distorded image on the floating header. 
                Vector offsetVector = VisualTreeHelper.GetOffset(FloatSourceHeader); 
                VisualBrush visualBrush = new VisualBrush(FloatSourceHeader);
 
                // set visual brush's mapping
                visualBrush.ViewboxUnits = BrushMappingMode.Absolute;
                visualBrush.Viewbox = new Rect(offsetVector.X, offsetVector.Y, FloatSourceHeader.ActualWidth, FloatSourceHeader.ActualHeight);
 
                _floatingHeaderCanvas.Background = visualBrush;
                FloatSourceHeader = null; 
            } 
        }
 
        /// 
        /// Handle IsMouseOverChanged when ClickMode is Hover
        /// 
        // Note: When ClickMode is Hover, ColumnHeader will be click when mouse is over it 
        // Here are 2 cases:
        // 1) Mouse is over column header 
        //    OnClick will be called 
        // 2) Mouse is over gripper
        //    OnClick won't be called, only when the mouse leaves the gripper and move to header, OnClick will be called. 
        private bool HandleIsMouseOverChanged()
        {
            if (ClickMode == ClickMode.Hover)
            { 
                if (IsMouseOver &&
                    //1) Gripper doesn't exist; 2) Gripper exists and Mouse isn't on Gripper; 
                    (_headerGripper == null || !_headerGripper.IsMouseOver)) 
                {
                    // Hovering over the button will click in the OnHover click mode 
                    SetValue(IsPressedPropertyKey, BooleanBoxes.Box(true));
                    OnClick();
                }
                else 
                {
                    ClearValue(IsPressedPropertyKey); 
                } 
                return true;
            } 
            return false;
        }

        // When mouse enters/leaves gripper, recall HandleIsMouseOverChanged to verify is mouse over header or not 
        private void OnGripperMouseEnterLeave(object sender, MouseEventArgs e)
        { 
            HandleIsMouseOverChanged(); 
        }
 
        #endregion Private Methods

        //-------------------------------------------------------------------
        // 
        //  Private Properties
        // 
        //------------------------------------------------------------------- 

        #region Private Properties 

        #region SplitCursor

        private Cursor SplitCursor 
        {
            get 
            { 
                if (_splitCursorCache == null)
                { 
                    _splitCursorCache = GetCursor(c_SPLIT);
                }
                return _splitCursorCache;
            } 
        }
 
        static private Cursor _splitCursorCache = null; 

        #endregion SplitCursor 

        #region SplitOpenCursor

        private Cursor SplitOpenCursor 
        {
            get 
            { 
                if (_splitOpenCursorCache == null)
                { 
                    _splitOpenCursorCache = GetCursor(c_SPLITOPEN);
                }
                return _splitOpenCursorCache;
            } 
        }
 
        static private Cursor _splitOpenCursorCache = null; 

        #endregion SplitOpenCursor 

        // is clicked by access key or automation
        private bool IsAccessKeyOrAutomation
        { 
            get { return GetFlag(Flags.IsAccessKeyOrAutomation); }
            set { SetFlag(Flags.IsAccessKeyOrAutomation, value); } 
        } 

        private double ColumnActualWidth 
        {
            get { return (Column != null ? Column.ActualWidth : ActualWidth); }
        }
 
        #endregion Private Properties
 
        //-------------------------------------------------------------------- 
        //
        //  Private Fields 
        //
        //-------------------------------------------------------------------

        #region Private Fields 

        ///  
        /// StyleSetByUser: the value of Style property is set by user. 
        /// IgnoreStyle: the OnStyleChanged is triggered by HeaderRowPresenter,
        /// not by user. Don't turn on the StyleSetByUser flag. 
        /// And so on
        /// (Only for user provided header. Ignored for internal generated header)
        ///
        /// Go to UpdateProperty and OnPropetyChanged for how these flags work. 
        /// 
        [Flags] 
        private enum Flags 
        {
            // IgnoreXXX can't be combined into one flag. 
            // Reason:
            // Define a Style with ContentTemplate and assign it to GridViewColumn.HeaderContainerStyle property. GridViewColumnHeader.OnPropertyChagned method will be called twice.
            // The first call is for ContentTemplate property. In this call, IgnoreContentTemplate is false.
            // The second call is for Style property. In this call, IgnoreStyle is true. 
            // One flag can’t distinguish them.
            None                                = 0, 
            StyleSetByUser                      = 0x00000001, 
            IgnoreStyle                         = 0x00000002,
            ContentTemplateSetByUser            = 0x00000004, 
            IgnoreContentTemplate               = 0x00000008,
            ContentTemplateSelectorSetByUser    = 0x00000010,
            IgnoreContentTemplateSelector       = 0x00000020,
            ContextMenuSetByUser                = 0x00000040, 
            IgnoreContextMenu                   = 0x00000080,
            ToolTipSetByUser                    = 0x00000100, 
            IgnoreToolTip                       = 0x00000200, 

            SuppressClickEvent                  = 0x00000400, 
            IsInternalGenerated                 = 0x00000800,
            IsAccessKeyOrAutomation             = 0x00001000,

            ContentStringFormatSetByUser        = 0x00002000, 
            IgnoreContentStringFormat           = 0x00004000,
        } 
 
        private Flags _flags;
 
        private Thumb _headerGripper;

        private double _originalWidth;
 
        // canvas for floating header
        private Canvas _floatingHeaderCanvas; 
 
        private GridViewColumnHeader _srcHeader;
 
        // cursor id in embedded win32 resource
        private const int c_SPLIT = 100;
        private const int c_SPLITOPEN = 101;
 
        // Part name used in the style. The class TemplatePartAttribute should use the same name
        private const string HeaderGripperTemplateName = "PART_HeaderGripper"; 
        private const string FloatingHeaderCanvasTemplateName = "PART_FloatingHeaderCanvas"; 

        #endregion Private Fields 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK