Подтвердить что ты не робот

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

UPDATE:
Здесь unit test Я использую, чтобы воспроизвести это (он не работает на моем ПК):

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

4b9b3361

Ответ 1

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

Обновление, обходное решение 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
Использование Boolean в 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)
{

}

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

Ответ 2

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

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

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

Ответ 3

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

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

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

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

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

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

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

Ответ 4

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