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

Cam*_*ron 22 c# wpf xaml xamlreader

我已经设法将其简化为一个简单的测试用例.在使用以下方法解析此XAML期间抛出异常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>
Run Code Online (Sandbox Code Playgroud)

异常消息是:

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

如果我不设置IsReadOnlyTextBox,它解析罚款.如果我删除样式触发器,它也会解析.

任何人都可以对此有所了解吗?我对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
}
Run Code Online (Sandbox Code Playgroud)

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

Fre*_*lad 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);
Run Code Online (Sandbox Code Playgroud)

解决方法1
在mscorlib中使用布尔而不是True Trigger似乎可以解决问题.以下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>";
Run Code Online (Sandbox Code Playgroud)

一些研究细节......

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

首先,我将工作包括DockPanel在Xaml中并保存

string xaml = XamlWriter.Save(theDockPanel);
Run Code Online (Sandbox Code Playgroud)

只是为了看看那片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)
{

}
Run Code Online (Sandbox Code Playgroud)

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