简体   繁体   English

在可重用的 WPF 控件中使用 named

[英]Using named in reusable WPF control

I recentrly discovered "reusable controls" in WPF and I have a project where they seem to provide me with a solution to a problem I have.我最近在 WPF 中发现了“可重复使用的控件”,我有一个项目,它们似乎为我提供了解决我遇到的问题的方法。

Let me sketch the situation: I need to make several UI elements.让我描述一下情况:我需要制作几个 UI 元素。 All of them share a common base, a common style/layout/template let's say, and they also share some common logic.它们都共享一个共同的基础,可以说是一个共同的样式/布局/模板,并且它们还共享一些共同的逻辑。

Next to that, all of these elements have some element-specific stuff.除此之外,所有这些元素都有一些特定于元素的东西。

You could say that I have some kind of inheritance here, but then for both XAML and CS.你可以说我这里有某种 inheritance,但是对于 XAML 和 CS。

The way I wanted to solve this, was by making an outer reusable element, I made a small example.我想解决这个问题的方法是制作一个外部可重用元素,我做了一个小例子。 The common part Is the Title label and the border.公共部分是Title label 和边框。 The element-specific UI can then be inserted into UserContent .然后可以将特定于元素的 UI 插入到UserContent中。

The code looks something like this (although it's simplified for the sake of brevity and conciseness, I also have an eventhandler and a routed event in my actual application):代码看起来像这样(尽管为了简洁起见进行了简化,但我在实际应用程序中也有一个事件处理程序和一个路由事件):

ReusableControl.xaml ReusableControl.xaml

<UserControl x:Class="StackOverflowQuestion4.ReusableControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             x:Name="root">

    <Border BorderBrush="Black"
            BorderThickness="1"
            Width="400"
            Height="200">
        
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            
            <Label Content="{Binding Title, ElementName=root}" 
                   Grid.Row="0"/>

            <ContentControl Content="{Binding UserContent, ElementName=root}"
                            Grid.Row="1"/>

        </Grid>
    </Border>

</UserControl>

ReusableControl.xaml.cs ReusableControl.xaml.cs

using System.Windows;
using System.Windows.Controls;

namespace StackOverflowQuestion4
{
    public partial class ReusableControl : UserControl
    {
        public ReusableControl()
        {
            InitializeComponent();
        }

        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(ReusableControl), new PropertyMetadata(string.Empty));

        public object UserContent
        {
            get { return GetValue(UserContentProperty); }
            set { SetValue(UserContentProperty, value); }
        }

        public static readonly DependencyProperty UserContentProperty =
            DependencyProperty.Register("UserContent", typeof(object), typeof(ReusableControl), new PropertyMetadata(string.Empty));
    }
}

Lovely, I can now use my special control in other parts of my code, and I can insert whatever I want into the UserContent field.太棒了,我现在可以在代码的其他部分使用我的特殊控件,并且可以将我想要的任何内容插入到UserContent字段中。

MainWindow.xaml主窗口.xaml

<Window x:Class="StackOverflowQuestion4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:StackOverflowQuestion4"
        mc:Ignorable="d"
        Title="MainWindow"
        SizeToContent="WidthAndHeight">
    
    <Grid Width="800"
          Height="600">
        
        <local:ReusableControl Title="Test">
            <local:ReusableControl.UserContent>
                <Rectangle Width="300"
                           Height="100"
                           Fill="Blue"/>
            </local:ReusableControl.UserContent>
        </local:ReusableControl>
        
    </Grid>
    
</Window>

This works great, but the problem arises when I start to name things.这很好用,但是当我开始给事物命名时,问题就出现了。 Simply adding a name to an element inside of my ReusableControl causes a compilation error.简单地向ReusableControl中的元素添加名称会导致编译错误。

<Rectangle Width="300"
           Height="100"
           Fill="Blue"
           Name="LolWhatAmIDoing"/>

I get the following error:我收到以下错误:

MC3093 - Cannot set Name attribute value 'LolWhatAmIDoing' on element 'Rectangle'. MC3093 - 无法在元素“矩形”上设置名称属性值“LolWhatAmIDoing”。 'Rectangle' is under the scope of element 'ReusableControl', which already had a name registered when it was defined in another scope. 'Rectangle' 在元素 'ReusableControl' 的 scope 下,它在另一个 scope 中定义时已经注册了名称。

This seems like such a small issue, but I cannot find an easy solution to this problem.这似乎是一个小问题,但我找不到解决这个问题的简单方法。

I found this thread on the forum, but it does not really provide a solution.我在论坛上找到了这个帖子,但它并没有真正提供解决方案。 Since I'm pretty new to all of this, I also don't really get what the issue is, so apologies if I'm slow minded.由于我对所有这一切都很陌生,所以我也不太明白问题是什么,所以如果我反应迟钝,我深表歉意。

Should I move to CustomControls?我应该转到 CustomControls 吗?

What you show is a simple property assignment: you set the value of type Rectangle to the property ReusableControl.UserContent .您显示的是一个简单的属性分配:您将Rectangle类型的值设置为属性ReusableControl.UserContent It's important to understand that the Rectangle is not part of the visual tree at this point.重要的是要了解Rectangle此时不是可视化树的一部分。 It's a simple property value that is only accessible via the property and not via the visual tree.这是一个简单的属性值,只能通过属性访问,而不能通过可视化树访问。
This all happens in the scope of MainWindow .这一切都发生在MainWindow的 scope 中。

But the Rectangle is not a member of this scope. The ReusableControl is adding it to its own visual subtree or scope by binding the value of ReusableControl.UserContent to a ContentControl .但是Rectangle不是这个 scope 的成员。 ReusableControl通过将ReusableControl.UserContent的值绑定到ContentControl来将它添加到自己的可视子树或 scope 中。 This is were the Rectangle exists ie is rendered in the visual tree.这是Rectangle存在的情况,即在可视化树中呈现。

It effectively doesn't exist in the scope of MainWindow .它实际上不存在于MainWindow的 scope 中。 It effectively only exists inside the ReusableControl in the "shape" of a ContentControl .它实际上仅存在于ContentControl的“形状”中的ReusableControl内部。 This means that the scope of ReusableControl is the only name scope where you can register a name for child elements.这意味着ReusableControl的 scope 是唯一可以为子元素注册名称的名称 scope。 It's also the only scope where you can directly reference it (if it had been defined and registered in this scope).它也是唯一可以直接引用它的 scope(如果它已在此范围内定义和注册)。

If you understand this, then you understand that the Rectangle is currently trying to register a name in the wrong scope, a scope in which it doesn't exist.如果你明白这一点,那么你就明白了Rectangle当前正在尝试在错误的 scope 中注册一个名称,一个它不存在的 scope。

As a consequence, you cannot directly refer to it in the scope of MainWindow .因此,您不能在MainWindow的 scope 中直接引用它。 You would have to dig into the ContentTemplate of the UserControl (which is a ContentControl ) in order to get the nested ContentControl that actually hosts the Rectangle .您必须深入研究UserControlContentTemplate (这是一个ContentControl )才能获得实际承载Rectangle的嵌套ContentControl

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM