如何通过用户的XAML动态向UserControl添加控件?

6

我希望创建一个用户控件,其中包含一个TextBlock和一个StackPanel,允许用户在XAML中动态添加自己的控件。

这是我的UserControl的示例XAML:

<UserControl x:Class="A1UserControlLibrary.UserControlStackPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             d:DesignHeight="200" d:DesignWidth="300">
    <StackPanel>
        <TextBlock Text="I want the user to be able to add any number of controls to the  StackPanel below this TextBlock."
                   FontFamily="Arial" FontSize="12" FontWeight="DemiBold" Margin="5,10,5,10" TextWrapping="Wrap"/>
        <StackPanel>
            <!-- I want the user to be able to add any number of controls here -->
        </StackPanel>
    </StackPanel>
</UserControl>

我希望用户能够在XAML中嵌入此用户控件,并将其自己的控件添加到该用户控件的堆栈面板中。
<uc:A1UserControl_StackPanel x:Name="MyUserControl_Test" Margin="10" Height="100">
    <Button Name="MyButton1" Content="Click" Height="30" Width="50"/>
    <Button Name="MyButton2" Content="Click" Height="30" Width="50"/>
    <Button Name="MyButton3" Content="Click" Height="30" Width="50"/>
</uc:A1UserControl_StackPanel>

使用上述XAML无法实现此操作。有任何想法吗?

我不相信你可以在XAML中这样做...除非我误解了你的例子。 - rae1
在代码后台有没有办法做到这一点? - PeterBuilt
1个回答

7
你可以这样做,虽然不完全像你的示例。你需要两个东西。第一个是声明一个DependencyProperty,其类型为UIElement,所有控件都会继承它:
public static DependencyProperty InnerContentProperty = DependencyProperty.Register("InnerContent", typeof(UIElement), typeof(YourControl));

public UIElement InnerContent
{
    get { return (UIElement)GetValue(InnerContentProperty); }
    set { SetValue(InnerContentProperty, value); }
}

第二步是在您希望内容出现的XAML中声明一个ContentControl
<StackPanel>
    <TextBlock Text="I want the user to be able to add any number of controls to the  StackPanel below this TextBlock."
               FontFamily="Arial" FontSize="12" FontWeight="DemiBold" Margin="5,10,5,10" TextWrapping="Wrap"/>
    <StackPanel>
        <ContentControl Content="{Binding InnerContent, RelativeSource={RelativeSource AncestorType={x:Type YourXmlNamspacePrefix:ContentView}}}" />
    </StackPanel>
</StackPanel>

在我看来,如果你使用 StackPanel,你可能会发现你的内容无法正确显示...... 我建议你在除了最简单的布局任务之外,使用 Grid 来进行布局。
现在与你的例子不同的一点是如何使用你的控件。 InnerContent 属性的类型为 UIElement,这意味着它只能包含一个 UIElement。这意味着你需要使用一个容器元素来显示多个项目,但它具有相同的最终结果:
<YourXmlNamspacePrefix:YourControl>
    <YourXmlNamspacePrefix:YourControl.InnerContent>
        <StackPanel x:Name="MyUserControl_Test" Margin="10" Height="100">
            <Button Content="Click" Height="30" Width="50"/>
            <Button Content="Click" Height="30" Width="50"/>
            <Button Content="Click" Height="30" Width="50"/>
        </StackPanel>
    </YourXmlNamspacePrefix:YourControl.InnerContent>
</YourXmlNamspacePrefix:YourControl>

结果如下:

输入图片说明


更新 >>>

为了记录,我知道你想做什么。而你似乎不理解我说的话,所以我会再给你讲一遍。按照我之前已经向你展示的方式,添加一个Button并设置Tag属性:

<Button Tag="MyButton1" Content="Click" Click="ButtonClick" />

现在添加一个 Click 处理程序:
private void ButtonClick(object sender, RoutedEventArgs e)
{
    Button button = (Button)sender;
    if (button.Tag = "MyButton1") DoSomething();
}

这就是全部内容了。

谢谢!我在想可能需要某种内容属性,但我不确定该如何处理。 - PeterBuilt
你的解决方案很好。不过我有一个问题。如果我尝试给我嵌入在用户控件中的控件之一命名(例如将其中一个按钮命名为MyButton1),我会收到一个错误:“错误1:无法在元素“Button”上设置名称属性值“MyButton1”。'Button'处于元素'A1UserControl_Dynamic'的范围内,在定义另一个范围时已经注册了名称。” - PeterBuilt
似乎有一个小错误(https://connect.microsoft.com/VisualStudio/feedback/details/483024/wpf-error-message-cannot-set-name-attribute-value-0-on-element-1-1-is-under-the-scope-of-element-2-which-already-had-a-name-registered-when-it-was-defined-in-another-scope)... 最简单的解决方案就是使用“Tag”属性来标识它们:<Button Tag="Button1" ... />。 - Sheridan
什么????使用Tag属性就像它是Name属性一样:button.Tag =“Some name”<Button Tag =“Button1”.../> - Sheridan
天啊,不是这个意思。我只是向你展示了两种设置名称到“Tag”属性的方法。你的原始代码是这样的:<Button Name="MyButton1" Content="Click" Height="30" Width="50"/>。我想说的是你可以这样做:<Button Tag="MyButton1" Content="Click" Height="30" Width="50"/>。请继续自己的发现。 - Sheridan
显示剩余6条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接