Lo scenario: Creare un MarkupExtension per sostituire Grid.Row =”0” di Grid.Row =” {namespace: ClassExtension GridRowName}”(lo stesso per la colonna)WPF MarkupExtension e RowDefinition risultati in 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>
Il requisito:
- Visualizza XAML errori quando un GridRowName incorrent (o columnName) è utilizzato
- Mostra errori XAML quando una corretta GridRowName (o columnName) viene utilizzato
- Quando un ColumnName valido viene utilizzato per una dichiarazione di fila (e vica verca) un errore di XAML dovrebbe essere mostrato
Il problema: Tutto funziona bene per Grid.Column, ma Grid.Row getta sempre un “eccezione non implementato” a designtime (Grid.Row è sottolineato , grid.colu mn non è).
Le righe e le colonne hanno entrambi un nome corretto, ma la riga mostra sempre un errore. Se specifichiamo un nome di colonna non valida, la colonna mostra un errore (che si prevede, quindi Grid.Column funziona bene!)
Come si può vedere, colonna funziona bene, ma non lo fanno righe. Il problema risiede all'interno del MarkupExtension chiamato 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();
}
}
L'eccezione è trown sulla linea:
var definition = referenceExt.ProvideValue(serviceProvider);
Dopo aver guardato all'interno della DLL da cui viene chiamato questo metodo ho scoperto che il corpo di questo metodo ProvideValue si presenta così:
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;
}
ho semplificato questo metodo ProvideValue per mostrare solo il codice cui i In realtà è utilizzare nel mio 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;
quanto pare l'eccezione viene generata dal metodo GetFixUpToken, ma la causa è il metodo Resolve. Questo metodo Resolve restituisce un oggetto valido durante la ricerca di ColumnDefinition in base al nome, ma restituisce NULL quando fa esattamente la stessa cosa per una RowDefinition.
L'errore lanciati da GetFixUpToken è: “NotImplementedException”, che si prevede da quando guardando il codice sorgente del IXamlNameResolver (che in questo caso è di tipo: XamlNameResolverImpl)
Se si guarda a il codice sorgente di questo XamlNameResolverImpl, si può vedere che il metodo “GetFixUpToken” è vuota e genera un'eccezione NotImplemented (guarda 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();
}
Ma il problema è, come ho già detto, è la chiamata Resolve, che funziona bene per ColumnDefinition ma non riesce per rowdefinitions ...:
Colonna:
Fila:
A questo punto , non so più cosa fare ...
codice sorgente (progetto di esempio) disponibile all'indirizzo: http://www.frederikprijck.net/stuff/MarkupExtension.rar
Solo una raccomandazione. Usa il codice reale nel tuo post (come quello che hai fatto con xaml) invece di screenshot del codice. Alcuni di questi screenshot sono piuttosto piccoli se ridimensionati in SO. –
Ho usato lo screenshot perché volevo sottolineare tutti i problemi: Xaml Underline, valori di runtime C#, ... Ci sono alcuni screenshot che ho sostituito con il codice, dato che hai ragione. Immagino di aver iniziato a usare schermate e di aver dimenticato di usare il testo dove possibile. A proposito, ho aggiunto il progetto sorgente per questi motivi :-) –