Передать элемент как CommandParameter из корня ElementTree

Я много искал в Google и StackOverflow, но ничего не ответило на мою проблему.

У меня есть два файла Xaml:

MainWindow.xaml

<Window x:Name="mainWindow">
    <Window.DataContext>
        <!-- Instantiate ViewModel of the MainWindow -->
        <vm:MainWindowViewModel x:Name="viewModel"/>
    </Window.DataContext>

    <!-- Create the Menu of the MainWindow -->
    <custom:MainMenu Grid.Row="0"/>

    <ad:DockingManager x:Name="dockingManager">
    <!-- ... -->
</Window>

И MainMenu.xaml

<UserControl>
    <Menu>
        <MenuItem Header="{t:Translate MENU_LAYOUT_SAVE}" Command="{Binding SaveLayoutCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
        <MenuItem Header="{t:Translate MENU_LAYOUT_LOAD}" Command="{Binding LoadLayoutCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=Window}}"/>
    </Menu>
</UserControl>

И тут возникает моя проблема. Вместо передачи объекта Mainwindow я хочу передать DockingManager x:Name="dockingManager" из MainWindow. Но если я попытаюсь сослаться на объект по его имени, это не удастся...

Я пробовал следующие привязки:

CommandParameter="{Binding ElementName=dockingManager}"
CommandParameter="{Binding ElementName=dockingManager, RelativeSource={RelativeSource AncestorType=Window}}"

Итак, как я могу найти и сослаться на объект (dockingManager) из ElementTree в xaml. Я хочу избежать использования дополнительного кода в Code-behind.


person Marschal    schedule 27.09.2013    source источник


Ответы (3)


Попробуйте CommandParameter="{Binding ElementName=dockingManager, Path=.}".

РЕДАКТИРОВАТЬ: предыдущий ответ не сработает. Вот рабочая идея...

В Window.xaml:

<custom:MainMenu Grid.Row="0" Tag="{Binding ElementName=dockingManager}" />

В MainMenu.xaml:

<UserControl x:Name="UcMainMenu" />
...
    <MenuItem Header="{t:Translate MENU_LAYOUT_SAVE}" Command="{Binding SaveLayoutCommand}" CommandParameter="{Binding ElementName=UcMainMenu, Path=Tag}"/>
person Paweł Motyl    schedule 27.09.2013
comment
Спасибо за быстрый повтор. Тоже уже пробовал. Ошибка с System.Windows.Data Error: 4 : Cannot find source for binding with reference 'ElementName=dockingManager'. BindingExpression:Path=.; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'CommandParameter' (type 'Object') - person Marschal; 27.09.2013
comment
Спасибо. Это сработало для меня, но выглядит немного как грязный обходной путь. Возможно, я оставлю это на некоторое время, а позже пойду так, как описала Мейлке. - person Marschal; 01.10.2013
comment
Это обходной путь, и причина проста: если у вас есть пользовательский элемент управления, который напрямую зависит от внешнего элемента управления, то, возможно, это не настоящий пользовательский элемент управления. То, что вы пытаетесь сделать, просто не является хорошей практикой, поэтому я настоятельно рекомендую вам попробовать то, что описал meilke или что-то подобное. В общем, старайтесь избегать боковых зависимостей в пользовательском интерфейсе (за исключением всего, что связано с простым внешним видом и стилем, может быть) и придерживайтесь использования данных виртуальной машины. - person Paweł Motyl; 01.10.2013
comment
Просто комментарий к решению, которое я разместил: немного лучший способ (не хакерский) сделать это — использовать выделенный DependencyProperty (например, DockingManagerDependencyProperty в пользовательском элементе управления MainMenu. На самом деле, я только что подумал над тем, что я сказал минуту назад: на мой взгляд, это хорошая практика. Почему? Одна из ловушек MVVM заключается в попытке впихнуть все в виртуальную машину. Всегда учитывайте следующее: можете ли вы представить пользовательский интерфейс для своего приложения без функции A (например, статический пользовательский интерфейс без стыковки)? Если это так, то функция A не должна быть включена в виртуальную машину, потому что виртуальная машина не должна зависеть от пользовательского интерфейса. - person Paweł Motyl; 01.10.2013

Ты можешь использовать:

CommandParameter="{x:Reference Name=yourElementName}"
person Davide Cannizzo    schedule 15.10.2018

Поскольку вы используете MVVM, вот что вам нужно сделать, чтобы найти немного другое решение:

  • Избавьтесь от CommandParameter
  • Команда вызовет обратный вызов в экземпляре MainWindowViewModel.
  • Этот обратный вызов изменит некоторые состояния/свойства в экземпляре MainWindowViewModel.
  • Экземпляр DockingManager реагирует на скорректированное состояние экземпляра MainWindowViewModel через привязки.

То, как вы это делаете сейчас, слишком сложно. Вдобавок ко всему, вы тут дико смешиваете паттерны. MVVM пытается отделить бизнес-логику от реальных элементов. Вы используете элементы MVVM с методами Smart UI/Code Behind.

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

person meilke    schedule 27.09.2013
comment
Это было бы более изящно, но вопрос был прямолинеен и это не дает на него ответа. - person Paweł Motyl; 27.09.2013
comment
@CodeMonkey Вы абсолютно правы. Я не мог удержаться от совета вместо ответа (которого у меня, собственно, сейчас нет). - person meilke; 27.09.2013
comment
Это понятно, и я призываю пользователя 2823573 рассмотреть возможность использования этого предложения :) - person Paweł Motyl; 27.09.2013
comment
Не могли бы вы немного подробнее рассказать о своем предложении. Что плохого в моем подходе к передаче dockingManager через привязку? - person Marschal; 27.09.2013
comment
@user2823573 user2823573 Я поправил свой ответ. - person meilke; 27.09.2013
comment
@ user2823573 Неплохо, но сложно. - person meilke; 27.09.2013