尝试设置TextBox.IsReadOnly时出现奇怪的XAML解析错误

时间:2011-07-27 20:18:47

标签: c# wpf xaml xamlreader

我已经设法将其简化为一个简单的测试用例。使用XamlReader.Parse()解析此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>

异常消息是:

  

无法设置未知成员'System.Windows.Controls.TextBox.IsReadOnly'。行号“13”和行位置“11”。

如果我没有在IsReadOnly上设置TextBox,则解析正常。如果我删除样式触发器,它也会解析。

有人可以对此有所了解吗?我对WPF很新。

更新
这是我用来重现这个的单元测试(它在我的电脑上失败了):

[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
}

更新2:
我最初只引用了PresentationFramework v4.0.30319。添加对PresentationCore,System.Xaml和WindowsBase的引用无效。

项目的.NET版本为4(完整,不是客户端配置文件)。

更新3:
Arg,这在ExpressionBlend 3.0.1927.0和XamlPadX 4中运行良好。正如AresAvatar报道的那样,在使用XamlReader.Parse()XamlReader.Load()解析时似乎只会失败!

4 个答案:

答案 0 :(得分:8)

简短回答,显然这是一个错误。以下内容可用作解决方法。

更新,解决方法2

即使只是在XamlReader.Parse(xaml)之前执行以下行修复了问题,但仍然无法解释为什么..

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);

解决方法1
Trigger中使用mscorlib中的布尔而不是True似乎可以解决问题。以下xaml不会在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>";

一些研究细节..

我对这个奇怪的问题做了一些测试。

首先,我在Xaml中包含了工作DockPanel并将其保存为

string xaml = XamlWriter.Save(theDockPanel);

只是为了看看那片xaml是否与XamlReader.Parse一起工作,而且确实如此。

然后我对生成的xaml进行了小的更改(并在异常恢复后恢复),直到我尽可能接近原始xaml。奇怪的是,一旦解析了这个xaml,原始版本也可以工作。

使其正常工作的部分似乎是使用<s:Boolean>True</s:Boolean>而不是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)
{

}

如果我在此发现更多内容,我会再次更新..

答案 1 :(得分:3)

我的一位客户在一次安装中遇到过这种情况 - 我无法自己复制。
在我的实例中,Text属性绑定到底层视图模型的字符串属性,IsReadOnly属性在xaml中设置为“True”,如Cameron的第一个示例中所示。

通过将绑定更改为Text属性的模式为OneWay解决了该问题。

<TextBox Text="{Binding SomeProperty, Mode=OneWay}" IsReadOnly="True" />

答案 2 :(得分:1)

我使用隐式样式使用Telerik UI for WPF 2017.2在WPF应用程序上遇到此问题。

我在此发布此内容是因为其他人很可能会在查找错误消息时遇到此问题:

  

无法设置未知成员&#39; System.Windows.Controls.TextBox.IsReadOnly&#39;

通常情况下,隐式样式XAML配置为&#34;资源&#34;的构建操作,如果您将其更改为构建操作&#34; Page&#34;,则所有Telerik控件都会正确显示。

来源:Telerik feedback page

到目前为止,我只需要更改Telerik.Windows.Controls.Input.xaml上的构建操作,但您的里程可能会有所不同。至少你不必像我那样改变隐式样式。

PS:我希望这个解决方法可以解决任何有类似问题的人,或者试图调查.NET XamlReader上的明显错误

答案 3 :(得分:0)

XamlParser不会自动加载额外的程序集,例如System.Windows.Interactivity,这是定义触发器的位置。在解析Xanl之前,尝试在代码中声明来自该程序集的虚拟变量。或者,使用Assembly.Load加载程序集。