The scenario: Create a MarkupExtension to replace Grid.Row=”0” by Grid.Row=”{namespace:ClassExtension GridRowName}” (same for column)
Xaml Code:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" x:Name="TitleRow" />
<RowDefinition Height="Auto" x:Name="LastNameRow" />
<RowDefinition Height="Auto" x:Name="FirstNameRow" />
<RowDefinition Height="Auto" x:Name="EmailRow" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="LabelColumn" />
<ColumnDefinition x:Name="ValueColumn" />
</Grid.ColumnDefinitions>
<Label Grid.Row="{me:GridDefinition Name=TitleRow}" Grid.ColumnSpan="2" FontWeight="Bold" FontSize="14" />
<Label Grid.Row="{me:GridDefinition Name=LastNameRow}" Grid.Column="{me:GridDefinition Name=LabelColumn}" FontWeight="Bold" FontSize="14" />
</Grid>
The requirement:
- Show XAML Errors when an incorrent GridRowName (or columnName) is used
- Show no XAML errors when a correct GridRowName (or columnName) is used
- When a Valid ColumnName is used for a Row declaration (and vica verca) a XAML error should be shown
The problem:
Everything works fine for Grid.Column, but Grid.Row always throws an “Not Implemented Exception” at designtime (grid.row is underlined, grid.column is not).
The rows and columns are both named correct, but row always shows an error.
If we specify an invalid column name, the column shows an error (which is expected, so Grid.Column works fine!)
As you can see, column works fine, but Rows don’t. The problem lies inside the MarkupExtension called GridDefinitionExtension:
[MarkupExtensionReturnType(typeof(int))]
public class GridDefinitionExtension : MarkupExtension
{
public string Name { private get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
var referenceExt = new Reference(Name);
var definition = referenceExt.ProvideValue(serviceProvider);
if (definition is DefinitionBase)
{
var grid = (definition as FrameworkContentElement).Parent as Grid;
if (grid != null && definition is RowDefinition)
return grid.RowDefinitions.IndexOf(definition as RowDefinition);
if (grid != null && definition is ColumnDefinition)
return grid.ColumnDefinitions.IndexOf(definition as ColumnDefinition);
}
// This Extension only works for DefinitionBase Elements.
throw new NotSupportedException();
}
}
The Exception is trown on the line:
var definition = referenceExt.ProvideValue(serviceProvider);
After looking inside the DLL from which this method is called I have found that the body of this ProvideValue method looks like this:
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (serviceProvider == null)
throw new ArgumentNullException("serviceProvider");
IXamlNameResolver xamlNameResolver = serviceProvider.GetService(typeof (IXamlNameResolver)) as IXamlNameResolver;
if (xamlNameResolver == null)
throw new InvalidOperationException(System.Xaml.SR.Get("MissingNameResolver"));
if (string.IsNullOrEmpty(this.Name))
throw new InvalidOperationException(System.Xaml.SR.Get("MustHaveName"));
object obj = xamlNameResolver.Resolve(this.Name);
if (obj == null)
{
string[] strArray = new string[1]
{
this.Name
};
obj = xamlNameResolver.GetFixupToken((IEnumerable<string>) strArray, true);
}
return obj;
}
I’ve simplified this ProvideValue method to only show the code which it is actually using in my scenario:
if (serviceProvider == null)
throw new ArgumentNullException("serviceProvider");
IXamlNameResolver xamlNameResolver = serviceProvider.GetService(typeof(IXamlNameResolver)) as IXamlNameResolver;
object obj = xamlNameResolver.Resolve(this.Name);
if (obj == null)
{
var strArray = new string[1]{ this.Name };
obj = xamlNameResolver.GetFixupToken((IEnumerable<string>)strArray, true);
}
return obj;
Apparantly the Exception is thrown by the GetFixUpToken method, but the cause is the Resolve method. This Resolve method returns a valid object when lookup up the ColumnDefinition by its name, but it returns NULL when doing the exact same thing for a RowDefinition.
The Error thrown by GetFixUpToken is: “NotImplementedException”, which is expected since when looking at the sourcecode of the IXamlNameResolver (which in this case is of Type: XamlNameResolverImpl)
When looking at the source code of this XamlNameResolverImpl, you can see that the method “GetFixUpToken” is empty and throws a NotImplemented exception (look at http://dotnetinside.com/en/framework/Microsoft+Expression/Microsoft.Expression.WpfPlatform/WpfMarkupExtensionValueSetter)
public object GetFixupToken(IEnumerable<string> names, bool canAssignDirectly)
{
throw new NotImplementedException();
}
public object GetFixupToken(IEnumerable<string> names)
{
throw new NotImplementedException();
}
But the problem is, as I already said, is the Resolve call, which works fine for columndefinition but fails for rowdefinitions…:
Column:
Row:
At this point, I don't know what to do anymore...
Source code (example project) available at: http://www.frederikprijck.net/stuff/MarkupExtension.rar