Fre*_*jck 7 c# wpf xaml design-time markup-extensions
场景: 创建一个MarkupExtension,用Grid.Row ="{namespace:ClassExtension GridRowName}"替换Grid.Row ="0"(列相同)
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>
Run Code Online (Sandbox Code Playgroud)
要求:
问题:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
该行上有异常:
var definition = referenceExt.ProvideValue(serviceProvider);
Run Code Online (Sandbox Code Playgroud)
在查看调用此方法的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;
}
Run Code Online (Sandbox Code Playgroud)
我已经简化了这个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;
Run Code Online (Sandbox Code Playgroud)
显然,GetFixUpToken方法抛出异常,但原因是Resolve方法.当通过名称查找ColumnDefinition时,此Resolve方法返回有效对象,但在为RowDefinition执行完全相同的操作时返回NULL.
GetFixUpToken抛出的错误是:"NotImplementedException",这是在查看IXamlNameResolver的源代码时所期望的(在本例中是Type: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();
}
Run Code Online (Sandbox Code Playgroud)
但问题是,正如我已经说过的那样,是Resolve调用,它对于columndefinition工作正常,但对于rowdefinitions却失败了......:
柱:

行:

此时,我不知道该怎么办......
源代码(示例项目)可从以下网址获得:http://www.frederikprijck.net/stuff/MarkupExtension.rar
这是一个解决方案,虽然与您的实现不同,但可以完成工作。
创建一个 IValueConverter 以与 Binding 一起使用,而不是 MarkupExtension:
public class GridDefinitionConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var definition = value as DefinitionBase;
int toReturn = 0;
if (definition != null)
{
var grid = (definition as FrameworkContentElement).Parent as Grid;
if (grid != null && definition is RowDefinition)
toReturn = grid.RowDefinitions.IndexOf(definition as RowDefinition);
if (grid != null && definition is ColumnDefinition)
toReturn = grid.ColumnDefinitions.IndexOf(definition as ColumnDefinition);
}
return toReturn;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Run Code Online (Sandbox Code Playgroud)
然后将其放入您的 XAML 中:
<Grid.Resources>
<me:GridDefinitionConverter x:Key="gridDefinitionConverter" />
</Grid.Resources>
Run Code Online (Sandbox Code Playgroud)
并像这样实现它:
<Label Grid.Row="{Binding ElementName=TitleRow, Converter={StaticResource gridDefinitionConverter}}" />
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
651 次 |
| 最近记录: |