Почему «Установка обработчиков событий внутри структуры Setter.Value» приводит к ошибке компиляции? - PullRequest
8 голосов
/ 12 апреля 2011

Я столкнулся с проблемой точно так же, как описано в Установка обработчиков событий внутри структуры Setter.Value . Но я хочу понять, почему решение, предоставленное автором вопроса, не работает. Похоже, я пропустил какую-то концепцию.

1 Ответ

15 голосов
/ 13 апреля 2011

Похоже, это ошибка в генерации кода XAML.В дополнение к пользовательскому коду для файлов XAML существует версия, сгенерированная «компилятором», которая определяет InitializeComponent и поля класса для именованных элементов (т. Е. X: Name).

Приведенный простой пример:

<Window.Resources>
    <Style TargetType="Button">
        <Setter Property="ContextMenu">
            <Setter.Value>
                <ContextMenu>
                    <MenuItem Header="Header" Click="MenuItem_Click"/>
                </ContextMenu>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

<Button />

Если вы запустите это, вы получите следующее исключение:

System.Windows.Markup.XamlParseException occurred
  Message='Set connectionId threw an exception.' Line number '13' and line position '8'.
  Source=PresentationFramework
  LineNumber=13
  LinePosition=8
  StackTrace:
       at System.Windows.Markup.XamlReader.RewrapException(Exception e, IXamlLineInfo lineInfo, Uri baseUri)
  InnerException: System.InvalidCastException
       Message=Unable to cast object of type 'System.Windows.Controls.MenuItem' to type 'System.Windows.Controls.Button'.
       Source=Windows7Theme
       StackTrace:
            at Windows7Theme.MainWindow.System.Windows.Markup.IComponentConnector.Connect(Int32 connectionId, Object target) in c:\Users\TJoe\Documents\Visual Studio 10\Projects\Windows7Theme\Windows7Theme\MainWindow.xaml:line 13
            at MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetConnectionId(Object root, Int32 connectionId, Object instance)
       InnerException: 

Сгенерированные файлы с выделенным кодом можно найти в папке obj, поэтому, если мы проверим, что мы можемсм. следующий код:

void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {
    switch (connectionId)
    {
    case 1:

    #line 13 "..\..\..\MainWindow.xaml"
    ((System.Windows.Controls.Button)(target)).AddHandler(System.Windows.Controls.MenuItem.ClickEvent, new System.Windows.RoutedEventHandler(this.MenuItem_Click));

    #line default
    #line hidden
    return;
    }
    this._contentLoaded = true;
}

Проблема заключается в том, что сгенерированный код пытается преобразовать MenuItem в Button.Если мы изменим наш пример следующим образом:

<Window.Resources>
    <ContextMenu x:Key="ContextMenuKey">
        <MenuItem Header="Header" Click="MenuItem_Click"/>
    </ContextMenu>

    <Style TargetType="Button">
        <Setter Property="ContextMenu"
                Value="{StaticResource ContextMenuKey}" />
    </Style>
</Window.Resources>

<Button />

Тогда сгенерированный код будет:

void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object target) {
    switch (connectionId)
    {
    case 1:

    #line 10 "..\..\..\MainWindow.xaml"
    ((System.Windows.Controls.MenuItem)(target)).Click += new System.Windows.RoutedEventHandler(this.MenuItem_Click);

    #line default
    #line hidden
    return;
    }
    this._contentLoaded = true;
}

На основании моих тестов кажется, что генератор кода назначает идентификатор каждому элементу управления, который оннеобходимо "подключить" или добавить обработчики / вспомогательные поля для.В случае, когда ContextMenu включен inline (то есть в первом примере), его обработчики событий назначаются корневому элементу внутри окна и не получают его собственный идентификатор.

Если мы изменили Button насодержаться в сетке, то исключение выше будет означать, что ему не удалось привести MenuItem к сетке.Потому что теперь Сетка является корневым элементом.Это указывает на то, что он не имеет никакого отношения к типу целей Style.

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

В конечном счете, это ошибка в генераторе кода XAML.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...