场景: 创建一个 MarkupExtension 以将 Grid.Row=”0” 替换为 Grid.Row=”{namespace:ClassExtension GridRowName}”(列相同)
Xaml 代码:
<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>
要求:
- 使用不正确的 GridRowName(或 columnName)时显示 XAML 错误
- 使用正确的 GridRowName(或 columnName)时不显示 XAML 错误
- 当 Valid ColumnName 用于 Row 声明(以及 vica verca)时,应显示 XAML 错误
问题: Grid.Column 一切正常,但 Grid.Row 总是在设计时抛出“未实现的异常”(grid.row 带下划线,grid.column 没有)。
行和列都命名正确,但行总是显示错误。如果我们指定了无效的列名,则该列会显示错误(这是预期的,因此 Grid.Column 可以正常工作!)
如您所见,列工作正常,但行不行。问题出在名为 GridDefinitionExtension 的 MarkupExtension 内部:
[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();
}
}
例外是在线上的:
var definition = referenceExt.ProvideValue(serviceProvider);
在查看调用此方法的 DLL 之后,我发现此 ProvideValue 方法的主体如下所示:
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;
}
我已经简化了这个 ProvideValue 方法,只显示它在我的场景中实际使用的代码:
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;
显然,异常是由 GetFixUpToken 方法引发的,但原因是 Resolve 方法。当通过名称查找 ColumnDefinition 时,此 Resolve 方法返回一个有效对象,但在对 RowDefinition 执行完全相同的操作时,它返回 NULL。
GetFixUpToken 抛出的错误是:“NotImplementedException”,这是预期的,因为在查看 IXamlNameResolver 的源代码时(在本例中是类型:XamlNameResolverImpl)
查看此 XamlNameResolverImpl 的源代码时,您可以看到方法“GetFixUpToken”为空并引发 NotImplemented 异常(查看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();
}
但问题是,正如我已经说过的,是 Resolve 调用,它对 columndefinition 工作正常,但对 rowdefinitions 失败......:
柱子:
排:
此时,我不知道该怎么办了......
源代码(示例项目)位于:http ://www.frederikprijck.net/stuff/MarkupExtension.rar