C# 如何将控件转发到自定义控件中的stackpanel?
我正在尝试创建一个自定义控件,它可以简化整个应用程序中工具栏的外观。不幸的是,我似乎找不到一种方法将孩子们从我的控件转发到底层的stackpanel。我试图通过使用ItemsControl来解决这个问题,但它似乎也不起作用 我采用的另一种方法是在ToolbarPanel中使用OnApplyTemplate,但这似乎也不起作用 有人知道如何让控制转发在这里工作吗? 工具栏面板.cs Generic.xamlC# 如何将控件转发到自定义控件中的stackpanel?,c#,wpf,C#,Wpf,我正在尝试创建一个自定义控件,它可以简化整个应用程序中工具栏的外观。不幸的是,我似乎找不到一种方法将孩子们从我的控件转发到底层的stackpanel。我试图通过使用ItemsControl来解决这个问题,但它似乎也不起作用 我采用的另一种方法是在ToolbarPanel中使用OnApplyTemplate,但这似乎也不起作用 有人知道如何让控制转发在这里工作吗? 工具栏面板.cs Generic.xaml 多亏了@Clemens,我终于想出了一个有效的方法。之前尝试失败的关键因素是我没有使用It
多亏了@Clemens,我终于想出了一个有效的方法。之前尝试失败的关键因素是我没有使用
ItemsControl
,也没有将IsItemsHost
设置为true。一旦我这样做了,StackPanel
就完全达到了我的预期
工具栏面板.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
namespace NetworkMonitor.Framework.Controls
{
[ContentProperty(nameof(Items))]
public class ToolbarPanel : ItemsControl
{
static ToolbarPanel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ToolbarPanel), new FrameworkPropertyMetadata(typeof(ToolbarPanel)));
}
public static readonly DependencyProperty ItemsSpacingProperty = DependencyProperty.Register(
nameof(ItemsSpacing), typeof(Thickness), typeof(ToolbarPanel), new PropertyMetadata(default(Thickness)));
public Thickness ItemsSpacing
{
get { return (Thickness) GetValue(ItemsSpacingProperty); }
set { SetValue(ItemsSpacingProperty, value); }
}
}
}
PanelExtensions.cs
using System.Windows;
using System.Windows.Controls;
namespace NetworkMonitor.Framework.Controls.Extensions
{
public class PanelExtensions
{
public static readonly DependencyProperty ChildMarginProperty = DependencyProperty.RegisterAttached(
"ChildMargin", typeof(Thickness), typeof(PanelExtensions), new UIPropertyMetadata(new Thickness(), ChildMarginChanged));
private static void ChildMarginChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Panel panel)
{
panel.Loaded += PanelOnLoaded;
}
}
private static void PanelOnLoaded(object sender, RoutedEventArgs e)
{
if (sender is Panel panel)
{
panel.Loaded -= PanelOnLoaded;
var itemsMargin = GetChildMargin(panel);
var skipLast = GetSkipLastMargin(panel);
for (int i = 0; i < panel.Children.Count; i++)
{
if (skipLast && i == (panel.Children.Count - 1))
break;
var child = panel.Children[i];
if (child is FrameworkElement frameworkElement)
{
frameworkElement.Margin = itemsMargin;
}
}
}
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = true)]
[AttachedPropertyBrowsableForType(typeof(Panel))]
public static void SetChildMargin(DependencyObject element, Thickness value)
{
element.SetValue(ChildMarginProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = true)]
[AttachedPropertyBrowsableForType(typeof(Panel))]
public static Thickness GetChildMargin(DependencyObject element)
{
return (Thickness) element.GetValue(ChildMarginProperty);
}
public static readonly DependencyProperty SkipLastMarginProperty = DependencyProperty.RegisterAttached(
"SkipLastMargin", typeof(bool), typeof(PanelExtensions), new PropertyMetadata(true));
public static void SetSkipLastMargin(DependencyObject element, bool value)
{
element.SetValue(SkipLastMarginProperty, value);
}
public static bool GetSkipLastMargin(DependencyObject element)
{
return (bool) element.GetValue(SkipLastMarginProperty);
}
}
}
使用System.Windows;
使用System.Windows.Controls;
命名空间NetworkMonitor.Framework.Controls.Extensions
{
公共类面板扩展
{
公共静态只读DependencyProperty ChildMarginProperty=DependencyProperty.RegisterAttached(
“ChildMargin”、typeof(厚度)、typeof(面板扩展)、新UIPropertyMetadata(新厚度()、ChildMarginChanged));
私有静态无效ChildMarginChanged(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
如果(d是面板)
{
panel.Loaded+=panel OnLoaded;
}
}
已加载专用静态无效面板(对象发送器,路由目标e)
{
如果(发送器为面板)
{
面板已加载-=面板已加载;
var itemsMargin=GetChildMargin(面板);
var skipLast=GetSkipLastMargin(面板);
对于(int i=0;i
Generic.xaml
<Style TargetType="{x:Type local:ToolbarPanel}">
<Setter Property="Padding" Value="8"></Setter>
<Setter Property="ItemsSpacing" Value="0,0,8,0"></Setter>
<Setter Property="BorderThickness" Value="0,1,0,0"></Setter>
<Setter Property="BorderBrush" Value="Black"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ToolbarPanel}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}" >
<StackPanel Orientation="Horizontal"
IsItemsHost="True"
extensions:PanelExtensions.ChildMargin="{TemplateBinding ItemsSpacing}"
extensions:PanelExtensions.SkipLastMargin="True">
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我看不到StackPanel
。为什么不从ItemsControl派生?@Sinatr是的。示例指出,即使使用ItemsControl,我似乎也无法通过分配给此面板的控件。使用StackPanel执行此操作将是我的理想解决方案。@Clemens,因为我不希望继承ItemsControl的属性。我想要的只是没有属性的StackPanel的行为。为什么不直接从StackPanel继承自定义控件?
using System.Windows;
using System.Windows.Controls;
namespace NetworkMonitor.Framework.Controls.Extensions
{
public class PanelExtensions
{
public static readonly DependencyProperty ChildMarginProperty = DependencyProperty.RegisterAttached(
"ChildMargin", typeof(Thickness), typeof(PanelExtensions), new UIPropertyMetadata(new Thickness(), ChildMarginChanged));
private static void ChildMarginChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Panel panel)
{
panel.Loaded += PanelOnLoaded;
}
}
private static void PanelOnLoaded(object sender, RoutedEventArgs e)
{
if (sender is Panel panel)
{
panel.Loaded -= PanelOnLoaded;
var itemsMargin = GetChildMargin(panel);
var skipLast = GetSkipLastMargin(panel);
for (int i = 0; i < panel.Children.Count; i++)
{
if (skipLast && i == (panel.Children.Count - 1))
break;
var child = panel.Children[i];
if (child is FrameworkElement frameworkElement)
{
frameworkElement.Margin = itemsMargin;
}
}
}
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = true)]
[AttachedPropertyBrowsableForType(typeof(Panel))]
public static void SetChildMargin(DependencyObject element, Thickness value)
{
element.SetValue(ChildMarginProperty, value);
}
[AttachedPropertyBrowsableForChildren(IncludeDescendants = true)]
[AttachedPropertyBrowsableForType(typeof(Panel))]
public static Thickness GetChildMargin(DependencyObject element)
{
return (Thickness) element.GetValue(ChildMarginProperty);
}
public static readonly DependencyProperty SkipLastMarginProperty = DependencyProperty.RegisterAttached(
"SkipLastMargin", typeof(bool), typeof(PanelExtensions), new PropertyMetadata(true));
public static void SetSkipLastMargin(DependencyObject element, bool value)
{
element.SetValue(SkipLastMarginProperty, value);
}
public static bool GetSkipLastMargin(DependencyObject element)
{
return (bool) element.GetValue(SkipLastMarginProperty);
}
}
}
<Style TargetType="{x:Type local:ToolbarPanel}">
<Setter Property="Padding" Value="8"></Setter>
<Setter Property="ItemsSpacing" Value="0,0,8,0"></Setter>
<Setter Property="BorderThickness" Value="0,1,0,0"></Setter>
<Setter Property="BorderBrush" Value="Black"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ToolbarPanel}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}" >
<StackPanel Orientation="Horizontal"
IsItemsHost="True"
extensions:PanelExtensions.ChildMargin="{TemplateBinding ItemsSpacing}"
extensions:PanelExtensions.SkipLastMargin="True">
</StackPanel>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>