2013-10-07 3 views
7

Сценарий: Создать MarkupExtension, чтобы заменить Grid.Row =»0” Grid.Row =» {Пространство имен: ClassExtension GridRowName}»(то же самое для столбца)WPF MarkupExtension и RowDefinition результаты в NotImplementedException

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> 

Требование:

  • Показать XAML Ошибки, когда incorrent GridRowName (или ColumnName) является используется
  • Показать без ошибок XAML, когда правильный GridRowName (или ColumnName) используется
  • Когда Действительно ColumnName используется для объявления Row (и Vica verca) ошибка XAML должны быть показаны

проблема: Все отлично работает для Grid.Column, но Grid.Row всегда выдает «Не Реализован исключение» на этапе проектирования (Grid.Row подчеркнут , grid.colu mn нет). enter image description here

Строки и столбцы называются правильными, но строка всегда показывает ошибку. Если указать неверное имя столбца, столбец показывает ошибку (которая, как ожидается, так Grid.Column работает отлично!) enter image description here

Как вы можете видеть, колонка работает отлично, но Ряды не делают. Проблема лежит внутри MarkupExtension называется 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(); 
    } 
} 

Исключение составляет trown на линии:

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 только показать код, это я S фактически используя в моем сценарии:

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 Исключение брошено методом GetFixUpToken, но причиной этого является метод Resolve. Этот метод Resolve возвращает действительный объект при поиске ColumnDefinition по его имени, но возвращает NULL, когда делает то же самое для RowDefinition.

Ошибка брошенной GetFixUpToken является: «NotImplementedException», который, как ожидается, так как при взгляде на исходный код из IXamlNameResolver (который в этом случае имеет тип: XamlNameResolverImpl)

enter image description here

При взгляде на исходный код этого 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 ...:

Колонка: enter image description here

Row: enter image description here

На данный момент Я не знаю, что делать больше ...

Исходный код (пример проекта) по адресу: http://www.frederikprijck.net/stuff/MarkupExtension.rar

+1

Просто рекомендация. Используйте фактический код в своем сообщении (например, то, что вы сделали с xaml) вместо скриншотов кода. Некоторые из этих скриншотов довольно малы при изменении размера в SO. –

+0

Я использовал скриншот, потому что хотел указать на все проблемы: Xaml Underline, C# runtime values, ... Есть несколько скриншотов, которые я заменил кодом, так как вы правы. Думаю, я начал использовать скриншоты и забыл использовать текст там, где это возможно. Кстати, я добавил исходный проект по этой причине :-) –

ответ

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}}" /> 
+0

Очевидно, это решение НЕ проверяется во время разработки: http://prntscr.com/1w31id Как вы можете видеть, TitleRow2 не существует. В этом весь смысл, который я хочу достичь. Мое решение прекрасно работает, как я уже сказал. Единственная проблема - во время разработки разработчику необходимо получить обратную связь. (что не работает для RowDefinitions в моем примере ... ColumnDefinitions работает нормально) –

+0

Мое решение работает во время разработки, чего нет у вас. Кажется, что проблема в WPF заключается в том, что строки не инициализируются, когда ваш MarkupExtension должен получить к ним доступ. Ваш скриншот не показывает вам использование конвертера, который я рекомендовал, просто привязывая непосредственно к RowDefinition, который не будет работать. Убедитесь, что вы включили преобразователь и создаете IValueConverter. –

+0

О, боже, я действительно сделал Конвертер, но забыл его использовать. Я просто хотел быстро дать ему тест, так как он не использует MarkupExtension. Я не вижу в этом решения проблемы. По-видимому, это работает. Итак, теперь у меня есть рабочий способ. Я беспокоюсь о производительности в этом случае, я предпочитаю не использовать привязки по нескольким причинам, но я думаю, что это не может работать без привязки? Большое вам спасибо за вашу помощь, это не значит, что я никогда не использовал конвертеры Value (или multiValue) ... Я просто сосредоточился на MarkupExtension :( –

Смежные вопросы