Вставить панель формы Windows в элемент управления WPF
Я пытаюсь создать модные элементы управления WPF для настольных приложений Windows. Мне интересно, возможно ли выставить встроенную панель в элемент управления WPF. Идея состоит в том, чтобы создать панель с названием ленты. Кнопка будет использоваться для развертывания или скрытия элементов управления.
Вот моя новая панель:
<UserControl x:Class="TestRibbonPanel.RibbonPanel.XamlRibbonPanel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
xmlns:local="clr-namespace:TestRibbonPanel.RibbonPanel"
mc:Ignorable="d"
d:DesignHeight="150" d:DesignWidth="200" MinHeight="40" x:Name="uc">
<UserControl.Resources>
<local:BorderHeightConverter x:Key="BhConverter"/>
</UserControl.Resources>
<Grid Background="Transparent">
<Grid x:Name="grd" Height="20" VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Button Grid.Column="0" Grid.Row="0" x:Name="btn" Background="#333333" Click="Btn_Click"/>
<TextBlock Grid.Column="1" Grid.Row="0" Text="Title" Background="#333333" Foreground="#CCCCCC"/>
</Grid>
<Popup x:Name="pu" StaysOpen="True" PlacementTarget="{Binding ElementName=grd}" AllowsTransparency="True" PopupAnimation="Slide" IsOpen="True">
<Border x:Name="brd" Background="White" CornerRadius="0,0,10,10" BorderThickness="2" BorderBrush="Black" Height="{Binding Path=ActualHeight, ElementName=uc, Converter={StaticResource BhConverter}, FallbackValue=130}" Width="{Binding ActualWidth, ElementName=grd, FallbackValue=200}" SizeChanged="Brd_SizeChanged">
<WindowsFormsHost>
<wf:Panel x:Name="pnl" BorderStyle="FixedSingle" BackColor="Red"/>
</WindowsFormsHost>
</Border>
</Popup>
</Grid>
В приведенном ниже коде я использовал System.Windows.Controls.Panel в качестве свойства с именем ContentPanel:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace TestRibbonPanel.RibbonPanel
{
/// <summary>
/// Logique d'interaction pour XamlRibbonPanel.xaml
/// </summary>
public partial class XamlRibbonPanel : UserControl
{
public static readonly DependencyProperty IsOPenProperty = DependencyProperty.Register("IsOpen", typeof(bool), typeof(XamlRibbonPanel), new PropertyMetadata(true));
public bool IsOPen
{
get { return (bool)GetValue(IsOPenProperty); }
set
{
SetValue(IsOPenProperty, value);
}
}
public System.Windows.Forms.Panel ContentPanel
{
get { return pnl; }
}
public XamlRibbonPanel()
{
InitializeComponent();
}
private void Brd_SizeChanged(object sender, SizeChangedEventArgs e)
{
pnl.Size = new System.Drawing.Size((int)brd.ActualWidth, (int)brd.ActualHeight);
}
private void Btn_Click(object sender, RoutedEventArgs e)
{
pu.IsOpen = !pu.IsOpen;
}
}
public class BorderHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (double)value - 20;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Теперь я поместил этот элемент управления WPF в оболочку формы Windows, используя класс интеграции ElementHost с именем EH, внедряющий элемент управления XamlRibbonPanel.:
[DesignerAttribute(typeof(XRibbonPanelDesigner))]
public class XRibbonPanel : UserControl
{
private System.ComponentModel.IContainer _components = null;
private System.Windows.Forms.Integration.ElementHost EH;
private RibbonPanel.XamlRibbonPanel _xp = null;
private Panel _contentPanel = null;
public Panel ContentPanel
{
get { return _contentPanel; }
}
/// <summary>
/// .ctor
/// </summary>
public XRibbonPanel()
{
InitializeComponent();
_contentPanel = xp.ContentPanel;
}
private void InitializeComponent()
{
this.EH = new System.Windows.Forms.Integration.ElementHost();
this._xp = new TestRibbonPanel.RibbonPanel.XamlRibbonPanel();
this.SuspendLayout();
//
// EH
//
this.EH.Dock = System.Windows.Forms.DockStyle.Fill;
this.EH.Location = new System.Drawing.Point(0, 0);
this.EH.Name = "EH";
this.EH.Size = new System.Drawing.Size(150, 150);
this.EH.TabIndex = 0;
this.EH.Text = "";
this.EH.Child = _xp;
//
// XRibbonPanel
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.EH);
this.Name = "XRibbonPanel";
this.ResumeLayout(false);
}
protected override void Dispose(bool disposing)
{
if (disposing && (_components != null))
{
_components.Dispose();
}
EH.Dispose();
base.Dispose(disposing);
}
}
Как вы можете видеть, я использовал пользовательский конструктор для элемента управления в надежде представить элемент управления дизайну. Это техника, которую я прочитал здесь и успешно применил для других "классических" элементов управления:
using System;
using System.ComponentModel;
using System.Windows.Forms.Design;
namespace TestRibbonPanel
{
public class XRibbonPanelDesigner : ScrollableControlDesigner
{
XRibbonPanel _panel;
public override void Initialize(IComponent component)
{
base.Initialize(component);
_panel = (XRibbonPanel)component;
if (_panel == null)
throw new ArgumentException();
else
{
System.Windows.Forms.Panel pnl = _panel.ContentPanel;
if (pnl != null)
{
bool result = EnableDesignMode(pnl, "Layout");
}
}
}
}
}
Когда я помещаю XRibbonPanel в форму, панель действует как нужно (открывая и закрывая панель). Но, к сожалению, я не вижу объект "Макет", который я обычно использую для удаления вложенных элементов управления. Еще один неприятный эффект, когда я перемещаю форму, всплывающее окно Xaml Control всплывает на рабочем столе, отделенное от исходной формы. Это также происходит в режиме разработки, когда я, например, оставляю вкладку формы открытой.
Если я установил точку останова на:
bool result = EnableDesignMode(pnl, "Layout");
в конструкторе pnl не имеет значение null, а логический результат - true.
Любая подсказка?