WindowsFormsHost.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Integration / System / Windows / Integration / WindowsFormsHost.cs / 2 / WindowsFormsHost.cs

                            using MS.Win32; 
using System.ComponentModel;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization; 
using System.Reflection;
using System.Runtime.InteropServices; 
using System.Security; 
using System.Security.Permissions;
using System.Windows.Interop; 
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Automation.Provider;
using System.Windows.Automation.Peers; 

using SD = System.Drawing; 
using SW = System.Windows; 
using SWC = System.Windows.Controls;
using SWF = System.Windows.Forms; 
using SWM = System.Windows.Media;
using SWI = System.Windows.Input;
using System.Collections.Generic;
using System.Windows.Input; 

namespace System.Windows.Forms.Integration 
{ 
    /// 
    ///     An element that allows you to host a Windows Forms control on a 
    ///     Windows Presentation Foundation page.
    /// 
    [System.ComponentModel.DesignerCategory("code")]
    [ContentProperty("Child")] 
    [DefaultEvent("ChildChanged")]
    public class WindowsFormsHost : HwndHost, IKeyboardInputSink 
    { 
        private SWM.Brush _cachedBackbrush;
 
        private HandleRef _hwndParent;
        private WinFormsAdapter _hostContainerInternal;

        #region Constructors 
        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
        static WindowsFormsHost() 
        { 
            //Keyboard tabbing support
            FocusableProperty.OverrideMetadata(typeof(WindowsFormsHost), new FrameworkPropertyMetadata(true)); 
            SWC.Control.IsTabStopProperty.OverrideMetadata(typeof(WindowsFormsHost), new FrameworkPropertyMetadata(true));
        }

        ///  
        /// Initializes a new instance of the WindowsFormsHost class.
        ///  
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
        public WindowsFormsHost()
            : base() 
        {
            this._hostContainerInternal = new WinFormsAdapter(this);

            _propertyMap = new WindowsFormsHostPropertyMap(this); 
        }
        #endregion 
 
        #region Focus
        ///  
        /// Notifies Avalon that focus has moved within this WindowsFormsHost.
        /// 
        void NotifyFocusWithinHost()
        { 
            DependencyObject focusScope = GetFocusScopeForElement(this);
            if (null != focusScope) 
            { System.Windows.Input.FocusManager.SetFocusedElement(focusScope, this); } 
        }
 
        /// 
        /// When implemented in a derived class, accesses the window process of the hosted child window.
        /// 
        ///  
        /// 
        ///  
        ///  
        /// 
        ///  
        protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            { 
                case NativeMethods.WM_CHILDACTIVATE:
                    _hostContainerInternal.HandleChildActivate(); 
                    break; 
                case NativeMethods.WM_SETFOCUS:
                case NativeMethods.WM_MOUSEACTIVATE: 
                    NotifyFocusWithinHost();
                    break;
                case NativeMethods.WM_GETOBJECT:
                    handled = true; 
                    return OnWmGetObject(wParam, lParam);
            } 
            return base.WndProc(hwnd, msg, wParam, lParam, ref handled); 
        }
 

