Странная ошибка синтаксического анализа XAML при попытке установить TextBox.IsReadOnly

Мне удалось сократить это до простого теста. Исключение выдается при разборе этого 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>

Сообщение об исключении:

Невозможно установить неизвестный элемент '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 ответа

Решение

Короткий ответ, ясно, что это ошибка. Следующее может быть использовано в качестве обходного пути.

Обновление, обход 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
Использование логического значения в 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>";

Некоторые детали исследования..

Я провел некоторое тестирование этой странной проблемы.

Сначала я включил рабочий DockPanel в Xaml и сохранил его с

string xaml = XamlWriter.Save(theDockPanel);

просто чтобы посмотреть, работал ли этот кусок xaml с XamlReader.Parseи это сделал.

Затем я внес небольшие изменения в сгенерированный 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)
{

}

Я обновлю еще раз, если найду что-то еще об этом..

Один из моих клиентов испытал это на одной установке - я сам не смог его воспроизвести.
В моем случае Text свойство было привязано к строковому свойству базовой модели представления, а IsReadOnly свойство было установлено в "True" в xaml, как в первом примере от Кэмерона.

Проблема была решена путем изменения привязки к Text режим собственности в OneWay.

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

У меня была такая проблема со мной в приложении WPF с использованием Telerik UI для WPF 2017.2 с использованием неявных стилей.

Я публикую это здесь, потому что очень вероятно, что другие дойдут до этого вопроса в поисках сообщения об ошибке:

Невозможно установить неизвестный элемент 'System.Windows.Controls.TextBox.IsReadOnly'

Обычно XAML неявного стиля настраиваются с действием сборки "Ресурс", если вы измените его на действие сборки "Страница", все элементы управления Telerik будут отображаться правильно.

Источник: Telerik Страница обратной связи

До сих пор мне нужно было только изменить действие сборки на Telerik.Windows.Controls.Input.xaml, но ваш пробег может отличаться. По крайней мере, вам не придется менять неявные стили, как я.

PS: я надеюсь, что этот обходной путь проливает свет на любого, кто имеет подобную проблему или пытается исследовать очевидную ошибку в.NET XamlReader

XamlParser не будет автоматически загружать дополнительные сборки, такие как System.Windows.Interactivity, в которой определены триггеры. Попробуйте объявить фиктивную переменную из этой сборки в коде перед синтаксическим анализом Xanl. Также можно использовать Assembly.Load для загрузки сборки.

Другие вопросы по тегам