如何通過用戶的 XAML 將控件動態添加到 UserControl

更新時間:2024-03-11 13:44:15

問題闡述

我想創建一個包含 TextBlock 和 St🀅ackPanel 的用戶控件,允許用戶在 XAML 中動態地將他/她自己的控件添加到用戶控件中.

這是我的 UserControl 的示例 XAML:

<UserControl x:Class="A1UserControlLibrary.UserControlStackPanel"
             xmlns="//schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="//schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="//schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="//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 執行此操作不起作用.有什么想法嗎?

精準答案

可以這樣做,雖然不像你的例子完全.你需要兩件事.第一種是聲明一個UIElement類型的DependencyProperty,所有控件都擴展它:

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>

在我看來,如果您使用 StackPanels,您可能會發現您的內容無法正確顯示...我建議您使用 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();
}

僅此而已.