Developer's Dump

WPF: Cannot set Name attribute value errror

with 2 comments

When writing a custom user control you might at some point be tempted to use it as an item container. If you then try to name the nested control you will get the following error:

Cannot set Name attribute value 'myControl' on element 'SomeControl'. 'SomeControl' is under the scope of element 'ContentPanel', which already had a name registered when it was defined in another scope.

This is unfortunately a common problem caused solely by the XAML parser.

The easiest solution to overcome this is by constructing the control yourself. I did this by defining my XAML in a resource dictionary and then writing the lines required to load it at runtime. The only downside in this approach is that no designer preview is available.

Here are the 3 easy steps to write a simple container with a title on top:

1. Add a new class (ContentPanel.cs) and a Resource Dictionary (ContentPanel.xaml) to your WPF project.

2. Then write your XAML into the dictionary defining the style for your control:


<ResourceDictionary 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyNamespace">
    <Style TargetType="{x:Type local:ContentPanel}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ContentPanel}">
                    <Grid Background="Transparent">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="18"/>
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Border Grid.Row="0" Background="#FF6C79A2"
CornerRadius="4 4 0 0" Padding="5 3 5 3">
                            <TextBlock VerticalAlignment="Center" Foreground="White" 
Text="{Binding Path=Title, RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type local:ContentPanel}}}"/>
                        </Border>
                        <ContentPresenter Grid.Row="1"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>

3. Finally edit the class so that it inherits from the UserControl class and add a initialize method that will be called by the constructor to load the XAML from the resource dictionary:

    public class ContentPanel: UserControl
    {
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register("Title", typeof(string), typeof(ContentPanel),
new UIPropertyMetadata(""));
        public ContentPanel()
        {
            Initialize();
        }
        private void Initialize()
        {
            ResourceDictionary resources = new ResourceDictionary();
            resources.Source = new Uri("/MyAssemblyName;component/ContentPanel.xaml", 
UriKind.RelativeOrAbsolute);
            this.Resources = resources;
        }
        public string Title
        {
            get { return (string)GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }
    }


The Uri format might seem odd, but just edit my example to define the names of your dll and xaml file.

Don't forget to vote on Microsoft Connect to get Microsoft to fix the XAML parser!

Advertisement

Written by Tom

February 24, 2010 at 00:56

Posted in .NET, WPF

Tagged with , , ,

2 Responses

Subscribe to comments with RSS.

  1. Thanks for nice blog! I think it’s useful.

    Lee2010

    September 9, 2010 at 09:29

  2. Great! This is the only workaround that worked for me

    test87Richard

    November 1, 2011 at 06:31


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.