Browse Source

Embeddable control window lifecycle should be tied to native host control

pull/698/head
Nikita Tsukanov 10 years ago
parent
commit
528e891e55
  1. 2
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs
  2. 5
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs
  3. 2
      samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs
  4. 2
      src/Avalonia.Controls/Avalonia.Controls.csproj
  5. 10
      src/Avalonia.Controls/EmbeddableControlRoot.cs
  6. 2
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  7. 2
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  8. 2
      src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml
  9. 75
      src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs
  10. 12
      src/Windows/Avalonia.Win32/Embedding/WpfAvaloniaControlHost.cs

2
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs

@ -85,7 +85,7 @@ namespace WindowsInteropTest
this.avaloniaHost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.avaloniaHost.Child = null;
this.avaloniaHost.Content = null;
this.avaloniaHost.Location = new System.Drawing.Point(6, 19);
this.avaloniaHost.Name = "avaloniaHost";
this.avaloniaHost.Size = new System.Drawing.Size(489, 393);

5
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs

@ -17,10 +17,7 @@ namespace WindowsInteropTest
public EmbedToWinFormsDemo()
{
InitializeComponent();
var ctrl = new EmbeddableControl();
ctrl.Content = new ControlCatalogControl();
ctrl.ApplyTemplate();
avaloniaHost.Child = ctrl;
avaloniaHost.Content = new ControlCatalogControl();
}
}
}

2
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs

@ -25,7 +25,7 @@ namespace WindowsInteropTest
public EmbedToWpfDemo()
{
InitializeComponent();
Host.Child = new EmbeddableControl {Content = new ControlCatalogControl()};
Host.Content = new ControlCatalogControl();
}
}
}

2
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -56,7 +56,7 @@
<Compile Include="HotkeyManager.cs" />
<Compile Include="IApplicationLifecycle.cs" />
<Compile Include="IScrollable.cs" />
<Compile Include="EmbeddableControl.cs" />
<Compile Include="EmbeddableControlRoot.cs" />
<Compile Include="Platform\IEmbeddableWindowImpl.cs" />
<Compile Include="WindowIcon.cs" />
<Compile Include="IPseudoClasses.cs" />

10
src/Avalonia.Controls/EmbeddableControl.cs → src/Avalonia.Controls/EmbeddableControlRoot.cs

@ -11,9 +11,9 @@ using Avalonia.Styling;
namespace Avalonia.Controls
{
public class EmbeddableControl : TopLevel, IStyleable, IFocusScope, INameScope
public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, INameScope, IDisposable
{
public EmbeddableControl() : base(PlatformManager.CreateEmbeddableWindow())
public EmbeddableControlRoot() : base(PlatformManager.CreateEmbeddableWindow())
{
PlatformImpl.Show();
}
@ -63,6 +63,10 @@ namespace Avalonia.Controls
public void Unregister(string name) => _nameScope.Unregister(name);
Type IStyleable.StyleKey => typeof(EmbeddableControl);
Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
public void Dispose()
{
PlatformImpl.Dispose();
}
}
}

2
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@ -209,7 +209,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="EmbeddableControl.xaml">
<EmbeddedResource Include="EmbeddableControlRoot.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>

2
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -32,5 +32,5 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.TreeView.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TreeViewItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Window.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.EmbeddableControl.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.EmbeddableControlRoot.xaml?assembly=Avalonia.Themes.Default"/>
</Styles>

2
src/Avalonia.Themes.Default/EmbeddableControl.xaml → src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml

@ -1,4 +1,4 @@
<Style xmlns="https://github.com/avaloniaui" Selector="EmbeddableControl">
<Style xmlns="https://github.com/avaloniaui" Selector="EmbeddableControlRoot">
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="{StyleResource FontSizeNormal}"/>

75
src/Windows/Avalonia.Win32/Embedding/WinFormsAvaloniaControlHost.cs

