File: System\Windows\Integration\ElementHost.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\WindowsFormsIntegration\WindowsFormsIntegration.csproj (WindowsFormsIntegration)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
        
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Windows.Documents;
using System.Windows.Interop;
using System.Windows.Markup;
using System.Windows.Media;
using System.Security;
using MS.Win32;
using MS.Internal;
using System.Runtime.Versioning;
using System.Windows.Input;
 
using SD = System.Drawing;
using SWF = System.Windows.Forms;
 
using SW = System.Windows;
using SWC = System.Windows.Controls;
using SWM = System.Windows.Media;
using SWMI = System.Windows.Media.Imaging;
using SWI = System.Windows.Input;
using SWT = System.Windows.Threading;
 
using NativeMethodsSetLastError = MS.Internal.WinFormsIntegration.NativeMethodsSetLastError;
 
namespace System.Windows.Forms.Integration
{
    /// <summary>
    ///     A Windows Forms control that can be used to host a Windows Presentation
    ///     Foundation element.
    /// </summary>
    [System.ComponentModel.DesignerCategory("code")]
    [ContentProperty("Child")]
    [DefaultEvent("ChildChanged")]
    [Designer("WindowsFormsIntegration.Design.ElementHostDesigner, WindowsFormsIntegration.Design, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    [DesignerSerializer("WindowsFormsIntegration.Design.ElementHostCodeDomSerializer, WindowsFormsIntegration.Design, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
                    "System.ComponentModel.Design.Serialization.CodeDomSerializer, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
    public class ElementHost : Control
    {
        private HwndSource _hwndSource;
        /// <summary>
        /// The decorator is used to provide an Adorner layer which is needed to show UI highlights
        /// for focus etc.  In the pure-Avalon case, this would be handled by Window
        /// </summary>
        private AdornerDecorator _decorator;
        private AvalonAdapter _hostContainerInternal;
        private bool _backColorTransparent;
        private SW.UIElement _child;
 
        private bool _processingWmInputLangChanged;  // Flag to prevent re-entrancy when processing WM_INPUTLANGCHANGED
 
        #region Constructors
        /// <summary>
        ///     Initializes a new instance of the ElementHost class.
        /// </summary>
        /// <internalonly>
        ///     Overridden to plug the Avalon control into WinForm's layout engines.
        /// </internalonly>
        public ElementHost()
            : base()
        {
            this._hostContainerInternal = new AvalonAdapter(this);
            this._decorator = new AdornerDecorator();
            _decorator.Child = this._hostContainerInternal;
 
            SetStyle(SWF.ControlStyles.SupportsTransparentBackColor, true);
            SetStyle(SWF.ControlStyles.UserPaint, true);
            SetStyle(SWF.ControlStyles.AllPaintingInWmPaint, true);
 
            System.Windows.Input.FocusManager.SetIsFocusScope(this._decorator, true);
            //For keyboarding, this listens for WM_CHAR events not handled, so that mnemonics
            //that are pressed without the ALT key can be handled.
            SWI.InputManager.Current.PostProcessInput += InputManager_PostProcessInput;
 
            this.SetAutoSizeMode(AutoSizeMode.GrowAndShrink);
            StartPropertyMapping();
            SizeChanged += new EventHandler(CallUpdateBackground);
            LocationChanged += new EventHandler(CallUpdateBackground);
        }
        #endregion
 
        #region Layout
 
        /// <internalonly>
        ///     Overrides the base class implementation of GetPreferredSize to provide
        ///     correct layout behavior for the hosted Windows Presentation Foundation elements.
        /// </internalonly>
        public override SD.Size GetPreferredSize(SD.Size proposedSize)
        {
            if (Disposing)
            {
                return base.GetPreferredSize(proposedSize);
            }
 
            proposedSize = HostUtils.IntersectSizes(HostUtils.ConvertZeroOrOneToUnbounded(proposedSize), HostUtils.ConvertZeroToUnbounded(MaximumSize));
            proposedSize = HostUtils.UnionSizes(proposedSize, MinimumSize);
 
            // Apply the child's scaling, if any
            Vector scale = (Child == null ? new Vector(1d, 1d) : HostUtils.GetScale(Child));
 
            Size constraints = Convert.ToSystemWindowsSize(proposedSize, scale);
 
            // At this point, an unbounded value is represented by Int32.MaxValue: WPF wants double.PositiveInfinity.
            if (constraints.Width == Int32.MaxValue) { constraints.Width = Double.PositiveInfinity; }
            if (constraints.Height == Int32.MaxValue) { constraints.Height = Double.PositiveInfinity; }
 
            // Request that control recompute desired size with new constraints.
            _decorator.Measure(constraints);
            SD.Size prefSize = Convert.ToSystemDrawingSize(_decorator.DesiredSize, scale);
 
            // WindowsForms guarantees results will be bounded by control Min/MaxSize
            prefSize = HostUtils.IntersectSizes(prefSize, HostUtils.ConvertZeroToUnbounded(MaximumSize));
            prefSize = HostUtils.UnionSizes(prefSize, MinimumSize);
 
            Debug.WriteLineIf(_traceLayout.TraceInfo, String.Format(CultureInfo.CurrentCulture, "AvalonAdapter({0}): MeasureOverride (constraint={1},result={2})", this.Name, proposedSize, prefSize));
            return prefSize;
        }
 
        /// <summary>
        ///     Gets the default size of the control.
        /// </summary>
        protected override System.Drawing.Size DefaultSize
        {
            get
            {
                return new SD.Size(200, 100);
            }
        }
 
        /// <summary>
        ///     Gets or sets a value indicating whether the control is
        ///     automatically resized to display its entire contents.
        /// </summary>
        [Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
        public override bool AutoSize
        {
            get
            {
                return base.AutoSize;
            }
            set
            {
                base.AutoSize = value;
            }
        }
        #endregion Layout
 
        #region Containership
        /// <summary>
        ///     Gets the parent container of the hosted Windows Presentation Foundation element.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SWC.Panel HostContainer
        {
            get { return HostContainerInternal; }
        }
 
        internal HwndSource HwndSource
        {
            get { return _hwndSource; }
        }
 
        /// <summary>
        /// Indicates that the Child property has been changed.
        /// </summary>
        public event EventHandler<ChildChangedEventArgs> ChildChanged;
 
        /// <summary>
        ///     Gets or sets the UIElement hosted by the ElementHost control.
        /// </summary>
        [Browsable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public SW.UIElement Child
        {
            get
            {
                return _child;
            }
            set
            {
                UIElement oldValue = Child;
#pragma warning disable 1634, 1691
#pragma warning disable 56526
                _child = value;
#pragma warning restore 1634, 1691, 56526
                HostContainerInternal.Children.Clear();
                if (_child != null)
                {
                    HostContainerInternal.Children.Add(_child);
                    _propertyMap.ApplyAll();
                    InitializeChildProperties();
                }
                OnChildChanged(oldValue);
            }
        }
 
        protected override bool CanEnableIme
        {
            get
            {
                if (this.Child == null)
                {
                    return false;
                }
                return base.CanEnableIme;
            }
        }
 
        /// <summary>
        ///     If focus on HwndSource, we need to return true here.
        /// </summary>
        public override bool Focused
        {
            get
            {
                if( IsHandleCreated )
                {
                    // observe that the EH.Child may be null and still it has an HwndSource.
                    IntPtr focusHandle = UnsafeNativeMethods.GetFocus();
                    return (focusHandle == this.Handle || (this.HwndSource != null && focusHandle == this.HwndSource.Handle));
                }
 
                return false;
            }
        }
 
        protected override SWF.ImeMode ImeModeBase
        {
            get
            {
                return this.CanEnableIme ? base.ImeModeBase : ImeMode.Disable;
            }
            set
            {
                base.ImeModeBase = value;
 
                // When the ImeMode is set to ImeMode.NoControl, Winforms stops raising the ImeModeChanged event
                // on the control, we need to notify the property mapper explicitly.
                if (value == SWF.ImeMode.NoControl)
                {
                    this.OnPropertyChangedImeMode(this, EventArgs.Empty);
                }
 
            }
        }
 
        /// <summary>
        ///    Raises the EnabledChanged event
        /// </summary>
        protected override void OnEnabledChanged(EventArgs e)
        {
            base.OnEnabledChanged(e);
 
            if (this.HwndSource != null && this.HwndSource.Handle != IntPtr.Zero)
            {
                NativeMethodsSetLastError.EnableWindow(this.HwndSource.Handle, this.Enabled);
            }
        }
 
        private void OnChildChanged(UIElement oldChild)
        {
            if (this.Child != null)
            {
                SyncHwndSrcImeStatus();
            }
 
            if (ChildChanged != null)
            {
                ChildChanged(this, new ChildChangedEventArgs(oldChild));
            }
        }
 
        /// <summary>
        /// Raises the Leave event.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnLeave(EventArgs e)
        {
            System.Windows.Input.FocusManager.SetFocusedElement(_decorator, null);
            base.OnLeave(e);
        }
 
        /// <summary>
        /// Raises the GotFocus event.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnGotFocus(EventArgs e)
        {
            base.OnGotFocus(e);
            SyncHwndSrcImeStatus();
            _decorator.Focus();
        }
 
        private void InitializeChildProperties()
        {
            FrameworkElement childFrameworkElement = Child as FrameworkElement;
            if (childFrameworkElement != null)
            {
                childFrameworkElement.SizeChanged += new SizeChangedEventHandler(childFrameworkElement_SizeChanged);
                childFrameworkElement.Height = double.NaN;
                childFrameworkElement.Width = double.NaN;
                childFrameworkElement.Margin = new Thickness(0d);
                childFrameworkElement.VerticalAlignment = SW.VerticalAlignment.Stretch;
                childFrameworkElement.HorizontalAlignment = SW.HorizontalAlignment.Stretch;
 
                DesignerProperties.SetIsInDesignMode(childFrameworkElement, this.DesignMode);
 
                Vector scale = HostUtils.GetScale(childFrameworkElement);
                SD.Size maxElementSize = Convert.ToSystemDrawingSize(new Size(childFrameworkElement.MaxWidth, childFrameworkElement.MaxHeight), scale);
                SD.Size priorMaxSize = HostUtils.ConvertZeroToUnbounded(MaximumSize);
                int maxWidth = Math.Min(priorMaxSize.Width, maxElementSize.Width);
                int maxHeight = Math.Min(priorMaxSize.Height, maxElementSize.Height);
                MaximumSize = HostUtils.ConvertUnboundedToZero(new SD.Size(maxWidth, maxHeight));
            }
        }
 
        /// <summary>
        /// Raises the VisibleChanged event.
        /// </summary>
        /// <param name="e"></param>
        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            UpdateBackground();
        }
 
        void CallUpdateBackground(object sender, EventArgs e)
        {
            UpdateBackground();
        }
 
        void UpdateBackground()
        {
            OnPropertyChanged("BackgroundImage", BackgroundImage); //Update the background
        }
 
        void childFrameworkElement_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (AutoSize)
            {
                PerformLayout();
            }
        }
 
        internal AvalonAdapter HostContainerInternal
        {
            get
            {
                return _hostContainerInternal;
            }
        }
        #endregion Containership
 
        #region Rendering
 
        /// <summary>
        ///     Gets or sets a value indicating whether the hosted element has a transparent background.
        /// </summary>
        [DefaultValue(false)]
        public bool BackColorTransparent
        {
            get { return _backColorTransparent; }
            set
            {
                _backColorTransparent = value;
                UpdateBackground();
            }
        }
 
        /// <internalonly>
        ///     Hide GDI painting because the HwndTarget is going to just bitblt the root
        ///     visual on top of everything.
        /// </internalonly>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        protected override void OnPaint(SWF.PaintEventArgs e)
        {
            base.OnPaint(e);
        }
 
        /// <internalonly>
        ///     Paint our parent's background into an offscreen HBITMAP.
        ///     We then draw this as our background in the hosted Avalon
        ///     control's Render() method to support WinForms->Avalon transparency.
        /// </internalonly>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        protected override void OnPaintBackground(SWF.PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);
            _decorator.InvalidateVisual();
        }
 
        internal void InvokePaintBackgroundAndPaint(SWF.Control control, SWF.PaintEventArgs args)
        {
            this.InvokePaintBackground(control, args);
            this.InvokePaint(control, args);
        }
 
        /// <summary>
        /// Renders the control using the provided Graphics object.
        /// </summary>
        /// <param name="e"></param>
        [ResourceExposure(ResourceScope.None)]
        // Resource consumption: HostUtils.GetBitmapFromRenderTargetBitmap.
        [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
        protected override void OnPrint(PaintEventArgs e)
        {
            SWMI.RenderTargetBitmap renderBitmap = HostUtils.GetBitmapForFrameworkElement(_decorator);
            if (renderBitmap != null)
            {
                using (SD.Bitmap bitmap = HostUtils.GetBitmapFromRenderTargetBitmap(this, renderBitmap, new Point(0, 0)))
                {
                    e.Graphics.DrawImage(bitmap, SD.Point.Empty);
                }
            }
        }
 
        #endregion rendering
 
        #region Keyboarding
        /// <summary>
        ///     Activates the hosted element.
        /// </summary>
        protected override void Select(bool directed, bool forward)
        {
            if (directed == true)
            {
                SWI.TraversalRequest request = new SWI.TraversalRequest(forward
                                                        ? SWI.FocusNavigationDirection.First
                                                        : SWI.FocusNavigationDirection.Last);
 
                //Currently ignore TabInto's return value
                (_hwndSource as IKeyboardInputSink).TabInto(request);
            }
            else
            {
                if (Child != null)
                {
                    Child.Focus();
                }
            }
 
            base.Select(directed, forward);
        }
 
        /// <summary>
        ///     Processes a command key, ensuring that the hosted element has an
        ///     opportunity to handle the command before normal Windows Forms processing.
        /// </summary>
        /// <internal>
        ///     This will try see if the pressed key is an Avalon accelerator, if so it returns TRUE,
        ///     which tells WinForms to stop trying to process this key.
        /// </internal>
        protected override bool ProcessCmdKey(ref System.Windows.Forms.Message msg, System.Windows.Forms.Keys keyData)
        {
            MSG msg2 = Convert.ToSystemWindowsInteropMSG(msg);
            SWI.ModifierKeys modifiers = Convert.ToSystemWindowsInputModifierKeys(keyData);
 
            // Let the AvalonAdapter know that ElementHost is currently processing a TabKey
            if (_hostContainerInternal != null) {
                _hostContainerInternal.ProcessingTabKeyFromElementHost = (keyData & SWF.Keys.Tab) == SWF.Keys.Tab;
            }
 
            bool result = (_hwndSource as IKeyboardInputSink).TranslateAccelerator(ref msg2, modifiers);
 
            // _hostContainerInternal can be disposed if the control is closed using keyboard.
            if (_hostContainerInternal != null && _hostContainerInternal.ProcessingTabKeyFromElementHost) {
                _hostContainerInternal.ProcessingTabKeyFromElementHost = false;
            }
 
            return result || base.ProcessCmdKey(ref msg, keyData);
        }
 
        /// <summary>
        ///     Processes a mnemonic character, ensuring that the hosted element has an opportunity to handle the mnemonic before
        ///     normal Windows Forms processing.
        /// </summary>
        /// <internal>
        ///     This will try see if the pressed key is an Avalon accelerator, if so it tries
        ///     to process the key, which may move focus to the Avalon control.
        /// </internal>
        protected override bool ProcessMnemonic(char charCode)
        {
            string upperKey = Char.ToUpper(charCode, CultureInfo.CurrentCulture).ToString();
            if (SWI.AccessKeyManager.IsKeyRegistered(_hwndSource, upperKey))
            {
                // ProcessKey doesn't return enough information for us to handle
                // mnemonic cycling reliably.  I.e. we can't tell the difference
                // between a key which wasn't processed (returns false) from the
                // case where there is just one element with this key registered
                // (also returns false).
                SWI.AccessKeyManager.ProcessKey(_hwndSource, upperKey, false);
                return true;
            }
            else
            {
                return base.ProcessMnemonic(charCode);
            }
        }
 
        /// <summary>
        ///     Ensures that all WM_CHAR key messages are forwarded to the hosted element.
        /// </summary>
        /// <internal>
        ///     Grab all WM_CHAR messages as text input to ensure they're sent to
        ///     Avalon.  If Avalon doesn't handle the message, we will call
        ///     ProcessDialogChar later on.
        /// </internal>
        protected override bool IsInputChar(char charCode)
        {
            return true;
        }
 
        /// <summary>
        ///     Catch WM_CHAR messages which weren't handled by Avalon
        ///     (including mnemonics which were typed without the "Alt" key)
        /// </summary>
        private void InputManager_PostProcessInput(object sender, SWI.ProcessInputEventArgs e)
        {
            IKeyboardInputSink ikis = _hwndSource as IKeyboardInputSink;
            if (ikis == null || !ikis.HasFocusWithin())
            {
                return;
            }
            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]);
                }
            }
        }
 
        /// <summary>
        ///     Enables a window to receive keyboard messages correctly when it is opened modelessly from Windows Forms.
        /// </summary>
        /// <param name="window">The System.Windows.Window which will be opened modelessly.</param>
        public static void EnableModelessKeyboardInterop(SW.Window window)
        {
            ApplicationInterop.EnableModelessKeyboardInterop(window);
        }
 
        #endregion Keyboarding
 
        #region Window Handling & Misc
        /// <internalonly>
        ///     Raises the HandleCreated event.
        /// </internalonly>
        protected override void OnHandleCreated(EventArgs e)
        {
            // We are about to call into WPF, and possibly from a callstack unrelated to WPF at all.
            // WPF needs to install its synchronization context, exception handlers, etc. So just
            // do it the normal way through Invoke.
            SWT.Dispatcher.CurrentDispatcher.Invoke(()=>
            {
                if (_hwndSource != null)
                {
                    DisposeHWndSource();
                }
                SWF.CreateParams cp = this.CreateParams;
 
                HwndSourceParameters HWSParam = new HwndSourceParameters(this.Text, cp.Width, cp.Height);
                HWSParam.WindowClassStyle = cp.ClassStyle;
                HWSParam.WindowStyle = cp.Style;
                HWSParam.ExtendedWindowStyle = cp.ExStyle;
                HWSParam.ParentWindow = Handle;
                HWSParam.HwndSourceHook = HwndSourceHook;
 
                _hwndSource = new HwndSource(HWSParam);
                _hwndSource.RootVisual = _decorator;
                //For keyboarding: Set the IKeyboardInputSite so that keyboard interop works...
                (_hwndSource as IKeyboardInputSink).KeyboardInputSite = (HostContainerInternal as IKeyboardInputSite);
            });
 
            base.OnHandleCreated(e);
        }
 
        /// <summary>
        ///     Hook for the HwndSource.WndProc.
        /// </summary>
        private IntPtr HwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            switch (msg)
            {
                case NativeMethods.WM_SETFOCUS:
                    if (wParam != Handle)
                    {
                        // wParam != Handle means focus was lost by a window different from this (EH).
                        // The message was sent directly to the HwndSource (by direct mouse input).
                        // We need to notify Winforms so it can set the active control and in turn
                        // notify Control.ActiveXImpl in case we are hosted in an unmanaged app.
                        // EH will set focus back to the WPF control from its OnGotFocus method.
                        this.Focus();
                    }
                    break;
 
                case NativeMethods.WM_KILLFOCUS:
                    if (!this.Focused)
                    {
                        UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), msg, wParam, lParam);
                    }
                    break;
 
                case NativeMethods.WM_INPUTLANGCHANGE:
                    OnHwndSrcWmInputLangChange(msg, wParam, lParam, ref handled);
                    break;
 
                case NativeMethods.WM_IME_NOTIFY:
                    OnHwndSrcWmImeNotify(msg, wParam, lParam, ref handled);
 
                    break;
            }
 
            return IntPtr.Zero; // This value depends on the message being processed, see MSDN for the particular message.
        }
 
        private void SetHWndSourceWindowPos()
        {
            if (_hwndSource != null)
            {
                SafeNativeMethods.SetWindowPos(_hwndSource.Handle, NativeMethods.HWND_TOP, 0, 0, this.Width, this.Height, 0);
            }
        }
 
        /// <summary>
        ///     Synchronizes the HwndSource context status to the ElementHost's
        /// </summary>
        internal bool SyncHwndSrcImeStatus()
        {
            Debug.WriteLineIf(HostUtils.ImeMode.Level >= TraceLevel.Info, "Inside SyncHwndSrcImeStatus(), this = " + this);
            Debug.Indent();
 
            bool handled = false;
 
            if (this.HwndSource != null)
            {
                ImeMode ehImeMode = this.ImeMode != ImeMode.NoControl ? this.ImeMode : SWF.Control.PropagatingImeMode;
                ImeMode hsImeMode = SWF.ImeContext.GetImeMode(this.HwndSource.Handle);
 
                SetChildElementsIsImeEnabled(this.Child, ehImeMode != ImeMode.Disable);
 
                if (ehImeMode != hsImeMode)
                {
                    SWF.ImeContext.SetImeStatus(ehImeMode, this.HwndSource.Handle);
                }
 
                handled = true;
            }
 
            Debug.Unindent();
 
            return handled;
        }
 
        /// <summary>
        ///     Maps the ImeMode property.  This is needed to synchronize the EH IME context with TFS used in WPF.
        /// </summary>
        private static void SetChildElementsIsImeEnabled(SW.DependencyObject element, bool isEnabled)
        {
            if (element == null)
            {
                return;
            }
 
            if (element is SW.IInputElement)
            {
                Debug.WriteLineIf(HostUtils.ImeMode.Level >= TraceLevel.Verbose, "SetChildElementsIsImeEnabled, element = " + element);
                SWI.InputMethod.SetIsInputMethodEnabled(element, isEnabled);
            }
 
            // Ideally, setting the top control context mode should suffice as with any other mapped property on EH
            // but there is no InputMethodEnabledChanged event for clients to listen to to update child elements.
            // we need to traverse the visual tree and do it ourselves.
 
            int childCount = VisualTreeHelper.GetChildrenCount(element);
 
            for (int childIndex = 0; childIndex < childCount; childIndex++)
            {
                SetChildElementsIsImeEnabled(VisualTreeHelper.GetChild(element, childIndex), isEnabled);
            }
        }
 
        /// <summary>
        ///     Handles HwndSrc WM_INPUTLANGCHANGED.
        /// </summary>
        private void OnHwndSrcWmInputLangChange(int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            Debug.WriteLineIf(HostUtils.ImeMode.Level >= TraceLevel.Info, "Inside OnHwndSrcWmInputLangChange(), this = " + this);
            Debug.Indent();
 
            if (!_processingWmInputLangChanged)
            {
                _processingWmInputLangChanged = true;
 
                try
                {
                    // IME is being attached, notify the ElementHost to update its handle context, it in turn will pass
                    // the message to the HwndSource to update its context too.
                    OnHwndSourceMsgNotifyElementHost(msg, wParam, lParam);
                    handled = true;
                }
                finally
                {
                    _processingWmInputLangChanged = false;
                }
            }
 
            Debug.Unindent();
        }
 
 
        /// <summary>
        ///     Handles HwndSrc WM_IME_NOTIFY.
        /// </summary>
        private void OnHwndSrcWmImeNotify(int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            Debug.WriteLineIf(HostUtils.ImeMode.Level >= TraceLevel.Info, "Inside OnHwndSrcWmImeNotify(), this = " + this);
            Debug.Indent();
 
            handled = false;
 
            if (SWF.ImeModeConversion.IsCurrentConversionTableSupported) // TODO: remove this condition?
            {
                if (wParam == (IntPtr)NativeMethods.IMN_SETCONVERSIONMODE || wParam == (IntPtr)NativeMethods.IMN_SETOPENSTATUS)
                {
                    // IME context mode has been changed by interaction or a different IME has been attached,
                    // notify EH to update its ImeMode property if needed.
                    ImeMode hsImeMode = SWF.ImeContext.GetImeMode(this.HwndSource.Handle);
                    ImeMode ehImeMode = this.ImeMode;
 
                    if (hsImeMode != ehImeMode)
                    {
                        OnHwndSourceMsgNotifyElementHost(msg, wParam, lParam);
                    }
 
                    handled = true;
                }
            }
 
            Debug.Unindent();
        }
 
        /// <summary>
        ///     Passes a msg sent to the HwndSource into the ElementHost for preprocessing.
        /// </summary>
        private void OnHwndSourceMsgNotifyElementHost(int msg, IntPtr wParam, IntPtr lParam)
        {
            Debug.WriteLineIf(HostUtils.ImeMode.Level >= TraceLevel.Verbose, "Inside OnHwndSourceMsgNotifyElementHost()");
            Debug.Indent();
 
            UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), msg, wParam, lParam);
 
            Debug.Unindent();
        }
 
        /// <summary>
        /// Processes Windows messages.
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)
            {
                case NativeMethods.WM_MOVE:
                case NativeMethods.WM_SIZE:
                case NativeMethods.WM_WINDOWPOSCHANGED:
                case NativeMethods.WM_WINDOWPOSCHANGING:
                    base.WndProc(ref m);
                    SetHWndSourceWindowPos();
                    break;
                case NativeMethods.WM_PARENTNOTIFY:
                case NativeMethods.WM_REFLECT + NativeMethods.WM_PARENTNOTIFY:
                    base.WndProc(ref m);
                    if (HostUtils.LOWORD(m.WParam) == NativeMethods.WM_CREATE)
                    {
                        this.BeginInvoke(new MethodInvoker(SetHWndSourceWindowPos));
                    }
                    break;
                case NativeMethods.WM_SETREDRAW:
                    if (!DesignMode && m.WParam == IntPtr.Zero)
                    {
                        base.WndProc(ref m);
                    }
                    break;
                case NativeMethods.WM_KILLFOCUS:
                    // if focus is being set on the HwndSource then we should prevent LostFocus by
                    // handling this message.
                    if (this.HwndSource == null || this.HwndSource.Handle != m.WParam)
                    {
                        base.WndProc(ref m);
 
                    }
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }
 
        /// <summary>
        ///     Scales the parent container and the Windows Forms control.
        /// </summary>
        /// <param name="dx"></param>
        /// <param name="dy"></param>
        protected override void ScaleCore(float dx, float dy)
        {
            TransformGroup layoutTransforms = new TransformGroup();
            layoutTransforms.Children.Add(_decorator.LayoutTransform);
            layoutTransforms.Children.Add(new ScaleTransform(dx, dy));
            _decorator.LayoutTransform = layoutTransforms;
            base.ScaleCore(dx, dy);
        }
 
        /// <internalonly/>
        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                try
                {
                    if (_hostContainerInternal != null)
                    {
                        _hostContainerInternal.Dispose();
                        _hostContainerInternal = null;
                    }
                }
                finally
                {
                    try
                    {
                        if (_hwndSource != null)
                        {
                            DisposeHWndSource();
                        }
                    }
                    finally
                    {
                        SWI.InputManager.Current.PostProcessInput -= InputManager_PostProcessInput;
 
                        IDisposable disposableChild = Child as IDisposable;
                        if (disposableChild != null)
                        {
                            disposableChild.Dispose();
                        }
                    }
                }
            }
            base.Dispose(disposing);
        }
 
        private void DisposeHWndSource()
        {
            //For keyboarding: As per comment in the Avalon code, this is set to null before disposal
            (_hwndSource as IKeyboardInputSink).KeyboardInputSite = null;
 
            _hwndSource.Dispose();
            _hwndSource = null;
        }
        #endregion Window Handling & Misc
 
        #region Property Mapping
 
        /// <summary>
        ///     This initializes the default property mapping for the element host.
        ///     First: it creates a new PropertyMap to store all the mappings, this
        ///         is exposed to the user as the PropertyMap property.
        ///     Second: it forwards all property Changed events that we want to listen to
        ///         towards the OnPropertyChanged method.
        ///     Third: it registers several default translators, all of which are handled by
        ///         the ElementHostPropertyTranslator deligate.
        /// </summary>
        private void StartPropertyMapping()
        {
            _propertyMap = new ElementHostPropertyMap(this);
 
            //This forwards property change notification to OnPropertyChanged, since
            //there is no generic way to handle listening to property value changes.
            this.BackColorChanged += this.OnPropertyChangedBackColor;
            this.BackgroundImageChanged += this.OnPropertyChangedBackgroundImage;
            this.BackgroundImageLayoutChanged += this.OnPropertyChangedBackgroundImageLayout;
            this.CursorChanged += this.OnPropertyChangedCursor;
            this.EnabledChanged += this.OnPropertyChangedEnabled;
            this.FontChanged += this.OnPropertyChangedFont;
            this.ForeColorChanged += this.OnPropertyChangedForeColor;
            this.RightToLeftChanged += this.OnPropertyChangedRightToLeft;
            this.VisibleChanged += this.OnPropertyChangedVisible;
 
            //We forward these property changes, but don't do anything with them.
            this.AutoSizeChanged += this.OnPropertyChangedAutoSize;
            this.BindingContextChanged += this.OnPropertyChangedBindingContext;
            this.CausesValidationChanged += this.OnPropertyChangedCausesValidation;
            this.ContextMenuStripChanged += this.OnPropertyChangedContextMenuStrip;
            this.DockChanged += this.OnPropertyChangedDock;
            this.LocationChanged += this.OnPropertyChangedLocation;
            this.MarginChanged += this.OnPropertyChangedMargin;
            this.PaddingChanged += this.OnPropertyChangedPadding;
            this.ParentChanged += this.OnPropertyChangedParent;
            this.RegionChanged += this.OnPropertyChangedRegion;
            this.SizeChanged += this.OnPropertyChangedSize;
            this.TabIndexChanged += this.OnPropertyChangedTabIndex;
            this.TabStopChanged += this.OnPropertyChangedTabStop;
            this.TextChanged += this.OnPropertyChangedText;
            this.ImeModeChanged += this.OnPropertyChangedImeMode;
        }
 
        /// <summary>
        ///     These delegates just map property changed events to OnPropertyChanged. These are
        ///     necessary in the WinForms model since there is no common path for property change
        ///     notification. (Avalon has an OnPropertyChanged method.)
        /// </summary>
        private void OnPropertyChangedBackColor(object sender, System.EventArgs e)
        {
            OnPropertyChanged("BackColor", this.BackColor);
        }
        private void OnPropertyChangedBackgroundImage(object sender, System.EventArgs e)
        {
            OnPropertyChanged("BackgroundImage", this.BackgroundImage);
        }
        private void OnPropertyChangedBackgroundImageLayout(object sender, System.EventArgs e)
        {
            OnPropertyChanged("BackgroundImageLayout", this.BackgroundImageLayout);
        }
        private void OnPropertyChangedCursor(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Cursor", this.Cursor);
        }
        private void OnPropertyChangedEnabled(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Enabled", this.Enabled);
        }
        private void OnPropertyChangedFont(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Font", this.Font);
        }
        private void OnPropertyChangedForeColor(object sender, System.EventArgs e)
        {
            OnPropertyChanged("ForeColor", this.ForeColor);
        }
        private void OnPropertyChangedRightToLeft(object sender, System.EventArgs e)
        {
            OnPropertyChanged("RightToLeft", this.RightToLeft);
        }
        private void OnPropertyChangedTabStop(object sender, System.EventArgs e)
        {
            OnPropertyChanged("TabStop", this.TabStop);
        }
        private void OnPropertyChangedVisible(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Visible", this.Visible);
        }
 
        // These properties don't have default mappings, but are added in case anyone wants to add them
 
        private void OnPropertyChangedAutoSize(object sender, System.EventArgs e)
        {
            OnPropertyChanged("AutoSize", this.AutoSize);
        }
        private void OnPropertyChangedPadding(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Padding", this.Padding);
        }
        private void OnPropertyChangedBindingContext(object sender, System.EventArgs e)
        {
            OnPropertyChanged("BindingContext", this.BindingContext);
        }
        private void OnPropertyChangedCausesValidation(object sender, System.EventArgs e)
        {
            OnPropertyChanged("CausesValidation", this.CausesValidation);
        }
        private void OnPropertyChangedContextMenuStrip(object sender, System.EventArgs e)
        {
            OnPropertyChanged("ContextMenuStrip", this.ContextMenuStrip);
        }
        private void OnPropertyChangedDock(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Dock", this.Dock);
        }
        private void OnPropertyChangedLocation(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Location", this.Location);
        }
        private void OnPropertyChangedMargin(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Margin", this.Margin);
        }
        private void OnPropertyChangedParent(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Parent", this.Parent);
        }
        private void OnPropertyChangedRegion(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Region", this.Region);
        }
        private void OnPropertyChangedSize(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Size", this.Size);
        }
        private void OnPropertyChangedTabIndex(object sender, System.EventArgs e)
        {
            OnPropertyChanged("TabIndex", this.TabIndex);
        }
        private void OnPropertyChangedText(object sender, System.EventArgs e)
        {
            OnPropertyChanged("Text", this.Text);
        }
        private void OnPropertyChangedImeMode(object sender, System.EventArgs e)
        {
            OnPropertyChanged("ImeMode", this.ImeMode);
        }
 
 
        /// <summary>
        ///     Notifies the property map that a property has changed.
        /// </summary>
        /// <param name="propertyName">the name of the property which has changed and requires translation</param>
        /// <param name="value">the new value of the property</param>
        public virtual void OnPropertyChanged(string propertyName, object value)
        {
            if (PropertyMap != null)
            {
                PropertyMap.OnPropertyChanged(this, propertyName, value);
            }
        }
 
        /// <summary>
        ///     Gets the property map, which determines how setting properties on the
        ///     ElementHost control affects the hosted Windows Presentation Foundation element.
        /// </summary>
        [Browsable(false)]
        public PropertyMap PropertyMap
        {
            get { return _propertyMap; }
        }
        private ElementHostPropertyMap _propertyMap;
 
        #endregion Property Mapping
 
        #region Hidden Events
        /// <summary>
        /// Occurs when the value of the BindingContext property changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler BindingContextChanged
        {
            add { base.BindingContextChanged += value; }
            remove { base.BindingContextChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when the control is clicked.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Click
        {
            add { base.Click += value; }
            remove { base.Click -= value; }
        }
 
        /// <summary>
        /// Occurs when the value of the ClientSize property changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ClientSizeChanged
        {
            add { base.ClientSizeChanged += value; }
            remove { base.ClientSizeChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when a new control is added to the Control.ControlCollection.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event ControlEventHandler ControlAdded
        {
            add { base.ControlAdded += value; }
            remove { base.ControlAdded -= value; }
        }
 
        /// <summary>
        /// Occurs when a control is removed from the Control.ControlCollection.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event ControlEventHandler ControlRemoved
        {
            add { base.ControlRemoved += value; }
            remove { base.ControlRemoved -= value; }
        }
 
        /// <summary>
        /// Occurs when the value of the Cursor property changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler CursorChanged
        {
            add { base.CursorChanged += value; }
            remove { base.CursorChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when the control is double-clicked.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DoubleClick
        {
            add { base.DoubleClick += value; }
            remove { base.DoubleClick -= value; }
        }
 
        /// <summary>
        /// Occurs when a drag-and-drop operation is completed.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event DragEventHandler DragDrop
        {
            add { base.DragDrop += value; }
            remove { base.DragDrop -= value; }
        }
 
        /// <summary>
        /// Occurs when an object is dragged into the control's bounds.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event DragEventHandler DragEnter
        {
            add { base.DragEnter += value; }
            remove { base.DragEnter -= value; }
        }
 
        /// <summary>
        /// Occurs when an object is dragged out of the control's bounds.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler DragLeave
        {
            add { base.DragLeave += value; }
            remove { base.DragLeave -= value; }
        }
 
        /// <summary>
        /// Occurs when an object is dragged over the control's bounds.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event DragEventHandler DragOver
        {
            add { base.DragOver += value; }
            remove { base.DragOver -= value; }
        }
 
        /// <summary>
        /// Occurs when the control is entered.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Enter
        {
            add { base.Enter += value; }
            remove { base.Enter -= value; }
        }
 
        /// <summary>
        /// Occurs when the Font property value changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler FontChanged
        {
            add { base.FontChanged += value; }
            remove { base.FontChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when the ForeColor property value changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler ForeColorChanged
        {
            add { base.ForeColorChanged += value; }
            remove { base.ForeColorChanged -= value; }
        }
 
        /// <summary>
        /// Occurs during a drag operation.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event GiveFeedbackEventHandler GiveFeedback
        {
            add { base.GiveFeedback += value; }
            remove { base.GiveFeedback -= value; }
        }
 
        /// <summary>
        /// Occurs when the control receives focus.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler GotFocus
        {
            add { base.GotFocus += value; }
            remove { base.GotFocus -= value; }
        }
 
        /// <summary>
        /// Occurs when a control's display requires redrawing.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event InvalidateEventHandler Invalidated
        {
            add { base.Invalidated += value; }
            remove { base.Invalidated -= value; }
        }
 
        /// <summary>
        /// Occurs when a key is pressed while the control has focus.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyDown
        {
            add { base.KeyDown += value; }
            remove { base.KeyDown -= value; }
        }
 
        /// <summary>
        /// Occurs when a key is pressed while the control has focus.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyPressEventHandler KeyPress
        {
            add { base.KeyPress += value; }
            remove { base.KeyPress -= value; }
        }
 
        /// <summary>
        /// Occurs when a key is released while the control has focus.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event KeyEventHandler KeyUp
        {
            add { base.KeyUp += value; }
            remove { base.KeyUp -= value; }
        }
 
        /// <summary>
        /// Occurs when a control should reposition its child controls.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event LayoutEventHandler Layout
        {
            add { base.Layout += value; }
            remove { base.Layout -= value; }
        }
 
        /// <summary>
        /// Occurs when the input focus leaves the control.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Leave
        {
            add { base.Leave += value; }
            remove { base.Leave -= value; }
        }
 
        /// <summary>
        /// Occurs when the control loses focus.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler LostFocus
        {
            add { base.LostFocus += value; }
            remove { base.LostFocus -= value; }
        }
 
        /// <summary>
        /// Occurs when the control loses mouse capture.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler MouseCaptureChanged
        {
            add { base.MouseCaptureChanged += value; }
            remove { base.MouseCaptureChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when the control is clicked by the mouse.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseClick
        {
            add { base.MouseClick += value; }
            remove { base.MouseClick -= value; }
        }
 
        /// <summary>
        /// Occurs when the control is double clicked by the mouse.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseDoubleClick
        {
            add { base.MouseDoubleClick += value; }
            remove { base.MouseDoubleClick -= value; }
        }
 
        /// <summary>
        /// Occurs when the mouse pointer is over the control and a mouse button is pressed.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseDown
        {
            add { base.MouseDown += value; }
            remove { base.MouseDown -= value; }
        }
 
        /// <summary>
        /// Occurs when the mouse pointer enters the control.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler MouseEnter
        {
            add { base.MouseEnter += value; }
            remove { base.MouseEnter -= value; }
        }
 
        /// <summary>
        /// Occurs when the mouse pointer rests on the control.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler MouseHover
        {
            add { base.MouseHover += value; }
            remove { base.MouseHover -= value; }
        }
 
        /// <summary>
        /// Occurs when the mouse pointer leaves the control. (
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler MouseLeave
        {
            add { base.MouseLeave += value; }
            remove { base.MouseLeave -= value; }
        }
 
        /// <summary>
        /// Occurs when the mouse pointer is moved over the control.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseMove
        {
            add { base.MouseMove += value; }
            remove { base.MouseMove -= value; }
        }
 
        /// <summary>
        /// Occurs when the mouse pointer is over the control and a mouse button is released.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseUp
        {
            add { base.MouseUp += value; }
            remove { base.MouseUp -= value; }
        }
 
        /// <summary>
        /// Occurs when the mouse wheel moves while the control has focus.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event MouseEventHandler MouseWheel
        {
            add { base.MouseWheel += value; }
            remove { base.MouseWheel -= value; }
        }
 
        /// <summary>
        /// Occurs when the control's padding changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler PaddingChanged
        {
            add { base.PaddingChanged += value; }
            remove { base.PaddingChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when the control is redrawn.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event PaintEventHandler Paint
        {
            add { base.Paint += value; }
            remove { base.Paint -= value; }
        }
 
        /// <summary>
        /// Occurs before the KeyDown event when a key is pressed while focus is on this control.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event PreviewKeyDownEventHandler PreviewKeyDown
        {
            add { base.PreviewKeyDown += value; }
            remove { base.PreviewKeyDown -= value; }
        }
 
        /// <summary>
        /// Occurs during a drag-and-drop operation and enables the drag source to determine
        /// whether the drag-and-drop operation should be canceled.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event QueryContinueDragEventHandler QueryContinueDrag
        {
            add { base.QueryContinueDrag += value; }
            remove { base.QueryContinueDrag -= value; }
        }
 
        /// <summary>
        /// Occurs when the control is resized.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler Resize
        {
            add { base.Resize += value; }
            remove { base.Resize -= value; }
        }
 
        /// <summary>
        /// Occurs when the RightToLeft property value changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler RightToLeftChanged
        {
            add { base.RightToLeftChanged += value; }
            remove { base.RightToLeftChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when the Size property value changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler SizeChanged
        {
            add { base.SizeChanged += value; }
            remove { base.SizeChanged -= value; }
        }
 
        /// <summary>
        /// Occurs when the Text property value changes.
        /// </summary>
        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new event EventHandler TextChanged
        {
            add { base.TextChanged += value; }
            remove { base.TextChanged -= value; }
        }
        #endregion
 
        #region DEBUG
#if DEBUG
        private static readonly TraceSwitch _traceLayout = new TraceSwitch("ElementHostLayout", "Tracks ElementHost layout information.");
#else
        private static readonly TraceSwitch _traceLayout = null;
#endif
 
        #endregion DEBUG
    }
 
 
    #region AvalonAdapter
    internal class AvalonAdapter : SWC.DockPanel, IDisposable, IKeyboardInputSite, IAvalonAdapter
    {
        private ElementHost _hostControl;
 
        [SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
        static AvalonAdapter()
        {
            //These properties define how tabbing occurs in the DockPanel. To be most like
            //WinForms these are set to use Continue mode as the default.
            //TODO: Do we need to have ControlTabNavigationProperty to for Ctrl-Tab???
            SWI.KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(
                    typeof(AvalonAdapter),
                    new FrameworkPropertyMetadata(SWI.KeyboardNavigationMode.Continue));
            SWI.KeyboardNavigation.TabNavigationProperty.OverrideMetadata(
                    typeof(AvalonAdapter),
                    new FrameworkPropertyMetadata(SWI.KeyboardNavigationMode.Continue));
        }
 
        /// <internalOnly>
        ///     Creates the Avalon control we use to host
        ///     other WinForms control in Avalon.
        ///</internalOnly>
        public AvalonAdapter(ElementHost hostControl)
        {
            _hostControl = hostControl;
        }
 
        ///<internalOnly>
        ///   unsink our events
        ///</internalOnly>
        public void Dispose()
        {
            _hostControl = null;
        }
 
        // used to force invalidation of the avalon control's client area.
        public static readonly DependencyProperty ForceInvalidateProperty =
                DependencyProperty.Register(
                        "ForceInvalidate",
                        typeof(bool),
                        typeof(AvalonAdapter),
                        new FrameworkPropertyMetadata(
                                false,
                                FrameworkPropertyMetadataOptions.AffectsRender));
 
        private static object OnGetForceInvalidate(DependencyObject d)
        {
            return ((AvalonAdapter)d).ForceInvalidate;
        }
 
        /// <summary>
        ///     This property is toggled by ElementHost to force the hosted
        ///     Avalon control to redraw itself
        /// </summary>
        public bool ForceInvalidate
        {
            get { return (bool)GetValue(ForceInvalidateProperty); }
            set { SetValue(ForceInvalidateProperty, value); }
        }
 
        /// <summary>
        ///     This is a transparency optimization. It looks up the SWF visual heirarchy to
        ///     find the first opaque control. It then uses this color as the background for
        ///     OnRender. This doesn't work all the time, but is much faster than the bitmap
        ///     conversion.
        /// </summary>
        /// <param name="whichControl">The current control</param>
        /// <returns>The first opaque color found, or Color.Empty if none is found</returns>
        private static SD.Color FindSolidColorParent(Control whichControl)
        {
            Control control = whichControl;
            while (control.Parent != null)
            {
                control = control.Parent;
                if (control.BackColor != SD.Color.Empty && control.BackColor.A == 255)
                {
                    return control.BackColor;
                }
            }
            return SD.Color.Empty;
        }
 
        #region IAvalonAdapter
 
        /// <summary>
        ///     Implements IAvalonAdapter.OnNoMoreTabStops an extended version of IKeyboardInputSite.OnNoMoreTabStops.
        ///     Components call this when they want to move focus ("tab") but have nowhere further to tab within their
        ///     own component.
        /// </summary>
        /// <param name="shouldCycle">
        ///     Whether focus should wrap around from the caller if we couldn't move focus.
        /// </param>
        /// <returns>
        ///     True if the site moved focus, false if the calling component still has focus.
        /// </returns>
        public bool OnNoMoreTabStops(SWI.TraversalRequest request, ref bool shouldCycle)
        {
            if(ProcessingTabKeyFromElementHost)
            {
                shouldCycle = false;
                return false;
            }
 
            return OnNoMoreTabStops(request);
        }
 
        #endregion
 
        #region IKeyboardInputSite
        public void Unregister()
        {
        }
 
        public bool OnNoMoreTabStops(SWI.TraversalRequest request)
        {
            //Tabbing out of hosted elements
 
            //Select the next control
            bool forward = true;
            Debug.Assert(request != null, "request was null!");
            if (request != null)
            {
                switch (request.FocusNavigationDirection)
                {
                    case System.Windows.Input.FocusNavigationDirection.Down:
                    case System.Windows.Input.FocusNavigationDirection.Right:
                    case System.Windows.Input.FocusNavigationDirection.Next:
                        forward = true;
                        break;
                    case System.Windows.Input.FocusNavigationDirection.Up:
                    case System.Windows.Input.FocusNavigationDirection.Left:
                    case System.Windows.Input.FocusNavigationDirection.Previous:
                        forward = false;
                        break;
                    case System.Windows.Input.FocusNavigationDirection.First:
                    case System.Windows.Input.FocusNavigationDirection.Last:
                        break;
                    default:
                        Debug.Assert(false, "Unknown FocusNavigationDirection");
                        break;
                }
            }
 
            if (_hostControl != null)
            {
                Control topMostParent = null;
 
                if (forward)
                {
                    // Get _hostControl's top-most parent.
                    topMostParent = _hostControl;
                    while (topMostParent.Parent != null)
                    {
                        topMostParent = topMostParent.Parent;
                    }
 
                    bool shouldWrap = ShouldSearchWrapForParentControl(topMostParent);
 
                    if (topMostParent.SelectNextControl(_hostControl, true, true, true, shouldWrap))
                    {
                        return true;
                    }
 
                }
                else
                {
                    // DDVSO: 458074. The above logic may not work in some cases going backwards,
                    // namely when a UserControl is involved, since the previous selectable item
                    // starting from the ElementHost would be its own UserControl, causing it to
                    // select the ElementHost again. Instead try to select the next control using
                    // the direct parent and starting from the current control, if that fails we
                    // go one level up.
                    Control currentControl = _hostControl;
                    Control parentControl = _hostControl.Parent;
 
                    while (parentControl != null)
                    {
                        bool shouldWrap = ShouldSearchWrapForParentControl(parentControl);
 
                        if (parentControl.SelectNextControl(currentControl, false, true, true, shouldWrap))
                        {
                            return true;
                        }
 
                        currentControl = parentControl;
                        parentControl = parentControl.Parent;
                    }
 
                    topMostParent = currentControl;
                }
 
                if (!CoreAppContextSwitches.UseNetFx471CompatibleAccessibilityFeatures)
                {
                    // DDVSO: 445603. If the top-most parent in this WinForms hierarchy is a WinFormsAdapter,
                    // that means there may be more WPF controls that can receive focus outside, forward the
                    // OnNoMoreTabStops call to the adapter's host.
                    WinFormsAdapter adapter = topMostParent as WinFormsAdapter;
 
                    if (adapter != null)
                    {
                        return adapter.HostKeyboardInputSite?.OnNoMoreTabStops(request) == true;
                    }
                }
            }
 
            return false;
        }
 
        private bool ShouldSearchWrapForParentControl(Control control)
        {
            // Only wrap for topmost controls
            // DDVSO 445603. If the topmost parent is a WinFormsAdapter we
            // shouldn't wrap, since there may be more WPF controls outside of
            // this WinForms hierarchy, only apply this logic if the accessibility
            // flag is set.
            return (control.Parent == null) &&
                    (CoreAppContextSwitches.UseNetFx471CompatibleAccessibilityFeatures
                    || !(control is WinFormsAdapter));
        }
 
        public IKeyboardInputSink Sink
        {
            get
            {
                return (_hostControl.HwndSource as IKeyboardInputSink);
            }
        }
        #endregion IKeyboardInputSite
 
        protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
        {
            return new ElementHostAutomationPeer(this);
        }
 
        // Set by ElementHost to let this AvalonAdapter it is currently processing a Tab Key.
        internal bool ProcessingTabKeyFromElementHost{ get; set; }
    }
    #endregion AvalonAdapter
}