WPF / MVVM: Как ссылаться на представление из ViewModel - PullRequest
0 голосов
/ 19 января 2020

Рассмотрим довольно классическую / простую конструкцию MVVM с элементами, которые отображаются с использованием Xaml-привязок к ViewModels для каждого элемента, соответственно. Элементы можно выбирать, а у ViewModels есть свойство IsSelected, которое вызывает событие PropertyChanged для свойства, относящегося к дизайну, например, BorderBrush, чтобы пользовательский интерфейс мог правильно обновлять себя.

Необходимое взаимодействие с мышью осуществляется путем прослушивания событий туннелирования и всплытия родительского контейнера, оценки e.OriginalSource.DataContext и, в конечном итоге, установки ViewModel.IsSelected в одну или другую сторону.

Это работает нормально, если «относящиеся к дизайну» изменения могут обрабатываться только связанным элементом управления, но я хотел бы добавить Adorner для каждого выбранного элемента / элемента управления и использовать его для выделения c пользовательских взаимодействий, например, select, move, размер. Это не проблема, если взаимодействие начинается и затрагивает только один из связанных с ViewModel элементов управления, потому что тогда элемент управления известен в области действия моего кода. Но если выбрано несколько элементов (например, с помощью команды «выбрать все»), как мне получить доступ к представлению / элементу управления всех затронутых моделей представления, чтобы я мог создать Adorner для каждого элемента, который может использовать визуальные элементы целевого элемента управления, позиция или размер?

Я понимаю принцип MVVM (или намерение, стоящее за ним), что ViewModel не должен зависеть от View, но я не вижу другого пути и мне интересно, как лучше реализовать решение .

В настоящее время мой подход включает в себя что-то вроде этого:

public interface IViewModel{
    FrameworkElement Element {get; set;}
}

public partial class MyItemControl : UserControl
{
    public MyItemControl()
    {
        InitializeComponent();

        this.DataContextChanged += OnDataContextChanged;
    }

    private void OnDataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        (e.NewValue as IViewModel)?.Element = this;
    }
}

Есть ли другой способ, например, через привязки Xaml? Обычно я не предпочитаю чистые решения Xaml, но в этом случае это поможет мне избежать требований к элементам управления - или мне вообще потребуется использовать элементы управления.

И: действительно ли это нарушение упомянутого принципа?

1 Ответ

0 голосов
/ 20 января 2020

Модель представления никогда не должна напрямую обращаться к представлению. Без исключений. За последние 15 лет я работал над некоторыми чрезвычайно сложными приложениями WPF и ни разу не сталкивался с делом, которое нельзя было бы элегантно решить без нарушения этого фундаментального правила.

Чтобы ответить на ваш вопрос, есть Есть несколько способов сделать это, хотя, какой вариант вы выберете, будет зависеть от ваших обстоятельств. Одним из самых простых является использование поведения. Вы присваиваете этому поведению некоторые свойства зависимостей, которые вы связываете со свойствами INP C в своей модели представления, и вы пишете код для соответствующего создания / обновления своих украшателей.

Имейте в виду, что поведение на самом деле просто другая форма кода, хотя и немного более абстрактная. Многие люди попадают в ловушку использования поведений и конвертеров для реализации функциональности, которая может быть легко реализована с помощью таких вещей, как DataTriggers. Опять же, специфика будет зависеть от того, что вы пытаетесь сделать.

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