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