У меня есть контекстное меню с некоторыми опциями. Один из вариантов - это коллекция Observable, и у меня возникают проблемы с привязкой к ним моих команд в моей модели представления. Я видел много разных способов решить эту проблему, но ни один из них не помог, потому что они не связаны конкретно с моей проблемой. Сначала вот мой код:

XAML:

 <ListView ItemsSource="{Binding ListViewItems}" SelectionMode="Single">
            <ListView.ContextMenu>
                <ContextMenu DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource Self}}">
                    <MenuItem Header="Test" Command="{Binding TestCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.SelectedItem}" />
                    <Separator></Separator>
                    <MenuItem Header="Status" ItemsSource="{Binding DataContext.ObservableCollectionList}" DisplayMemberPath="Name" Command="{Binding Path=DataContext.UpdateCommand}" CommandParameter="{Binding Path=SelectedItem}"/>
                </ContextMenu>
            </ListView.ContextMenu>
//listviewstuff here
</ListView>

VM :

public class VM : ViewModelBase
{
    public RelayCommand UpdateCommand { get; private set; }
    public Action UpdateCommandAction { get; set; }
    public ObservableCollection<Status> ObservableCollectionList { get; set; }

    public VM()
    {
        this.UpdateCommand = new RelayCommand(new Action(() => this.UpdateCommandAction.DynamicInvoke())));
    }
}

Код программной части для представления XAML:

public partial class View
{
    public View()
    {
        InitializeComponent();
        var ViewDataContext = this.DataContext as VM;
        ViewDataContext .UpdateCommandAction = UpdateStatus;
    }


    private void UpdateStatus()
    {
        MessageBox.Show("test");
    }

}

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

0
JTester 22 Июл 2014 в 02:34
(У вас действительно есть свойство в вашей модели представления под названием DataContext? Если это так, это действительно сбивает с толку, и я бы его избегал)
 – 
H.B.
22 Июл 2014 в 03:00

2 ответа

Лучший ответ

Вам нужно привязать команду ко всем дочерним элементам, теперь вы привязываете ее к родительскому элементу, который проигнорирует ее, потому что у нее есть дочерние элементы (вместо этого открывается подменю).

Чтобы привязать его к дочерним элементам, вам понадобится ItemContainerStyle, создайте там Setter для Command. Вам нужно будет снова подняться, возможно это: {Binding DataContext.DataContext.UpdateCommand, RelativeSource={RelativeSource AncestorType=MenuItem}} (не уверен насчет AncestorLevel, если он выбирает себя, а не родительский, увеличивайте его; удвойте DataContext, потому что вы привязаны к DataContext.ObservableCollectionList, предполагая, что привязка действительно работает).

Точно так же в меню нет SelectedItem, вам нужен другой Setter для CommandParameter, он просто привяжется к текущему элементу, то есть {Binding}.


Изменить: Пример кода:

<MenuItem Header="Status"
          ItemsSource="{Binding DataContext.ObservableCollectionList}"
          DisplayMemberPath="Name">
  <MenuItem.ItemContainerStyle>
    <Style TargetType="MenuItem">
      <Setter Property="Command" Value="{Binding DataContext.DataContext.UpdateCommand,
                                             RelativeSource={RelativeSource AncestorType=MenuItem}}"/>
      <Setter Property="CommandParameter" Value="{Binding}"/>
    </Style>
  </MenuItem.ItemContainerStyle>
</MenuItem>
1
H.B. 22 Июл 2014 в 03:01
Спасибо, ваше решение сработало. К сожалению, я только что понял, что сделал ошибку. Я не был на 100% точен с вами. Контекстное меню должно быть уникальным для каждого элемента списка. Поэтому, если я щелкну правой кнопкой мыши строку 2, эти параметры должны повлиять на эту строку и не применяться ко всему представлению списка. Будет ли этот код по-прежнему работать или мне нужно внести изменения в приведенный выше код?
 – 
JTester
22 Июл 2014 в 04:26
@ user1296981: Это в основном зависит от того, где и как реализована ваша команда. У вас может быть либо одна команда, тогда вам нужно передать как элемент строки, так и любой параметр, который у вас есть, или у вас есть команда, реализованная как часть элемента, тогда вам просто нужно выполнить привязку относительно элемента списка (как вы уже сделать, установив DataContext меню на PlacementTarget), тогда команда должна просто взаимодействовать с этим соответствующим элементом.
 – 
H.B.
22 Июл 2014 в 04:58
Ну, идея в том, что у списка есть пользователи. Я щелкаю правой кнопкой мыши пользователя, и я могу изменить его статус. Я довольно новичок в этом, поэтому, возможно, я просто неправильно построил это. Но идея заключалась в том, чтобы щелкнуть правой кнопкой мыши «занятого» пользователя и установить его статус в один из вариантов в контекстном подменю, скажем, «Доступен». Мне нужно получить идентификатор пользователя И идентификатор статуса и передать их методу, чтобы обновить их как в БД, так и изменить свойство в приложении.
 – 
JTester
22 Июл 2014 в 05:02
@user1296981: user1296981: Тогда вашей пользовательской виртуальной машине просто нужно сохранить идентификатор в поле/свойстве, затем в конструкторе вы напрямую реализуете свою команду изменения статуса примерно так: new RelayCommand(param => UpdateStatus(ID, (Status)param)), param должны быть переданными CommandParameter и ID — это просто свойство виртуальной машины, содержащее идентификатор пользователя.
 – 
H.B.
22 Июл 2014 в 05:19
Ну, идентификатор пользователя не является статической переменной. Это список пользователей, поэтому, когда я щелкаю правой кнопкой мыши, мне нужен идентификатор пользователя, связанный с контекстным меню, из которого я выбрал статус.
 – 
JTester
22 Июл 2014 в 05:26

Вам понадобится List<MenuItem> MenuItems для привязки к свойству ContextMenu ItemSource как

public class MenuItem
{
    public string Header { get; set; }

    public ICommand Command { get; set; }
}

XAML: и установите itemContainerstyle

<ContextMenu ItemsSource="{Binding MenuItems}" >
        <ContextMenu.ItemContainerStyle>
            <Style TargetType="{x:Type MenuItem}" >
                <Setter Property="Header" Value="{Binding Header}"/>
                <Setter Property="Command" Value="{Binding Command}" />
            </Style>
        </ContextMenu.ItemContainerStyle>
    </ContextMenu>

И добавьте столько элементов контекстного меню, сколько захотите, в вашу модель просмотра, сколько захотите.

0
Kylo Ren 29 Янв 2016 в 20:17