@ -5,45 +5,31 @@ using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.VisualTree;
using Avalonia.Win32.Interop;
using Control = System.Windows.Forms.Control;
using WinFormsControl = System.Windows.Forms.Control;
namespace Avalonia.Win32.Embedding
{
[ToolboxItem(true)]
public class WinFormsAvaloniaControlHost : Control
public class WinFormsAvaloniaControlHost : WinFormsControl
{
private EmbeddableControl _child;
private readonly EmbeddableControlRoot _root = new EmbeddableControlRoot();
public EmbeddableControl Child
public WinFormsAvaloniaControlHost()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
UnmanagedMethods.SetParent(_root.PlatformImpl.Handle.Handle, Handle);
_root.Prepare();
if (_root.IsFocused)
FocusManager.Instance.Focus(null);
_root.GotFocus += RootGotFocus;
_root.PlatformImpl.LostFocus += PlatformImpl_LostFocus;
FixPosition();
}
public Avalonia.Controls.Control Content
{
get { return _child; }
set
{
if (value !=null && value.PlatformImpl.Handle.HandleDescriptor != PlatformConstants.WindowHandleType)
throw new ArgumentException("Invalid widget for embedding, don't know what to do with " +
value.PlatformImpl.Handle.HandleDescriptor);
if (_child != null)
{
_child.GotFocus -= _child_GotFocus;
_child.PlatformImpl.LostFocus -= PlatformImpl_LostFocus;
_child.PlatformImpl.Hide();
Unfocus();
UnmanagedMethods.SetParent(_child.PlatformImpl.Handle.Handle, EmbeddedWindowImpl.DefaultParentWindow);
}
_child = value;
if (_child != null)
{
UnmanagedMethods.SetParent(_child.PlatformImpl.Handle.Handle, Handle);
_child.Prepare();
if (_child.IsFocused)
FocusManager.Instance.Focus(null);
_child.GotFocus += _child_GotFocus;
_child.PlatformImpl.LostFocus += PlatformImpl_LostFocus;
FixPosition();
if(Focused)
UnmanagedMethods.SetFocus(_child.PlatformImpl.Handle.Handle);
}
}
get { return (Avalonia.Controls.Control)_root.Content; }
set { _root.Content = value; }
}
void Unfocus()
@ -54,7 +40,7 @@ namespace Avalonia.Win32.Embedding
while (focused.VisualParent != null)
focused = focused.VisualParent;
if (focused == _child)
if (focused == _root)
KeyboardDevice.Instance.SetFocusedElement(null, NavigationMethod.Unspecified, InputModifiers.None);
}
@ -65,32 +51,30 @@ namespace Avalonia.Win32.Embedding
protected override void Dispose(bool disposing)
{
Child = null;
if (disposing)
_root.Dispose();
base.Dispose(disposing);
}
private void _child_GotFocus(object sender, Interactivity.RoutedEventArgs e)
private void RootGotFocus(object sender, Interactivity.RoutedEventArgs e)
{
UnmanagedMethods.SetFocus(_child.PlatformImpl.Handle.Handle);
UnmanagedMethods.SetFocus(_root.PlatformImpl.Handle.Handle);
}
protected override void OnGotFocus(EventArgs e)
{
if (_child != null)
UnmanagedMethods.SetFocus(_child.PlatformImpl.Handle.Handle);
if (_root != null)
UnmanagedMethods.SetFocus(_root.PlatformImpl.Handle.Handle);
}
void FixPosition()
{
if (_child != null && Width > 0 && Height > 0)
UnmanagedMethods.MoveWindow(_child.PlatformImpl.Handle.Handle, 0, 0, Width, Height, true);
if (_root != null && Width > 0 && Height > 0)
UnmanagedMethods.MoveWindow(_root.PlatformImpl.Handle.Handle, 0, 0, Width, Height, true);
}
public WinFormsAvaloniaControlHost()
{
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
protected override void OnResize(EventArgs e)
{
@ -100,8 +84,7 @@ namespace Avalonia.Win32.Embedding
protected override void OnPaint(PaintEventArgs e)
{
if (Child == null)
base.OnPaint(e);
}
}
}

12
src/Windows/Avalonia.Win32/Embedding/WpfAvaloniaControlHost.cs

@ -16,16 +16,16 @@ namespace Avalonia.Win32.Embedding
public class WpfAvaloniaControlHost : HwndHost
{
private WinFormsAvaloniaControlHost _host;
private EmbeddableControl _child;
private Avalonia.Controls.Control _content;
public EmbeddableControl Child
public Avalonia.Controls.Control Content
{
get { return _child; }
get { return _content; }
set
{
if (_host != null)
_host.Child = value;
_child = value;
_host.Content = value;
_content = value;
}
}
@ -39,7 +39,7 @@ namespace Avalonia.Win32.Embedding
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
DestroyHost();
_host = new WinFormsAvaloniaControlHost {Child = _child};
_host = new WinFormsAvaloniaControlHost {Content = _content};
UnmanagedMethods.SetParent(_host.Handle, hwndParent.Handle);
return new HandleRef(this, _host.Handle);
}

Loading…
Cancel
Save