WPF - 如何将其他控件传递到我的 UserControl 中?

发布于 2024-11-25 13:07:14 字数 253 浏览 1 评论 0原文

基本上,我希望我的 UserControl 能够接受某种类型的 ItemsControl,以便我的 XAML 可以如下所示:

<my:MyControl DataContext="{Binding InnerViewModel}">
    <ItemsControl ... />
</my:MyControl>

这样,MyControl 将显示自定义 Items 控件以及其他控件吗?

Basically, I want my UserControl to be able to take in a type of ItemsControl so that my XAML can look like this:

<my:MyControl DataContext="{Binding InnerViewModel}">
    <ItemsControl ... />
</my:MyControl>

That way, the MyControl displays the custom Items control along with other controls?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

荒芜了季节 2024-12-02 13:07:14

首先需要注意几点:

  1. UserControlContentControl。这意味着您不能将子元素传递到 UserControl 中。您可以覆盖内容,但这对于您想要完成的任务来说是徒劳的。
  2. 如果您想要一个包含 SINGLE 子元素的控件,则需要寻找 装饰器类。
  3. 如果您想要一个包含MULTIPLE子元素的控件,您需要寻找ItemsControl 类。

所以,基本上你做错了。话虽如此,有几种方法可以实现您想要的目标。您可以简单地使用 ItemsControl 并使用您自己的模板覆盖模板。您还可以创建一个继承自 ItemsControl 或 Decorator 的 CustomControl。

重写模板(作为一种样式)将是更简单的方法,因此我的建议是这样做,除非您非常精通如何正确创建 WPF 自定义控件。

如果您选择使用自定义控件,那么看起来您可能会想要作为装饰者这样做(只是猜测您在这里想要一个孩子)。令人烦恼的是,要真正创建编写良好的 WPF 自定义控件,您必须具备一些非常好的技能。例如,Border 是一种装饰器类型,包含一些 DependencyProperty 属性。该模板附带了PresentationFramework.dll(我认为),因此它具有一些默认的外观。边框(自定义控件)编写起来并不困难。当你想要真正拥有交互逻辑时,会变得非常烦人。您需要进行检查和平衡,以确保从模板中检索控件引用。然后,只有到那时,如果引用不为空,您才能继续执行您的逻辑。基本上,假设您编写了一种具有 2 个按钮来执行逻辑的自定义控件,并且您提供了一个默认模板,其中按钮名为“按钮 1”和“按钮 2”。您不能只是从模板中拉出按钮 1 和按钮 2 并期望它们在那里;有人可以轻松覆盖您的默认模板并删除按钮 1 和按钮 2,从而使您的自定义控件毫无用处(几乎)。如果你在编码时没有考虑到这些情况,那么事情就会变得很糟糕。您的自定义控件将遇到 NullReferenceException。更不用说您必须进行连接以允许命令绑定每个按钮,并且您还应该为每个按钮提供一个路由事件。基本上,自定义控件对于您想要做的事情可能有点太多了(可能)。

我可能是错的,您可能非常熟练并且知道如何制作自定义控件。或者,更好的是,您可能只是想要一种简单的方法来装饰您的 ItemsControl,例如在其顶部添加横幅?我不知道,但我确信您知道:)


总的来说,我会看看如何覆盖 ItemsControl 模板。这是一个示例:

<Window x:Class="Sample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480">
    <Window.Resources>
        <Style x:Key="ItemsControlStyle1" TargetType="{x:Type ItemsControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ItemsControl}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                            <StackPanel Orientation="Vertical">
                                <TextBlock Text="A HEADER!" />
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <ItemsControl Style="{DynamicResource ItemsControlStyle1}" />
    </Grid>
</Window>

A couple of notes first:

  1. A UserControl is a type of ContentControl. This means that you can not pass a child element into the UserControl. You can override the content, but that would be fruitless for what you want to accomplish.
  2. If you want a control that contains a SINGLE child element, you're looking for a Decorator class.
  3. If you want a control that contains MULTIPLE child elements, you're looking for a ItemsControl class.

So, basically you're doing it incorrectly. That being said, there are a couple of ways of accomplishing what you want. You could simply use an ItemsControl and override the Template with your own template. You could also create a CustomControl that inherits from ItemsControl or Decorator.

Overriding the template (as a style) will be the easier way to do it, so my suggestion is to do that, unless you're very well-versed in how to create a WPF custom control properly.

If you opt to go for a custom control, it looks like you're probably going to want to do so as a Decorator (just guessing that you'd want a single child here). The annoying part is that to truly create a well-written WPF custom control you'll have to have some really good skills. For example, Border is a type of Decorator that contains a few DependencyProperty properties. The template ships with the PresentationFramework.dll (I think) so that it has some default look-and-feel to it. A border (custom control) is not that difficult to write. What gets very annoying is when you want to actually have interaction logic. You'll need to put in checks and balances to ensure that you retrieve the control references from the template. Then, and only then, if the references are not null can you proceed onto your logic. Basically, say you wrote a type of custom control that has 2 buttons to perform logic, and you provided a default template where the buttons are named "Button 1" and "Button 2". You can't just pull Button 1 and Button 2 from the template and expect them to be there; someone could easily override your default template and remove Button 1 and Button 2, rendering your custom control useless (pretty much). What makes it terrible is if you coded without accounting for these situations. You're custom control will run into NullReferenceExceptions. Not to mention that you'll have to wire things up to allow for command binding PER button and you should also provide a routedevent for each button. Basically, a custom control might be a bit too much for what you want to do (possibly).

I could be wrong, you might be super skilled and know how to crank out custom controls. Or, better yet, you might have just wanted a simple way to decorate your ItemsControl by say, adding a banner to the top of it? I don't know, but I'm sure you do :)


Overall, I'd look at how to override the ItemsControl template. Here's a sample:

<Window x:Class="Sample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="640" Height="480">
    <Window.Resources>
        <Style x:Key="ItemsControlStyle1" TargetType="{x:Type ItemsControl}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ItemsControl}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                            <StackPanel Orientation="Vertical">
                                <TextBlock Text="A HEADER!" />
                                <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </StackPanel>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <ItemsControl Style="{DynamicResource ItemsControlStyle1}" />
    </Grid>
</Window>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文