I've managed to reduce this to a simple test case. An exception is thrown during the parsing of this XAML using 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>
The exception message is:
Cannot set unknown member 'System.Windows.Controls.TextBox.IsReadOnly'. Line number '13' and line position '11'.
If I don't set IsReadOnly
on the TextBox
, it parses fine. It also parses fine if I remove the style trigger.
Can anyone shed some light on this? I'm rather new to WPF.
UPDATE:
Here's the unit test I'm using to reproduce this (it's failing on my 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
}
UPDATE 2:
I was originally referencing just PresentationFramework v4.0.30319. Adding references to PresentationCore, System.Xaml, and WindowsBase has no effect.
.NET version of project is 4 (full, not client profile).
UPDATE 3:
Arg, this works fine in ExpressionBlend 3.0.1927.0 and XamlPadX 4. As reported by AresAvatar, it seems to only fail when parsed with XamlReader.Parse()
or XamlReader.Load()
!
Short answer, clearly this is a bug. The following can be used as a workaround.
Update, workaround 2
Even just executing the following line before XamlReader.Parse(xaml)
fixes the problem, still clueless as to why though..
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);
Workaround 1
Using Boolean in mscorlib instead of True in the Trigger
seems to fix the problem for good. The following xaml does not throw an exception in 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>";
Some research details..
I did some testing of this weird problem.
First I included the working DockPanel
in Xaml and saved it with
string xaml = XamlWriter.Save(theDockPanel);
just to see if that piece of xaml was working with XamlReader.Parse
, and it did.
Then I made small changes to the generated xaml (and reverted once the exception came back) until I got as close as possible to the original. The weird part is that once this xaml has been parsed, the original works as well.
The part that made it working seems to be using <s:Boolean>True</s:Boolean>
instead of 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)
{
}
I'll update again if I find something more on this..
One of my clients experienced this on one install - I could not repro it myself.
In my instance the Text
property was bound to an underlying view model's string property, and the IsReadOnly
property was set to "True" in xaml as in the first example from Cameron.
The problem was solved by changing the binding to the Text
property's mode to OneWay.
<TextBox Text="{Binding SomeProperty, Mode=OneWay}" IsReadOnly="True" />
I had this problem happen to me on a WPF application using Telerik UI for WPF 2017.2 using implicit styles.
I'm posting this here because it is very likely that others will reach this question looking for the error message:
Cannot set unknown member 'System.Windows.Controls.TextBox.IsReadOnly'
Normally, the implicit style XAMLs are configured with build action of "Resource", if you change it to build action "Page", all the Telerik controls are displayed correctly.
Source: Telerik feedback page
So far, I've only needed to change the build action on Telerik.Windows.Controls.Input.xaml but your mileage may vary. At least you will not have to change the implicit styles like I did.
PS: I hope this workaround sheds some light to anybody that has a similar issue or is trying to investigate the apparent bug on the .NET XamlReader
The XamlParser won't automatically load extra assemblies such as System.Windows.Interactivity which is where Triggers are defined. Try declaring a dummy variable from that assembly in code prior to parsing the Xanl. Alternatively, use Assembly.Load to load the assembly.