C# 如何将控件转发到自定义控件中的stackpanel?

C# 如何将控件转发到自定义控件中的stackpanel?,c#,wpf,C#,Wpf,我正在尝试创建一个自定义控件,它可以简化整个应用程序中工具栏的外观。不幸的是,我似乎找不到一种方法将孩子们从我的控件转发到底层的stackpanel。我试图通过使用ItemsControl来解决这个问题,但它似乎也不起作用 我采用的另一种方法是在ToolbarPanel中使用OnApplyTemplate,但这似乎也不起作用 有人知道如何让控制转发在这里工作吗? 工具栏面板.cs Generic.xaml 多亏了@Clemens,我终于想出了一个有效的方法。之前尝试失败的关键因素是我没有使用It

我正在尝试创建一个自定义控件,它可以简化整个应用程序中工具栏的外观。不幸的是,我似乎找不到一种方法将孩子们从我的控件转发到底层的stackpanel。我试图通过使用ItemsControl来解决这个问题,但它似乎也不起作用

我采用的另一种方法是在ToolbarPanel中使用OnApplyTemplate,但这似乎也不起作用

有人知道如何让控制转发在这里工作吗? 工具栏面板.cs Generic.xaml
多亏了@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>