WPF MVVM - Связывание команд внутри ItemsControl - PullRequest
9 голосов
/ 27 июня 2009

В настоящее время я конвертирую небольшой проект WPF в MVVM. У меня есть List<CustomObject> в ViewModel главного окна, к которому привязывается мой ItemsControl и который использует DataTemplate для построения пользовательского интерфейса каждого элемента. Мой старый код использовал обработчик событий внутри DataTemplate для обработки события щелчка. Я хочу использовать какое-то связывание команд для устранения моих обработчиков событий с выделенным кодом, но DataContext элементов в моем ItemsControl является объектом модели, поэтому в настоящее время я не могу связать ICommand из ViewModel.

Итак, я полагаю, что есть несколько способов атаковать это, и я не уверен, что это будет самый "MVVM" способ сделать это. Связывать ли ItemsControl.ItemsSource с коллекцией нового класса ViewModel, который представляет каждый элемент? Или я использую UserControls вместо DataTemplate, а затем я могу связать каждый UserControl с его собственным экземпляром ViewModel, который его представляет? Или есть какое-то выражение для привязки, которое я могу использовать для ссылки на DataContext окна, чтобы иметь доступ к привязке к ViewModel (когда я набираю это, это звучит плохо, поэтому я предполагаю, что это большое «НЕТ») идея)?

Кроме того, я хочу связать свою команду с событием LeftMouseButtonUp элемента управления Grid. Для Grid нет «Команды», поэтому я пытался использовать InputBindings. Я мог бы использовать статическую команду (например, одну из встроенных ApplicationCommands), но я не мог использовать выражение привязки для привязки к экземпляру ICommand, который является свойством ViewModel, поскольку MouseBinding.Command не является DependencyProperty.

Я не совсем понимаю, как обрабатывать события в MVVM, поэтому любая информация приветствуется.

Ответы [ 3 ]

19 голосов
/ 27 июня 2009

Связывать ли ItemsControl.ItemsSource с коллекцией нового класса ViewModel, который представляет каждый элемент?

Независимо от того, создаете ли вы CustomObjectViewModel для размещения команды или помещаете команду в ту же ViewModel, которая имеет список, действительно зависит от функции происходящего действия. Это что-то, что принадлежит CustomObject, или это что-то, что относится к вашей текущей ViewModel?

Или есть какое-то выражение для привязки, которое я могу использовать для ссылки на DataContext окна, чтобы иметь доступ к привязке к ViewModel (когда я набираю это, это просто звучит плохо, поэтому я предполагаю большое "НЕТ" "к этой идее)?

Это не так плохо, как кажется. Вам на самом деле не нужен DataContext окна, а только DataContext до того, как он переключился на отдельные элементы. Поэтому, если ваша команда была в том же ViewModel, в котором размещен список пользовательских объектов, вы можете привязать ее к одному из DataTemplate пользовательского объекта, используя любой из этих методов:

{Binding ElementName=uiCustomObjectsItemsControl, Path=DataContext.MyCommand}
{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemsControl}}, Path=DataContext.MyCommand}

Кроме того, что я хочу связать свою команду в это событие LeftMouseButtonUp Сетка контроля. Там нет "Команда" для Сетка, поэтому я пытался использовать InputBindings.

Для этого я бы использовал что-то вроде Поведение присоединенной команды , которое позволит вам присоединить ICommand к любому событию.

4 голосов
/ 27 июня 2009

Джош Смит написал отличную статью в MSDN здесь , где он рассказывает о привязке команд.

В вашем случае все сводится к следующему:

  • Вы не устраните ВСЕ свой код, но, вероятно, он будет выглядеть по-другому
  • Ваши CustomObjects, вероятно, должны будут иметь классы подшивки VM или сами виртуальные машины, чтобы воспользоваться преимуществами описанной им архитектуры RelayCommand.

НТН.

1 голос
/ 08 августа 2012

Вы можете попытаться сохранить свою Команду в своей Модели.

public class MyModel
{
    public MyModel()
    {
        MyCommand = new DelegateCommand(MyCommandExecute);
    }

    public ICommand MyCommandCommand { get; set; }

    private void MyCommandExecute()
    {
    }
}

И затем у вас должен быть ObservableList для списка ваших Предметов в вашей ViewModel как,

public class MyViewModel
{
    public MyViewModel()
    {
        MyStarterCommand = new DelegateCommand(MyCommandExecute);

        if (!IsDesignTime)//(bool)DependencyPropertyDescriptor.FromProperty(DesignerProperties.IsInDesignModeProperty, typeof(DependencyObject)).Metadata.DefaultValue;
            MyCommand.Execute(null);
    }

    private ObservableCollection<MyModel> list;
    private  ICommand MyStarterCommand { get; set; }

    public ObservableCollection<MyModel> List
    {
        get { return list; }
        set
        {
            list = value;
            RaisePropertyChanged(() => List);
        }
    }

    private void MyStarterCommandExecute()
    {
        List = new ObservableCollection<MyModel>();

        //Fill the list here
        List.Add(new MyModel());
    }
}

Тогда в XAML вы должны сказать:

<ItemsControl ItemsSource="{Binding List}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Content="MyButton" Command="{Binding MyCommand}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...