Neem even de volgende code. Het is een standaard WPF Window met een Grid en een Button in de Grid.
<Window x:Class="NameScopeTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid Name="myGrid" >
<Button Name="myButton"/>
</Grid>
</Window>
Niet echt spannend, zou ik denken. Nou heb ik echter in mijn code een eigen container nodig, om redenen die er even niet toe doen. Ik heb daarvoor een UserControl gemaakt en die ziet er als volgt uit
XAML:
<UserControl x:Class="NameScopeTest.MyContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<!-- This will hold the child controls -->
<StackPanel Orientation="Horizontal" Name="myStackPanel"/>
</Grid>
</UserControl>
En de bijbehorende C# class:
using System;
using System.Windows.Controls;
namespace NameScopeTest
{
/// <summary>
/// Interaction logic for MyContainer.xaml
/// </summary>
public partial class MyContainer : UserControl
{
public UIElementCollection Children { get; set; }
public MyContainer()
{
this.Children = new UIElementCollection(this, this);
InitializeComponent();
}
}
}
In de Window1 XAML file krijg je dan het volgende:
<Window x:Class="NameScopeTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myStuff="clr-namespace:NameScopeTest"
Title="Window1" Height="300" Width="300">
<Grid Name="myGrid" >
<myStuff:MyContainer>
<Button />
</myStuff:MyContainer>
</Grid>
</Window>
Tot zover geen enkel probleem. Ik heb een namespace reference toegevoegd en vervolgens mijn MyContainer met daarin een Button in de Grid gezet. Het verschil met de eerste xaml file is dat ik in het eerste voorbeeld de elementen een naam gegeven hebt.
Aangezien MyContainer afgeleid is van UserControl hebben we de Name property. Dus die kunnen we zetten, en ook op de button doen we dat gelijk maar even:
<Window x:Class="NameScopeTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myStuff="clr-namespace:NameScopeTest"
Title="Window1" Height="300" Width="300">
<Grid Name="myGrid" >
<myStuff:MyContainer Name="myContainer" >
<Button Name="myButton"/>
</myStuff:MyContainer>
</Grid>
</Window>
Compile, en. helaas. Dit gaat dus niet. Visual Studio geeft me een hele mooie foutmelding:
Error 1 Because 'MyContainer' is implemented in the same assembly, you must set the x:Name attribute rather than the Name attribute. Line 7 Position 30. C:\Users\Dennis\Documents\Visual Studio 2008\Projects\NameScopeTest\NameScopeTest\Window1.xaml 7 30 NameScopeTest
We krijgen te horen dat we niet de Name property moeten gebruiken maar de x:Name. Deze twee zijn verschillend, maar functioneel doen ze min of meer hetzelfde (x:Name is de instance name van het object dat je maakt, net zoals je in de code behind je variabele een naam geeft. Name is echter een DependencyProperty. Nogmaals: functioneel zijn ze vrijwel gelijk).
Ok, dan passen we de code aan en vervangen we <myStuff:MyContainer Name="myContainer"> door <myStuff:MyContainer x:Name="myContainer">
Compile en. nee. Nog steeds niet:
Error 1 Cannot set Name attribute value 'myButton' on element 'Button'. 'Button' is under the scope of element 'MyContainer', which already had a name registered when it was defined in another scope. Line 8 Position 21. C:\Users\Dennis\Documents\Visual Studio 2008\Projects\NameScopeTest\NameScopeTest\Window1.xaml 8 21 NameScopeTest
WTF? Na lang zoeken blijkt dat dit standaard gedrag is. Een UserControl met een XAML erbij kan geen named-child elementen bevatten. Lastig, erg lastig. De oplossing? Geen UserControl als baseclass gebruiken maar Control. En dan de rendering zelf regelen.
Dit werkt dan wel, maar het is wel veel lastiger (je moet nu alles wat je eerst in de XAML van je usercontrol deed zelf doen in de OnRender()). Ik snap niet goed wat de reden van deze beperking is, maar er zal wel over nagedacht zijn Weet iemand de reden voor dit alles?