7

场景: 创建一个 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

4

1 回答 1

1

这是一个解决方案,虽然与您的实施不同,但可以完成工作。

代替 MarkupExtension,创建一个 IValueConverter 用于绑定:

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();
        }
    }

然后把它放在你的 XAML 中:

<Grid.Resources>
    <me:GridDefinitionConverter x:Key="gridDefinitionConverter" />
</Grid.Resources>

并像这样实现它:

<Label Grid.Row="{Binding ElementName=TitleRow, Converter={StaticResource gridDefinitionConverter}}" />
于 2013-10-08T15:29:21.010 回答