用户控件和ContentControl之间有什么区别?

时间:2013-09-13 08:27:54

标签: wpf user-controls subclass

更新

正如标记的答案所示,Reflector确认UserControl会覆盖一些方法,因此虽然两者之间的界面完全相同,并且您可以使用VS设计器,但行为上存在细微差别。我会让读者更多地研究这些差异,但这里是子类代码......

public class UserControl : ContentControl
{
    // Fields
    private static DependencyObjectType _dType;

    // Methods
    static UserControl()
    {
        FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(UserControl), new FrameworkPropertyMetadata(typeof(UserControl)));
        _dType = DependencyObjectType.FromSystemTypeInternal(typeof(UserControl));
        UIElement.FocusableProperty.OverrideMetadata(typeof(UserControl), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
        KeyboardNavigation.IsTabStopProperty.OverrideMetadata(typeof(UserControl), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
        Control.HorizontalContentAlignmentProperty.OverrideMetadata(typeof(UserControl), new FrameworkPropertyMetadata(HorizontalAlignment.Stretch));
        Control.VerticalContentAlignmentProperty.OverrideMetadata(typeof(UserControl), new FrameworkPropertyMetadata(VerticalAlignment.Stretch));
    }

    internal override void AdjustBranchSource(RoutedEventArgs e)
    {
        e.Source = this;
    }

    protected override AutomationPeer OnCreateAutomationPeer()
    {
        return new UserControlAutomationPeer(this);
    }

    // Properties
    internal override DependencyObjectType DTypeThemeStyleKey
    {
        [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        get
        {
            return _dType;
        }
    }

    internal override FrameworkElement StateGroupsRoot
    {
        get
        {
            return (base.Content as FrameworkElement);
        }
    }
}

原始问题:

根据所有文档,当您创建一个非外观控件时,您应该将UserControl子类化。但是,UserControlContentControl的一个简单子类,但它似乎没有向接口添加任何内容。因此,您可以使用设计器生成的代码并将基类更改为ContentControl,它似乎仍然完全相同。

那么UserControlContentControl的重点是什么?

更新:对于那些一直在回答VS的人来说,对待他们的方式不同,我认为事实并非如此。试试吧。在Visual Studio中创建一个新的UserControl。然后在生成的XAML文件中,将根标记更改为ContentControl。然后在关联的类文件中,将基类更改为ContentControl。它似乎完全相同,包括完全所见即所得的设计师支持。

这是更新后的XAML ......

<ContentControl x:Class="Playground.ComboTest.InlineTextEditor"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <TextBlock Text="Success" />

</ContentControl>

...以及相关的类文件......

using System.Windows.Controls;

namespace Playground.ComboTest
{
    public partial class InlineTextEditor : ContentControl
    {
        public InlineTextEditor()
        {
            InitializeComponent();
        }
    }
}

6 个答案:

答案 0 :(得分:22)

当您不需要向消费者提供ControlTemplate时,UserControl非常适合聚合现有控件。这意味着 UserControls看起来并不像。为什么不使用ContentControl,因为它可以像UserControl一样耦合XAML,实现看起来类似于UserControl?那么,您必须知道几个重要的技术差异:

  1. UserControls将自己设置为由其中的元素引发的RoutedEvents 的源。这意味着当UserControl外部的元素收到冒泡事件时,Source是UserControl,而不是您在 UserControl中交互的内容。在您经常听到的关于UserControls的哲学意义上,&#34; 它用于聚合现有控件&#34;,这是有意义的,因为您希望父容器元素能够考虑您的UserControl作为一个单元。例如,您的UserControl包含用户单击的按钮,包含UserControl实例的Grid接收MouseLeftButtonUp事件,但Button不是事件的来源,您的UserControl是。
  2. UserControl将Focusable和IsTabStop设置为false 。你可以在这里看到再次证明自己的哲学,因为我们不希望将现有控件分组为可聚焦。
  3. UserControl将Horizo​​ntalAlignment和VerticalAlignment设置为Stretch 。 ContentControl将自动设置为Left和Top。
  4. UserControl自己的AutomationPeer implementation允许您通过 VisualStateManager.GoToState()更改VisualStates。 ContentControl要求VisualStateGroups位于顶层,您必须使用VisualStateManager.GoToElementState()调用它们。
  5. UserControl自己的ControlTemplate将您的内容包装在Border 中。在考虑UserControl的哲学用例时,这又有意义。
  6. UserControl自己的ControlTemplate比ContentControl提供更多的TemplateBindings 。这是对上述一些项目的概括,但解释了它们是如何可能的。回想一下,UserControl提供了一个Border,这与你在下面看到的一些免费TemplateBinding相关。这样可以控制控件上的BorderBrush,BorderThickness,Background和Padding属性,否则这些属性只能用于ContentControl。例如,如果您只是从ContentControl派生控件并在根ContentControl元素上设置Background属性,则它将无法工作,因为ContentControl的ControlTemplate没有用于Background的TemplateBinding。当然,您可以在包含所需元素的子内容元素上设置Background属性,例如Grid,但这不是理想的IMO。
  7.   

    ContentControl的ControlTemplate

    <ControlTemplate TargetType="ContentControl">
      <ContentPresenter
       Content="{TemplateBinding ContentControl.Content}"
       ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
       ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}" />
    </ControlTemplate>
    
      

