23

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()!

akjoshi
  • 15,374
  • 13
  • 103
  • 121
Cameron
  • 96,106
  • 25
  • 196
  • 225
  • 1
    Your code worked fine for me. – CodeNaked Jul 27 '11 at 20:23
  • Try out to change IsReadOnly by TextBox.IsReadOnly – sll Jul 27 '11 at 20:23
  • 1
    Also worked fine for me. What version of WPF are you using? – Ed Bayiates Jul 27 '11 at 20:25
  • I'm assuming the assembly with your unit tests references all the proper assemblies? – CodeNaked Jul 27 '11 at 20:27
  • @CodeNaked: I've added the exact test case code I'm using (which fails here). – Cameron Jul 27 '11 at 20:27
  • @AresAvatar: I'm using WPF shipped with .NET 4 – Cameron Jul 27 '11 at 20:27
  • @CodeNaked: I'm referencing PresentationFramework v4.0.30319. Am I missing anything else? – Cameron Jul 27 '11 at 20:29
  • @CodeNaked: Added those, plus PresentationCore. Still no dice. – Cameron Jul 27 '11 at 20:31
  • This only does not work for me when put into Kaxaml, wonder why... – H.B. Jul 27 '11 at 20:36
  • 1
    OK, I reproduced your problem using your test code with XamlReader.Parse. This looks like a Microsoft bug to me. – Ed Bayiates Jul 27 '11 at 20:42
  • @AresAvatar: How did you get it to work before? – Cameron Jul 27 '11 at 20:48
  • @sll: Just saw your comment and tried -- no effect. – Cameron Jul 27 '11 at 20:50
  • 4
    @Cameron, I had tried just the Xaml at the top, which works. It's XamlReader.Parse that is broken. The exception has an inner exception from the XamlWriter, but the details are the same. I say report it to Microsoft. – Ed Bayiates Jul 27 '11 at 20:52
  • @AresAvatar: OK, thanks. This is embedded in a WinForms app, so we use `XamlReader.Load(stream)` (which causes the same exception). – Cameron Jul 27 '11 at 20:54
  • Try changing `TargetType="TextBox"` to `TargetType="{x:Type TextBox}"`, just for my sanity. I had a weird problem that occurred from not using the longhand notation. – Adam Maras Jul 27 '11 at 21:12
  • I bet you'll need to set an appropriate ParserContext. Sure _your_ code has access to all the assemblies and whatnot you're referencing. Doesn't mean the parser does... – Jeff Mercado Jul 27 '11 at 21:14
  • @Adam: I tried your suggestion, but to no avail – Cameron Jul 27 '11 at 21:15
  • @Jeff: I tried using an explicit parser class, but I'm not sure which other assemblies I'd need to reference (I'm not using any special ones as far as I can tell). Could you expand on your comment? – Cameron Jul 27 '11 at 21:25
  • @Cameron: `XamlReader.Parse()` has an overload that accepts a `ParserContext`. I'm saying everything you need is probably set in that context. I don't know how to set it myself, I've been messing with this for a while but couldn't figure out how this should be set. You should look into this. – Jeff Mercado Jul 27 '11 at 21:32
  • @Jeff: Thanks for the suggestion, I'll poke around with that a bit. It works if I remove the `IsReadOnly="True"` though, which leads me to think it's not something in the context. – Cameron Jul 27 '11 at 21:35
  • I am getting this on a DataTemplate in 2021, .net 5 – Arrow_Raider Jul 16 '21 at 14:11
  • I had same issue today on .Net 6. It build just right but decided to replace it with aplying style. –  Jul 08 '22 at 20:27

4 Answers4

10

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..

Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
  • Holy cows that's weird! Thanks for the workaround, I'll play around with it tomorrow and get back to you. – Cameron Jul 27 '11 at 22:59
  • 1
    The second workaround is nice and short, and only needs to be executed once. The `x` namespace isn't needed, so it can be shortened to `XamlReader.Parse("");`. Thanks! – Cameron Jul 28 '11 at 13:28
  • Had the same problem with a DatePicker where the inner DatePickerTextBox would complain. Changing from IsReadOnly="True" to True did the trick. Thanks! – maets Apr 23 '22 at 06:22
4

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" />
eilef
  • 73
  • 5
  • This was what I encountered. The TextBox was bound to a readonly property and without the Mode=OneWay (or OneTime) it would generate the runtime exception. – AdvApp May 19 '17 at 22:35
1

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

Mike Rod
  • 111
  • 4
1

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.

Scott Munro
  • 13,369
  • 3
  • 74
  • 80
  • 3
    I tried your suggestion using `var dummy = TriggerCollection.ShouldSerializeStoredWeakReference(null);` (randomly chosen method). Still same exception. I suspect it's not the trigger in general, since it parses fine if I remove the `IsReadOnly="True"` attribute on the `TextBox` element itself. It's `System.Windows.Interactivity`, by the way – Cameron Jul 27 '11 at 21:23
  • Based on the other answer it sounds like it might be mscorlib that is not being loaded in time. This sounds very strange but it might be worth trying to declare a boolean variable prior to the Parse call. – Scott Munro Jul 27 '11 at 23:11
  • I added a dummy boolean variable, but it didn't change the behaviour. I have a hard time believing that the code could run at all without mscorlib being loaded ;-) – Cameron Jul 28 '11 at 13:17
  • Based on the other answer and how the original code is parsed correctly after the workaround it still seems as if 'something' is not being loaded correctly. The workaround that I described was required to parse Xaml containing a Telerik RadChart. I agree though - mscorlib not loading seems very unlikely. – Scott Munro Jul 28 '11 at 21:49