c# - Error de análisis extraño de XAML al intentar establecer TextBox.IsReadOnly
wpf xamlreader (4)
Pude reducir esto a un simple caso de prueba. Se produce una excepción durante el análisis de este XAML utilizando XamlReader.Parse()
:
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsReadOnly" Value="True">
<Setter Property="Background" Value="#FFEEEEEE" />
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Resources>
<TextBox IsReadOnly="True" />
</DockPanel>
El mensaje de excepción es:
No se puede establecer el miembro desconocido ''System.Windows.Controls.TextBox.IsReadOnly''. Número de línea ''13'' y posición de línea ''11''.
Si no configuro IsReadOnly
en el TextBox
, se analiza bien. También analiza bien si elimino el disparador de estilo.
¿Alguien puede arrojar algo de luz sobre esto? Soy bastante nuevo en WPF.
ACTUALIZAR:
Aquí está la prueba unitaria que estoy usando para reproducir esto (está fallando en mi PC):
[TestMethod]
public void TestIsReadOnlyOnTextBox()
{
// Arrange
var xaml =
@"<DockPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<DockPanel.Resources>
<Style TargetType=""TextBox"">
<Style.Triggers>
<Trigger Property=""IsReadOnly"" Value=""True"">
<Setter Property=""Background"" Value=""#FFEEEEEE"" />
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Resources>
<TextBox IsReadOnly=""True"" />
</DockPanel>
";
// Act
try {
var root = XamlReader.Parse(xaml);
}
catch (XamlParseException ex) {
Assert.Fail(ex.Message);
}
// If we get here, test passes
}
ACTUALIZACIÓN 2:
Originalmente me estaba refiriendo a PresentationFramework v4.0.30319. Agregar referencias a PresentationCore, System.Xaml y WindowsBase no tiene ningún efecto.
La versión .NET del proyecto es 4 (completa, no perfil de cliente).
ACTUALIZACIÓN 3:
Arg, esto funciona bien en ExpressionBlend 3.0.1927.0 y XamlPadX 4. Según lo informado por AresAvatar, parece que solo falla cuando se analiza con XamlReader.Parse()
o XamlReader.Load()
!
Me ocurrió este problema en una aplicación WPF que usa Telerik UI para WPF 2017.2 utilizando estilos implícitos.
Estoy publicando esto aquí porque es muy probable que otros lleguen a esta pregunta buscando el mensaje de error:
No se puede establecer el miembro desconocido ''System.Windows.Controls.TextBox.IsReadOnly''
Normalmente, los XAML de estilo implícito se configuran con la acción de compilación de "Recurso", si lo cambia a la acción de compilación "Página", todos los controles de Telerik se muestran correctamente.
Fuente: página de comentarios de Telerik
Hasta ahora, solo he necesitado cambiar la acción de compilación en Telerik.Windows.Controls.Input.xaml pero su kilometraje puede variar. Al menos no tendrás que cambiar los estilos implícitos como yo.
PD: Espero que esta solución arroje algo de luz a cualquiera que tenga un problema similar o que esté intentando investigar la aparente falla en .NET XamlReader
Respuesta corta, claramente esto es un error. Lo siguiente se puede usar como una solución alternativa.
Actualización, solución alternativa 2
Incluso ejecutando la siguiente línea antes de XamlReader.Parse(xaml)
corrige el problema, todavía no tiene ni idea de por qué ...
XamlReader.Parse(@"<TextBox xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
IsReadOnly=""True""/>");
var root = XamlReader.Parse(xaml);
Solución 1
Usar Boolean en mscorlib en lugar de Verdadero en el Trigger
parece solucionar el problema para siempre. El siguiente xaml no lanza una excepción en XamlReader.Parse
var xaml =
@"<DockPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml""
xmlns:s=""clr-namespace:System;assembly=mscorlib"" >
<DockPanel.Resources>
<s:Boolean x:Key=""BooleanTrue"">True</s:Boolean>
<Style TargetType=""TextBox"">
<Style.Triggers>
<Trigger Property=""IsReadOnly"" Value=""{StaticResource BooleanTrue}"">
<Setter Property=""Background"" Value=""#FFEEEEEE"" />
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Resources>
<TextBox IsReadOnly=""True"" />
</DockPanel>";
Algunos detalles de investigación ...
Hice algunas pruebas de este extraño problema.
Primero DockPanel
el DockPanel
trabajo en Xaml y lo guardé con
string xaml = XamlWriter.Save(theDockPanel);
solo para ver si esa pieza de xaml estaba trabajando con XamlReader.Parse
, y lo hizo.
Luego hice pequeños cambios en el xaml generado (y revertí una vez que la excepción regresó) hasta que estuve lo más cerca posible del original. La parte extraña es que una vez que se ha analizado este xaml, el original también funciona.
La parte que lo hizo funcionar parece usar <s:Boolean>True</s:Boolean>
lugar de True
.
var modifiedXaml = @"<DockPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:s=""clr-namespace:System;assembly=mscorlib""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<DockPanel.Resources>
<s:Boolean x:Key=""BooleanTrue"">True</s:Boolean>
<Style TargetType=""TextBox"">
<Style.Triggers>
<Trigger Property=""IsReadOnly"" Value=""{StaticResource BooleanTrue}"">
<Setter Property=""Background"" Value=""#FFEEEEEE"" />
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Resources>
<TextBox IsReadOnly=""True"" />
</DockPanel>";
var originalXaml = @"<DockPanel xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
<DockPanel.Resources>
<Style TargetType=""TextBox"">
<Style.Triggers>
<Trigger Property=""IsReadOnly"" Value=""True"">
<Setter Property=""Background"" Value=""#FFEEEEEE"" />
</Trigger>
</Style.Triggers>
</Style>
</DockPanel.Resources>
<TextBox IsReadOnly=""{Binding}""/>
</DockPanel>";
try
{
// If this line is executed, no `XamlParseException` is thrown
var root = XamlReader.Parse(modifiedXaml);
var root2 = XamlReader.Parse(originalXaml);
}
catch (XamlParseException ex)
{
}
Actualizaré de nuevo si encuentro algo más sobre esto ...
Uno de mis clientes experimentó esto en una instalación, no pude reproducirlo yo mismo.
En mi instancia, la propiedad Text
estaba vinculada a la propiedad de cadena de un modelo de vista subyacente, y la propiedad IsReadOnly
se estableció en "True" en xaml como en el primer ejemplo de Cameron.
El problema se resolvió cambiando el enlace al modo de propiedad Text
a OneWay.
<TextBox Text="{Binding SomeProperty, Mode=OneWay}" IsReadOnly="True" />
XamlParser no cargará automáticamente conjuntos adicionales, como System.Windows.Interactivity, que es donde se definen los desencadenadores. Intente declarar una variable ficticia de ese ensamblado en el código antes de analizar el Xanl. Alternativamente, use Assembly.Load para cargar el conjunto.