在可重用WPF控件中使用已命名

rslzwgfq  于 2022-12-14  发布在  其他
关注(0)|答案(1)|浏览(203)

我最近在WPF中发现了“可重用控件”,我有一个项目,它们似乎为我提供了一个问题的解决方案。
让我概述一下情况:我需要做几个UI元素,它们都有一个共同的基础,比如说一个共同的样式/布局/模板,它们也有一些共同的逻辑。
除此之外,所有这些元素都有一些特定于元素的东西。
您可以说我在这里有某种继承,但是对于XAML和CS都是如此。
我想解决这个问题的方法是通过创建一个外部可重用元素,我做了一个小例子。公共部分是Title标签和边框。然后可以将特定于元素的UI插入到UserContent中。
代码如下所示(虽然为了简洁起见,代码被简化了,但在我的实际应用程序中,我还有一个eventhandler和一个routed事件):

可重用控件.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>

可重用控件. 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));
    }
}

可爱的是,我现在可以在代码的其他部分使用我的特殊控件,并且可以将任何我想要的内容插入到UserContent字段中。

主窗口.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>

这样做效果很好,但是当我开始命名东西时,问题就出现了。简单地给我的ReusableControl中的元素添加一个名称会导致编译错误。

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

出现以下错误:
MC 3093-无法在元素“Rectangle”上设置Name属性值“LolWhatAmIDoing.”“Rectangle”位于元素“ReusableControl”得范围内,该元素在另一个范围中定义时已注册了名称.
这看起来是个小问题,但我找不到解决这个问题的简单方法。
我在论坛上找到了this的帖子,但是它并没有提供一个解决方案。因为我对这一切都很陌生,所以我也不知道这个问题是什么,所以如果我React迟钝的话,我很抱歉。
是否应移至CustomControls?

flvlnr44

flvlnr441#

您显示的是一个简单的属性赋值:将Rectangle类型的值设置为ReusableControl.UserContent属性。此时,必须了解Rectangle不是可视树的一部分。它是一个简单的属性值,只能通过属性访问,而不能通过可视树访问。
这一切都发生在MainWindow的范围内。
Rectangle不是此范围的成员。ReusableControl通过将ReusableControl.UserContent的值绑定到ContentControl,将其添加到自己的可视子树或范围。这是Rectangle存在的位置,即呈现在可视树中的位置。
它实际上并不存在于MainWindow的作用域中。它实际上只存在于ContentControl的“shape”中的ReusableControl中。这意味着ReusableControl的作用域是唯一可以为子元素注册名称的名称作用域。它也是唯一可以直接引用它的作用域(如果它已经在此作用域中定义并注册)。
如果您理解了这一点,那么您就理解了Rectangle当前正试图在错误的作用域中注册一个名称,在这个作用域中它并不存在。
因此,不能在MainWindow的作用域中直接引用它,必须深入到UserControlContentTemplate(它是一个ContentControl)中,才能获得实际承载Rectangle的嵌套ContentControl

相关问题