简体   繁体   中英

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.

Let me sketch the situation: I need to make several UI elements. 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.

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. The element-specific UI can then be inserted into 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

<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

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.

MainWindow.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.

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

I get the following error:

MC3093 - Cannot set Name attribute value 'LolWhatAmIDoing' on element 'Rectangle'. 'Rectangle' is under the scope of element 'ReusableControl', which already had a name registered when it was defined in another 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?

What you show is a simple property assignment: you set the value of type Rectangle to the property ReusableControl.UserContent . It's important to understand that the Rectangle is not part of the visual tree at this point. 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 .

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 . This is were the Rectangle exists ie is rendered in the visual tree.

It effectively doesn't exist in the scope of MainWindow . It effectively only exists inside the ReusableControl in the "shape" of a ContentControl . This means that the scope of ReusableControl is the only name scope where you can register a name for child elements. It's also the only scope where you can directly reference it (if it had been defined and registered in this 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.

As a consequence, you cannot directly refer to it in the scope of MainWindow . 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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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