Предоставить «триггер-метод» для модуля- (под) -обзора модели в WPF и MVVM - PullRequest
1 голос
/ 17 октября 2019

У меня есть другой вопрос для моего приложения WPF / MVVM, над которым я работаю некоторое время. Основная идея состоит в том, чтобы использовать главное окно, обеспечивающее панель навигации и ContentControl.

. Различные "Модули" построены как UserControl с каждым собственным ViewModel.

. Основной вызов основной видовой модели для запуска модуля:

private void ShowAddressModule() {
  ContentControlBindingProperty = new AddressModule(new AddressModuleViewModel);
}

. В реальном приложении видовые модели предварительно загружены и т. д., но запуск более или менее одинаков.

Модель основного представления содержит логическое свойство LongRunningOperation для выполнения нескольких операций в главном окне во время любой длительной операции. Как пример, показывающий загрузку изображения или отключение основной навигации при загрузке нового модуля или чего-либо еще.

Так что моя идея состоит в том, чтобы предоставить модулям (их моделям представления) возможность активировать этот «режим». Пример того, как это может выглядеть в модели представления модулей:

private void LoadContactList() {
  MainWindow.LongRunningOperation = true;
  LoadAllContactsInAThread(); /*Takes a long time*/
  MainWindow.LongRunningOperation = false;
}

Я попытался пометить свойство как статическое и общедоступное, но это не будет работать из-за события OnPropertyChanged.

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

MainWindow.ShowErrorMessageInStatusBar("The error xyz occured!");

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

Заранее спасибо за любые подсказки

С уважением Маркус

Ответы [ 2 ]

1 голос
/ 17 октября 2019

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

В вашей модели дополнительного вида могут быть такие события, как это:

Модель дополнительного вида

public delegate void OnLongRunningOperationStartedEventHandler(object sender);
public delegate void OnLongRunningOperationFinishedEventHandler(object sender);

public event OnLongRunningOperationStartedEventHandler OnLongRunningOperationStarted;
public event OnLongRunningOperationFinishedEventHandler OnLongRunningOperationFinished;

private void LoadContactList() {
  OnLongRunningOperationStarted?.Invoke(this);
  LoadAllContactsInAThread(); /*Takes a long time*/
  OnLongRunningOperationFinished.Invoke(this);
}

И ваша модель основного вида будет подключаться к ним следующим образом:

Модель основного вида

public bool LongRunningOperation { get; private set; }

// Keep track of the number of modules currently running long operations
private int _countLongRunningOperations = 0;

public LoadSubModules(){
    // Depending on how you load your sub modules, this piece of code could move around
    foreach (var module in submodules){
        module.OnLongRunningOperationStarted += Module_LongOperationStarted;
        module.OnLongRunningOperationFinished += Module_LongOperationFinished;
    }
}

private void Module_LongOperationStarted(object sender){
    _countLongRunningOperations += 1;
    LongRunningOperation = true;
}

private void Module_LongOperationFinished(object sender){
    _countLongRunningOperations -= 1;
    if (_countLongRunningOperations == 0) {
        LongRunningOperation = false;
    }

Тот же принцип (с использованием событий) можно использовать для всплытия сообщений об ошибках из каждого субмодуля в модель основного представления.

0 голосов
/ 17 октября 2019

Быстрый и очень грязный подход:

Получить ссылку на mainwindow из application.current.mainwindow. Приведите его к MainWindow. Это свойство, для которого установлено первое отображаемое окно - просто MainWindow является именем основного окна по умолчанию.

Затем вы можете установить для него свойство, если оно является общедоступным свойством зависимости. Убедитесь, что дп связывает twoway в своих метаданных.

Это плохо, потому что вы ссылаетесь на пользовательский интерфейс в своих моделях представления, и у вас нет приложения, когда вы запускаете тесты на моделях представления в каком-либо из запускающих тестов.

Быстрый и грязный подход

Добавьте публичное свойство в приложение и установите его для своего экземпляра mainwindowviewmodel в его ctor. Вы можете ссылаться на приложение из куска кода. Добавьте общедоступное свойство в mainwindowviewmodel и привяжите к нему.

Это плохо, потому что у вас нет приложения, когда вы запускаете тесты на моделях представления в каком-либо из них. Вы можете добавить статические данные с интерфейсом, абстрагируясь от этого, и обойти это.

Мое предложение

Это зависит от того факта, что вы можете использовать точечную нотацию для связывания иэто включает Content.IsBusy в yourcontentcontrol.

Таким образом, вы можете привязать родительское окно к свойству зависимостей любого usercontrol, который находится в его contentcontrol.

Добавить это свойство с помощью присоединенного свойстваи свяжите это с IsBusy в базовой модели представления. От этого унаследуйте модели представления ваших дочерних представлений.

Следует упомянуть, что привязка к присоединенному свойству немного странная, а не просто

 ElementName=YourContentControl, Path=Content.YourAttachedProperty

Вам нужно что-то вроде:

ElementName=YourContentControl, Path=Content.(local:AttachClass.YourAttachedProperty)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...