        /// 
        ///     Critical    - Calls critical HwndHost.Handle.
        ///     TreatAsSafe - This demands full trust, so it's safe 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] 
        private IntPtr OnWmGetObject(IntPtr wparam, IntPtr lparam)
        { 
            IntPtr result = IntPtr.Zero;

            WindowsFormsHostAutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this) as WindowsFormsHostAutomationPeer;
            if(peer != null) 
            {
                // get the element proxy 
                IRawElementProviderSimple el = peer.GetProvider(); 

                //This requires FullTrust but we already have it. 
                result = AutomationInteropProvider.ReturnRawElementProvider(Handle, wparam, lparam, el);
            }
            return result;
        } 

        private static DependencyObject GetFocusScopeForElement(DependencyObject element) 
        { 
            //Walk up the visual tree until we find an element that is a focus scope (or we run out of elements).
            //This will usually be the root Avalon Window. 
            while (null != element && !FocusManager.GetIsFocusScope(element))
            { element = VisualTreeHelper.GetParent(element); }
            return element;
        } 

        #endregion 
 
        #region Layout
 
        private Vector _currentScale = new Vector(1.0, 1.0);

        /// 
        ///     Scales the hosted Windows Forms control, and tracks the scale factor. 
        /// 
        ///  
        /// The new scale factor 
        protected virtual Vector ScaleChild(Vector newScale)
        { 
            if (newScale != _currentScale)
            {
                if (Child != null)
                { 
                    Child.Scale(new System.Drawing.SizeF((float)(newScale.X / _currentScale.X), (float)(newScale.Y / _currentScale.Y)));
                } 
            } 
            return newScale;
        } 

        private void ScaleChild()
        {
            bool skewed; 
            Vector newScale = HostUtils.GetScale(this, out skewed);
            if (skewed) 
            { 
                OnLayoutError();
            } 
            _currentScale = ScaleChild(newScale);
        }

        private event EventHandler _layoutError; 
        /// 
        /// Occurs when a layout error, such as a skew or rotation that WindowsFormsHost does not support, 
        /// is encountered. 
        /// 
        public event EventHandler LayoutError 
        {
            add { _layoutError += value; }
            remove { _layoutError -= value; }
        } 

        private void OnLayoutError() 
        { 
            InvalidOperationException exception = new InvalidOperationException(SR.Get(SRID.Host_CannotRotateWindowsFormsHost));
            LayoutExceptionEventArgs args = new LayoutExceptionEventArgs(exception); 
            if (_layoutError != null)
            {
                _layoutError(this, args);
            } 
            if (args.ThrowException)
            { 
                throw exception; 
            }
        } 

        /// 
        ///     Overrides the base class implementation of MeasureOverride to measure
        ///     the size of a WindowsFormsHost object and return the proper size to the layout engine. 
        /// 
        protected override SW.Size MeasureOverride(SW.Size constraint) 
        { 
            if (this.Visibility == Visibility.Collapsed || Child == null)
            { 
                //Child takes up no space
                return new Size(0, 0);
            }
 
            ScaleChild();
 
            SD.Size constraintSize = Convert.ConstraintToSystemDrawingSize(constraint, _currentScale); 
            SD.Size preferredSize = Child.GetPreferredSize(constraintSize);
 
            System.Windows.Size returnSize = Convert.ToSystemWindowsSize(preferredSize, _currentScale);

            // Apply constraints to the preferred size
            returnSize.Width = Math.Min(returnSize.Width, constraint.Width); 
            returnSize.Height = Math.Min(returnSize.Height, constraint.Height);
 
            return returnSize; 
        }
 
        // Note: the WPF layout engine may call ArrangeOverride multiple times in succession
        private Size _priorConstraint;

        ///  
        ///     When implemented in a derived class, positions child elements and determines a
        ///     size for a FrameworkElement-derived class. 
        ///  
        /// 
        ///  
        protected override Size ArrangeOverride(Size finalSize)
        {
            if (this.Visibility == Visibility.Collapsed || Child == null)
            { 
                //Child takes up no space
                return new Size(0, 0); 
            } 

            Vector originalScale = _currentScale; 
            ScaleChild();
            bool scaled = (_currentScale != originalScale);

            SD.Size targetSize = Convert.ConstraintToSystemDrawingSize(finalSize, _currentScale); 
            if ((Child.Size != targetSize) && ((finalSize != _priorConstraint) || scaled))
            { 
                _priorConstraint = finalSize; 
                Child.Size = targetSize;
            } 
            Size returnSize = Convert.ToSystemWindowsSize(Child.Size, _currentScale);
            returnSize.Width = Math.Min(returnSize.Width, finalSize.Width);
            returnSize.Height = Math.Min(returnSize.Height, finalSize.Height);
            if (HostContainerInternal.BackgroundImage != null) 
            {
                _propertyMap.OnPropertyChanged(this, "Background", this.Background); 
            } 
            return returnSize;
        } 
        #endregion Layout

        #region Containership
 
        /// 
        /// Occurs when the Child property is set. 
        ///  
        public event EventHandler ChildChanged;
 
        /// 
        ///     Gets or sets the child control hosted by the WindowsFormsHost element.
        /// 
        public Control Child 
        {
            get 
            { 
                return _hostContainerInternal.Child;
            } 
            set
            {
#pragma warning disable 1634, 1691
#pragma warning disable 56526 
                Control oldChild = Child;
                SWF.Form form = value as SWF.Form; 
                if (form != null) 
                {
                    if (form.TopLevel) 
                    {  //WinOS #1030878 - Can't host top-level forms
                        throw new ArgumentException(SR.Get(SRID.Host_ChildCantBeTopLevelForm));
                    }
                    else 
                    {
                        form.ControlBox = false; 
                    } 
                }
                _hostContainerInternal.Child = value; 
                if (Child != null)
                {
                    _propertyMap.ApplyAll();
 
                    Child.Margin = SWF.Padding.Empty;
                    Child.Dock = DockStyle.None; 
                    Child.AutoSize = false; 
                    Child.Location = SD.Point.Empty;
                    // clear the cached size 
                    _priorConstraint = new Size(double.NaN, double.NaN);
                }
                OnChildChanged(oldChild);
#pragma warning restore 1634, 1691, 56526 
            }
        } 
 
        private void OnChildChanged(Control oldChild)
        { 
            if (ChildChanged != null)
            {
                ChildChanged(this, new ChildChangedEventArgs(oldChild));
            } 
        }
 
        internal WinFormsAdapter HostContainerInternal 
        {
            get 
            {
                return _hostContainerInternal;
            }
        } 

        #endregion Containership 
 
        #region Rendering
 
        static Brush defaultBrush = SystemColors.WindowBrush;
        /// 
        ///     Manually searches up the parent tree to find the first FrameworkElement that
        ///     has a non-null background, and returns that Brush. 
        ///     If no parent is found with a brush, then this returns WindowBrush.
        ///  
        ///  
        /// 
        private static SWM.Brush FindBackgroundParent(SW.DependencyObject dependencyObject) 
        {
            if (dependencyObject == null)
            {
                return defaultBrush; 
            }
 
            Brush backgroundBrush = null; 
            backgroundBrush = (Brush)dependencyObject.GetValue(SWC.Control.BackgroundProperty);
 
            if (backgroundBrush == null)
            {
                SW.FrameworkElement frameworkElement = dependencyObject as SW.FrameworkElement;
                if (frameworkElement != null) 
                {
                    DependencyObject parentElement = VisualTreeHelper.GetParent(frameworkElement); 
                    backgroundBrush = FindBackgroundParent(parentElement); 
                }
            } 

            return backgroundBrush ?? defaultBrush;
        }
 

        ///  
        ///     This is called by the OnPaintBackground method of the host container. 
        /// 
        internal void PaintBackground() 
        {
            SWM.Brush parentBrush = FindBackgroundParent(this);
            if (parentBrush != null)
            { 
                if (_cachedBackbrush != parentBrush)
                { 
                    _cachedBackbrush = parentBrush; 
                    _propertyMap.OnPropertyChanged(this, "Background", parentBrush);
                } 
            }
        }

        #endregion Rendering 

        #region Keyboarding 
 
        /// 
        ///     Enables Windows Forms forms to function correctly when opened modelessly from 
        ///     Windows Presentation Foundation.
        /// 
        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public static void EnableWindowsFormsInterop() 
        {
            ApplicationInterop.EnableWindowsFormsInterop(); 
        } 

        ///  
        ///     Forwards focus from Windows Presentation Foundation to the hosted Windows Forms control.
        /// 
        public virtual bool TabInto(SWI.TraversalRequest request)
        { 
            return HostContainerInternal.FocusNext(request);
        } 
 
        #endregion Keyboarding
 
        #region Activation
        private Control _focusedChild;
        private void RestoreFocusedChild()
        { 
            _hostContainerInternal.Focus();
            _hostContainerInternal.ActiveControl = _focusedChild; 
            _focusedChild = null; 
        }
        private void NotifyActivateApp(ref Message m) 
        {
            if (m.WParam != IntPtr.Zero)
            {
                if (null != _focusedChild) 
                { _hostContainerInternal.BeginInvoke(new MethodInvoker(RestoreFocusedChild)); }
            } 
            else 
            {
                IntPtr currentFocus = UnsafeNativeMethods.GetFocus(); 
                if (currentFocus == Handle || UnsafeNativeMethods.IsChild(Handle, currentFocus))
                { _focusedChild = _hostContainerInternal.ActiveControl; }
            }
        } 
        private ActivateWindowListener _activateWindowListener;
        private class ActivateWindowListener : NativeWindow, IDisposable 
        { 
            WindowsFormsHost _host;
            public ActivateWindowListener(WindowsFormsHost host) 
            { _host = host; }
            protected override void WndProc(ref Message m)
            {
                if (NativeMethods.WM_ACTIVATEAPP == m.Msg) 
                { _host.NotifyActivateApp(ref m); }
                base.WndProc(ref m); 
            } 
            public void Dispose()
            { this.ReleaseHandle(); } 
        }
        #endregion

        #region Window Handling & Misc 
        /// 
        ///     Overrides the base class implementation of BuildWindowCore to build the hosted 
        ///     Windows Forms control. 
        /// 
        protected override HandleRef BuildWindowCore(HandleRef hwndParent) 
        {
            this.Loaded += new RoutedEventHandler(ApplyAllProperties);

            Debug.WriteLineIf(_traceHandle.TraceVerbose, String.Format(CultureInfo.CurrentCulture, "WindowsFormsHost({0}): BuildWindowCore (parent=0x{1:x8})", this.Name, hwndParent.Handle.ToInt32())); 
            if (_activateWindowListener != null)
            { 
                _activateWindowListener.Dispose(); 
            }
            _activateWindowListener = new ActivateWindowListener(this); 
            _activateWindowListener.AssignHandle(hwndParent.Handle);
            _hwndParent = hwndParent;
            //For Keyboard interop
            ApplicationInterop.ThreadWindowsFormsHostList.Add(this);    //Keep track of this control, so it can get forwarded windows messages 
            EnableWindowsFormsInterop();        //Start the forwarding of windows messages to all WFH controls on active windows
 
            UnsafeNativeMethods.SetParent(/* child = */ HostContainerInternal.Handle, /* parent = */ _hwndParent.Handle); 
            return new HandleRef(HostContainerInternal, HostContainerInternal.Handle);
        } 

        /// 
        ///     Overrides the base class implementation of DestroyWindowCore to delete the
        ///     window containing this object. 
        /// 
        protected override void DestroyWindowCore(HandleRef hwnd) 
        { 
            //For keyboard interop (remove this control from the list)
            //This line shouldn't be necessary since the list cleans itself, but it's good to be tidy. 
            ApplicationInterop.ThreadWindowsFormsHostList.Remove(this);

            if (HostContainerInternal != null)
            { 
                HostContainerInternal.Dispose();
            } 
        } 

        void ApplyAllProperties(object sender, RoutedEventArgs e) 
        {
            _propertyMap.ApplyAll();
        }
 
        /// 
        ///     Releases all resources used by the WindowsFormsHost element. 
        ///  
        protected override void Dispose(bool disposing)
        { 
            try
            {
                base.Dispose(disposing);
            } 
            finally
            { 
                if (disposing) 
                {
                    if (_hostContainerInternal != null) 
                    {
                        try
                        {
                            if (_activateWindowListener != null) 
                            {
                                _activateWindowListener.Dispose(); 
                            } 
                            _hostContainerInternal.Dispose();
                            this.Loaded -= new RoutedEventHandler(ApplyAllProperties); 
                        }
                        finally
                        {
                            if (Child != null) 
                            {
                                Child.Dispose(); 
                            } 
                        }
                    } 
                }
            }
        }
        #endregion Window Handling & Misc 

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

        #region Property Mapping 

        //Some of the properties that we would like to map don't exist on HwndHost,
        //so we add them here: TabIndex, Font (4x), Foreground, Background, Padding.
 
        /// 
        ///     Identifies the Padding dependency property. 
        ///  
        public static readonly DependencyProperty PaddingProperty =
                SWC.Control.PaddingProperty.AddOwner(typeof(WindowsFormsHost)); 

        /// 
        /// Specifies the size of the desired padding within the hosted Windows Forms control.
        ///  
        [Bindable(true), Category("Behavior")]
        public Thickness Padding 
        { 
            get { return (Thickness)GetValue(PaddingProperty); }
            set { SetValue(PaddingProperty, value); } 
        }

        /// 
        ///     Identifies the TabIndex dependency property. 
        /// 
        public static readonly DependencyProperty TabIndexProperty = 
                SWC.Control.TabIndexProperty.AddOwner(typeof(WindowsFormsHost)); 

        ///  
        ///     Gets or sets the hosted control's tab index.
        /// 
        [Bindable(true), Category("Behavior")]
        public int TabIndex 
        {
            get { return (int)GetValue(TabIndexProperty); } 
            set { SetValue(TabIndexProperty, value); } 
        }
 
        /// 
        ///     Identifies the FontFamily dependency property.
        /// 
        public static readonly DependencyProperty FontFamilyProperty = 
            SWC.Control.FontFamilyProperty.AddOwner(typeof(WindowsFormsHost));
 
        ///  
        ///     Gets or sets the hosted control's font family as an ambient property.
        ///  
        public SWM.FontFamily FontFamily
        {
            get { return (SWM.FontFamily)GetValue(FontFamilyProperty); }
            set { SetValue(FontFamilyProperty, value); } 
        }
 
        ///  
        ///     Identifies the FontSize dependency property.
        ///  
        public static readonly DependencyProperty FontSizeProperty =
            SWC.Control.FontSizeProperty.AddOwner(typeof(WindowsFormsHost));

        ///  
        ///     Gets or sets the hosted control's font size as an ambient property.
        ///  
        public double FontSize 
        {
            get { return (double)GetValue(FontSizeProperty); } 
            set { SetValue(FontSizeProperty, value); }
        }

        ///  
        ///     Identifies the FontStyle dependency property.
        ///  
        public static readonly DependencyProperty FontStyleProperty = 
            SWC.Control.FontStyleProperty.AddOwner(typeof(WindowsFormsHost));
 
        /// 
        ///     Gets or sets the hosted control's font style as an ambient proeprty.
        /// 
        public SW.FontStyle FontStyle 
        {
            get { return (FontStyle)GetValue(FontStyleProperty); } 
            set { SetValue(FontStyleProperty, value); } 
        }
 
        /// 
        ///     Identifies the FontWeight dependency property.
        /// 
        public static readonly DependencyProperty FontWeightProperty = 
            SWC.Control.FontWeightProperty.AddOwner(typeof(WindowsFormsHost));
 
        ///  
        ///     Gets or sets the hosted control's font weight as an ambient property.
        ///  
        public SW.FontWeight FontWeight
        {
            get { return (FontWeight)GetValue(FontWeightProperty); }
            set { SetValue(FontWeightProperty, value); } 
        }
 
        ///  
        ///     Identifies the Foreground dependency property.
        ///  
        public static readonly DependencyProperty ForegroundProperty =
            SWC.Control.ForegroundProperty.AddOwner(typeof(WindowsFormsHost));

 
        ///
        ///     Gets or sets the hosted control's foreground color as an ambient property. 
        /// 
        public Brush Foreground
        { 
            get { return (Brush)GetValue(ForegroundProperty); }
            set { SetValue(ForegroundProperty, value); }
        }
 
        /// 
        ///     Identifies the Background dependency property. 
        ///  
        public static readonly DependencyProperty BackgroundProperty =
            SWC.Control.BackgroundProperty.AddOwner(typeof(WindowsFormsHost)); 

        /// 
        ///     Gets or sets the hosted control's background as an ambient property.
        ///  
        public Brush Background
        { 
            get { return (Brush)GetValue(BackgroundProperty); } 
            set { SetValue(BackgroundProperty, value); }
        } 

        /// 
        ///     Forces the translation of a mapped property.
        ///  
        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        { 
            base.OnPropertyChanged(e); 

            // Invoke method currently set to handle this event 
            if (_propertyMap != null)
            {
                _propertyMap.OnPropertyChanged(this, e.Property.Name, e.NewValue);
            } 
        }
 
        ///  
        ///     Gets the property map that determines how setting properties on the
        ///     WindowsFormsHost element affects the hosted Windows Forms control. 
        /// 
        public PropertyMap PropertyMap
        {
            get { return _propertyMap; } 
        }
        private PropertyMap _propertyMap; 
 
        #endregion Property Mapping
 
        #region DEBUG