    UserControl的ControlTemplate

    <ControlTemplate TargetType="UserControl">
      <Border BorderBrush="{TemplateBinding Border.BorderBrush}"
       BorderThickness="{TemplateBinding Border.BorderThickness}"
       Background="{TemplateBinding Panel.Background}"
       Padding="{TemplateBinding Control.Padding}"
       SnapToDevicePixels="True">
        <ContentPresenter
         HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
         VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
         SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"
         ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
         ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
         Content="{TemplateBinding ContentControl.Content}" />
      </Border>
    </ControlTemplate>
    

答案 1 :(得分:7)

基本上,UserControl类是为了方便起见。它使我们能够从已有的控件构建UI的一小部分,而ContentControl实际上是用于创建新控件,通常只有一个目的和/或功能。

我读了一本书,对此有一个很好的解释,祝你好运,有人'在网上发了一份'。从链接的书中:

  

UserControl类是一个容器类,充当集合的“黑盒子”容器   相关控制。如果您需要一组三个控件始终一起显示   被允许轻松地互相交谈,然后一个可能的候选人来实现这一点   UserControl类。

然后是否要创建CustomControl

  

以下是决策过程的摘要:

     

尽可能使用框架。 WPF提供了各种可扩展的功能   控件,因此请确保您所需的功能尚不存在于   WPF控制。

     

在许多情况下,您正在使用的数据结构需要不同的可视化表示。   使用ControlTemplates和DataTemplates通常可以为您提供功能   你需要。

     

看看ValueConverters是否可以帮助弥合之间的差距   库存功能和您需要的东西。

     

最后,看看您是否无法使用附加属性扩展现有行为。

深入了解您的问题:

WPF Control Development Unleashed

更新&gt;&gt;&gt;

@MarqueIV,更直接地回答您的问题:为方便起见,我们提供了UserControl课程。而已。如果将WPF CustomControl添加到项目中,您将看到它没有XAML文件。这意味着您必须在Generic.xaml文件夹中名为Themes的文件中设计控制标记。 UserControl类为我们提供了一个XAML文件,因此更容易创建它们......所以它更方便......就是这样。这就是原因。

答案 2 :(得分:3)

ContentControl不同的一点是,UserControl会覆盖OnCreateAutomationPeer方法,您可能会寻找它。也许它有一些不同于ContentControl的UI行为。

此方法会创建UserControlAutomationPeer-instance

答案 3 :(得分:1)

<强> ContentControl中
ContentControl直接派生自Control类 它托管一个单独的元素,可以是一个容器(例如Grid,Stackpanel,......),它自己托管几个元素(例如StackPanel with TextBlock和Image children)。
它的外观可以通过DataTemplate修改 请参阅MSDN Remarks section

<强>用户控件
UserControl派生自ContentControl 它不支持模板,因此无需定制 它不像Window那样自动捕捉焦点 仍然在MSDN Remarks section

答案 4 :(得分:0)

UserControl是一个复合控件。它与ASP.NET Webforms中的UserControl具有类似的概念。这意味着它是一个由许多控件组成的控件。在WPF中,创建用户控件支持Visual Studio 2008及更高版本中的设计器。 ContentControl是一个控件,旨在将单个控件作为其内容。

了解更多信息: http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.aspx

答案 5 :(得分:0)

UserControl和ContentControl可能是相同的实现,但用例不一样。

我们需要回答两个问题何时使用UserControl或CustomControl?何时使用ContentControl?

所以何时使用UserControl或CustomControl? <
每当我想要一个可重用的UI 时 例如,如果我想让FileDialogBrowser意味着一个带有TextBlock的按钮,那么每当我按下按钮并且用户选择一个文件时,我将在TextBlock中显示所选文件。

相同但不完全适用于customControl但是在这里我们想做更复杂的事情,无论如何这不是问题。

所以何时使用ContentControl?

这说起来有点棘手,但让我们说我们想要一个带有消息的progressBar 所以我们可以继承BusyIndi​​cator或Border,但是如果我们使用ContentControl,我们就可以控制它内部的内容。我们可以将它包裹在其他xaml元素周围。

希望这会有所帮助