#if DEBUG
        internal static readonly TraceSwitch _traceHandle = new TraceSwitch("WindowsFormsHostHandle", "Tracks WindowsFormsHost handle information.");
        internal static readonly TraceSwitch _traceLayout = new TraceSwitch("WindowsFormsHostLayout", "Tracks WindowsFormsHost layout information."); 
#else
        internal static readonly TraceSwitch _traceHandle = null; 
        internal static readonly TraceSwitch _traceLayout = null; 
#endif
        #endregion DEBUG 
    }


 
    #region WinFormsAdapter
    [System.ComponentModel.DesignerCategory("code")] 
    internal class WinFormsAdapter : SWF.ContainerControl 
    {
        private WindowsFormsHost _host; 
        private FocusTargetControl _focusTarget;
        private IntPtr _prevFocusHwnd = IntPtr.Zero;

        private Control _child; 
        public Control Child
        { 
            get { return _child; } 
            set
            { 
                if (null != Child)
                { Controls.Remove(Child); }

                if (null != value) 
                { Controls.Add(value); }
 
                _child = value; 
            }
        } 

        private bool IsParked
        {
            get { return ActiveControl == _focusTarget; } 
        }
 
        Control _controlBeforePark; 
        public void HandleChildActivate()
        { 
            IntPtr focusHwnd = UnsafeNativeMethods.GetFocus();
            try
            {
                if (IntPtr.Zero == _prevFocusHwnd ) { return; } 

                //If nothing's focused, but Avalon thinks we should have focus, give us focus. 
                if (IntPtr.Zero == focusHwnd && _host.IsFocused) 
                {
                    this.BeginInvoke(new MethodInvoker(RestoreFocus)); 
                    return;
                }

                //If focus is changing from a child of the WinFormsAdapter to something outside 
                //we will activate the a temporary control to cause leave and validation events
                if ( 
                    _focusTarget.Handle != _prevFocusHwnd && 
                    UnsafeNativeMethods.IsChild(Handle, _prevFocusHwnd) &&
                    !UnsafeNativeMethods.IsChild(Handle, focusHwnd)) 
                {
                    _controlBeforePark = this.ActiveControl;
                    this.ActiveControl = _focusTarget;
                } 
            }
            finally 
            { _prevFocusHwnd = focusHwnd; } 
        }
 
        private void RestoreFocus()
        {
            this.Focus();
            if (IsParked) 
            { ActiveControl = _controlBeforePark; }
        } 
 
        //Note: there's no notification when the ambient cursor changes, so we
        //can't do a normal mapping for this and have it work.  We work around 
        //this by overriding WinFormsAdapter.Cursor and walking the visual tree
        //to find the cursor IF the Cursor translator has not been changed.
        //host.PropertyMap["Cursor"] += delegate {MessageBox.Show("?");};
        //will cause the mapping to no longer happen. 
        public override Cursor Cursor
        { 
            get 
            {
                if (_host == null) { return base.Cursor; } 

                if (!_host.PropertyMap.PropertyMappedToEmptyTranslator("Cursor"))
                { return base.Cursor; }
 
                bool forceCursorMapped = _host.PropertyMap.PropertyMappedToEmptyTranslator("ForceCursor");
 
                FrameworkElement cursorSource = HostUtils.GetCursorSource(_host, forceCursorMapped); 
                if (cursorSource == null) { return base.Cursor; }
 
                return Convert.ToSystemWindowsFormsCursor(cursorSource.Cursor);
            }
            set
            { 
                base.Cursor = value;
            } 
        } 

        private class FocusTargetControl : Control 
        {
            public FocusTargetControl()
            {
                this.Size = SD.Size.Empty; 
                //Hide it as far away as possible
                this.Location = new SD.Point(short.MinValue, short.MinValue); 
                this.TabStop = false; 
#if DEBUG
                this.Name = "Focus target"; 
#endif //DEBUG
            }

        } 

        public WinFormsAdapter(WindowsFormsHost host) 
        { 
            _host = host;
            _focusTarget = new FocusTargetControl(); 
            Controls.Add(_focusTarget);
            this.HandleCreated += WinFormsAdapter_HandleCreated;

            //Keyboard interop: We listen to this event to refresh the visual cues (workaround) 
            SWI.InputManager.Current.PostProcessInput += InputManager_PostProcessInput;
        } 
 
        protected override void Dispose(bool disposing)
        { 
            try
            {
                if (disposing)
                { 
                    SWI.InputManager.Current.PostProcessInput -= InputManager_PostProcessInput;
                } 
            } 
            finally
            { 
                base.Dispose(disposing);
            }
        }
        #region Keyboard Interop 
        /// 
        ///     Forwards focus from Avalon and into the WinForms "sink". 
        ///     The request is often First and Last, which isn't really mapped the 
        ///     same way, but it seems to work, probably because we only host one control.
        ///  
        /// 
        /// 
        internal bool FocusNext(SWI.TraversalRequest request)
        { 
            UpdateUIState(NativeMethods.UIS_INITIALIZE);
            bool forward = true; 
            bool tabStopOnly = true; 
            switch (request.FocusNavigationDirection)
            { 
                case System.Windows.Input.FocusNavigationDirection.Down:
                case System.Windows.Input.FocusNavigationDirection.Right:
                    forward = true;
                    tabStopOnly = false; 
                    break;
                case System.Windows.Input.FocusNavigationDirection.Next: 
                case System.Windows.Input.FocusNavigationDirection.First: 
                    forward = true;
                    tabStopOnly = true; 
                    break;
                case System.Windows.Input.FocusNavigationDirection.Up:
                case System.Windows.Input.FocusNavigationDirection.Left:
                    forward = false; 
                    tabStopOnly = false;
                    break; 
                case System.Windows.Input.FocusNavigationDirection.Previous: 
                case System.Windows.Input.FocusNavigationDirection.Last:
                    forward = false; 
                    tabStopOnly = true;
                    break;
                default:
                    Debug.Assert(false, "Unknown FocusNavigationDirection"); 
                    break;
            } 
            _focusTarget.Enabled = false; 
            try
            { 
                if (this.SelectNextControl(null, forward, tabStopOnly, true, false))
                {
                    // find the inner most active control
                    ContainerControl ret = this; 
                    while (ret.ActiveControl is ContainerControl)
                    { 
                        ret = (ContainerControl)ret.ActiveControl; 
                    }
                    if (!ret.ContainsFocus) 
                    { ret.Focus(); }
                    return true;
                }
                return false; 
            }
            finally 
            { _focusTarget.Enabled = true; } 
        }
        //  CSS added for keyboard interop 
        protected override bool ProcessDialogKey(Keys keyData)
        {
            _focusTarget.Enabled = false;
            try 
            {
                if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None) 
                { 
                    Keys keyCode = (Keys)keyData & Keys.KeyCode;
                    if (keyCode == Keys.Tab || keyCode == Keys.Left || 
                        keyCode == Keys.Right || keyCode == Keys.Up ||
                        keyCode == Keys.Down)
                    {
                        if (this.Focused || this.ContainsFocus) 
                        {
                            // CSS:  In WF apps, by default, arrow keys always wrap within a container 
                            // However, we don't want them to wrap in the Adapter, which always has only 
                            // one immediate child
                            if ((keyCode == Keys.Left || keyCode == Keys.Right || keyCode == Keys.Down || keyCode == Keys.Up) 
                                && (this.ActiveControl != null && this.ActiveControl.Parent == this))
                            {
                                SWF.Control c = this.ActiveControl.Parent;
                                return c.SelectNextControl(this.ActiveControl, keyCode == Keys.Right || keyCode == Keys.Down, false, false, false); 
                            }
                            else 
                                return base.ProcessDialogKey(keyData); 
                        }
                    } 
                }
                return false;
            }
            finally { _focusTarget.Enabled = true; } 
        }
 
        //  CSS added for keyboard interop 
        internal bool PreProcessMessage(ref Message msg, bool hasFocus)
        { 
            // Don't steal WM_CHAR messages from Avalon, Catch them later in InputManager_PostProcessInput
            if (!hasFocus && msg.Msg == NativeMethods.WM_CHAR)
            {
                return false; 
            }
            return PreProcessMessage(ref msg); 
        } 

        ///  
        ///     For keyboard interop, when this handle is recreated, the current state of the
        ///     visual shortcut key cues (AKA underlining the hotkey) is lost, so it needs
        ///     to be refreshed.
        ///  
        /// 
        ///  
        private void WinFormsAdapter_HandleCreated(object sender, EventArgs e) 
        {
            //CSS - Workaround OS bug.  The initial UI state was being set erratically 
            // (sometimes cues were shown, sometimes not.  This forces it to a known state.
            UpdateUIState(NativeMethods.UIS_SET);
        }
 
        /// 
        ///     For keyboard interop 
        ///     Ensure the visual shortcut key cues on controls are in the same visual 
        ///     state that we expect. This is a workaround for odd Windows API.
        ///  
        internal void UpdateUIState(int uiAction)
        {
            Debug.Assert(uiAction == NativeMethods.UIS_INITIALIZE || uiAction == NativeMethods.UIS_SET, "Unexpected uiAction");
            int toSet = NativeMethods.UISF_HIDEACCEL | NativeMethods.UISF_HIDEFOCUS; 
            if (UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle),
                 NativeMethods.WM_UPDATEUISTATE, 
                 (IntPtr)(uiAction | (toSet << 16)), 
                 IntPtr.Zero) != IntPtr.Zero)
            { 
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
 
        // CSS Added for keyboard interop
        // Catch WM_CHAR messages which weren't handled by Avalon 
        //  (including mnemonics which were typed without the "Alt" key) 
        private void InputManager_PostProcessInput(object sender, SWI.ProcessInputEventArgs e)
        { 
            // Should return immediately if this WFH is not in the active Window
            PresentationSource presentationSource = PresentationSource.FromVisual(this._host);
            if (presentationSource == null)
            { 
                return;
            } 
            Window presentationSourceWindow = presentationSource.RootVisual as Window; 

            //CSS This active window check may not work for multiple levels of nesting... 
            // RootVisual isn't top level window.  Should we traverse upward through nested levels?
            if (presentationSourceWindow == null || !presentationSourceWindow.IsActive)
                return;
 
            // Now check for unhandled WM_CHAR messages and process them as mnemonics
            if (!e.StagingItem.Input.Handled && e.StagingItem.Input.RoutedEvent == SWI.TextCompositionManager.TextInputEvent) 
            { 
                SWI.TextCompositionEventArgs te = (SWI.TextCompositionEventArgs)e.StagingItem.Input;
                string text = te.Text; 
                if (string.IsNullOrEmpty(text))
                {
                    text = te.SystemText;
                } 
                if (!string.IsNullOrEmpty(text))
                { 
                    e.StagingItem.Input.Handled = this.ProcessDialogChar(text[0]); 
                }
            } 
        }

        #endregion Keyboard Interop
 
        /// 
        ///     Overridden to invalidate host layout when our layout changes. 
        ///  
        protected override void OnLayout(SWF.LayoutEventArgs e)
        { 
            base.OnLayout(e);
            _host.InvalidateMeasure();

#if DEBUG 
            string compName = "";
            if (e.AffectedControl != null) 
            { 
                compName = e.AffectedControl.Name;
            } 
            else if (e.AffectedComponent != null)
            {
                compName = e.AffectedComponent.ToString();
            } 
            Debug.WriteLineIf(WindowsFormsHost._traceLayout.TraceInfo, String.Format(CultureInfo.CurrentCulture, "WindowsFormsHost({0}): Layout invalidated (control='{1}',property='{2}')", _host.Name, compName, e.AffectedProperty));
#endif 
        } 

        ///  
        ///     Forward the Host Containers paint events to the WFH, so that it can either
        ///     use a bitmap to do "fake" transparency or set the BackColor correctly.
        /// 
        protected override void OnPaintBackground(SWF.PaintEventArgs e) 
        {
            _host.PaintBackground(); 
            base.OnPaintBackground(e); 
        }
 
        //Changing RightToLeft on the WinFormsAdapter recreates the handle. Since our
        //handle is being cached, this causes problems.  The handle gets recreated when
        //RightToLeft changes.  To avoid changing our handle, we can override the
        //RightToLeft property, and notify our child when the property changes. 
        private RightToLeft _rightToLeft = RightToLeft.Inherit;
        ///  
        /// Gets or sets a value indicating whether control's elements are aligned 
        /// to support locales using right-to-left fonts.
        ///  
        public override RightToLeft RightToLeft
        {
            get
            { 
                //Return the same default value as Control does (No)
                return _rightToLeft == RightToLeft.Inherit ? 
                    RightToLeft.No : _rightToLeft; 
            }
            set 
            {
                if (_rightToLeft != value)
                {
                    //If RightToLeft is Inherit and we're setting to the "default" value, don't call OnRTLChanged. 
                    bool fireRightToLeftChanged = _rightToLeft != RightToLeft.Inherit || base.RightToLeft != value;
                    _rightToLeft = value; 
                    if (fireRightToLeftChanged) 
                    {
                        OnRightToLeftChanged(EventArgs.Empty); 
                    }
                }
            }
        } 

        ///  
        /// Override OnRightToLeftChanged as noted above 
        /// 
        ///  
        protected override void OnRightToLeftChanged(EventArgs e)
        {
            if (null != Child)
            { 
                CallOnParentRightToLeftChanged(Child);
            } 
        } 

        //Use reflection to call protected OnParentRightToLeftChanged 
        private void CallOnParentRightToLeftChanged(Control control)
        {
            MethodInfo methodInfo = typeof(SWF.Control).GetMethod("OnParentRightToLeftChanged", BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(EventArgs) }, null);
            Debug.Assert(methodInfo != null, "Couldn't find OnParentRightToLeftChanged method!"); 
            if (methodInfo != null)
            { 
                methodInfo.Invoke(control, new object[] { EventArgs.Empty }); 
            }
        } 
    }
    #endregion WinFormsAdapter
}

// 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