Страницы

Поиск по вопросам

Показаны сообщения с ярлыком prism. Показать все сообщения
Показаны сообщения с ярлыком prism. Показать все сообщения

пятница, 31 января 2020 г.

Смысл от перегрузки метода SetProperty с Action в который нельзя передать объект

#c_sharp #mvvm #prism


В классе BindableBase есть 2 перегрузки метода

bool SetPropetry(ref T storage, T value, string propertyName = null);
bool SetPropetry(ref T storage, T value, Action onChanged, string propertyName
= null);


Не вижу в чем смысл данной перегрузки? Если это перегрузка для того что бы к примеру
повесить callback на сторонний View или ViewModel, то в чем смысл передавать Action,
если мне необходимо сослаться к примеру на ссылку какого то объекта текущей ViewModel,
или передать данные для валидации Model?

Простейшие перегрузки методов которые мне необходимы:

protected virtual bool SetProperty(ref T storage, T value, Action onChanged,
T2 obj,
    [CallerMemberName] string propertyName = null)
{
    if (!SetProperty(ref storage, value)) return false;
    onChanged.Invoke(obj);
    return true;
}

protected virtual bool SetProperty(ref T storage, T value, Action onChanged,
    ref T2 obj, [CallerMemberName] string propertyName = null)
{
    if (!SetProperty(ref storage, value)) return false;
    onChanged.Invoke(obj);
    return true;
}



  Q: Почему возник такой вопрос?
  
  A: До этого пользовался исключительно Catel, в котором изначально было описана
одна реализация установки значений полям, и оповещении подписчиков.


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


Ответы

Ответ 1



Смотрите, никаких проблем я тут не вижу. Проблемы в том, чтобы «засунуть» дополнительные параметры в Action, нет: вы просто делаете замыкание по нужным параметрам (например, () => ProcessOnPropertySet(this)). А вот на стороне фреймворка проблемы есть, потому что непонятно, какие именно параметры вам нужно передать. Вы хотите весь объект? Вы хотите новое значение свойства? Вы хотите проверить и возможно изменить значение свойства? Вы хотите отправить событие? Всё это можно легко выразить через Action при помощи замыкания. А если мы хотим избавиться от замыкания, то фреймворку нужно заранее угадать, какие параметры вам понадобятся. И самостоятельно определить нужную вам перегрузку. А это не так просто, потому что у каждого проекта свои, специфические требования. Поэтому универсальное решение с Action вполне катит.

Ответ 2



Данный вопрос следует задавать разработчикам Prism, но никак не в этом комьюнити. Не бывает идеальных API, которые бы устраивали всех. Тем не менее, это явно не худший пример, так как у тебя остаётся возможность реализовать собственную обёртку и передать менее общий делегат. Можно взглянуть на классический подход WindowsForms-приложений, в которых коллбеки строго ограничены сигнатурой (Object sender, EventArgs args). Легко найти такие варианты использования, в которых передаётся this, null, 'new EventArgs()' и т.д. И люди точно так же задаются вопросом - зачем так было делать? Prism наследует принципы .NET Framework и предоставляет минимально достаточный API, который программисты могут расширять для своих нужд. В данном случае такая возможность есть.

вторник, 9 июля 2019 г.

Не отображактся новое окно при RequestNavigation в Prism

Использую в приложении WPF и Prism c UnityContainer. Внутри приложения запускается отдельное окно со следующим содержимым:

То есть окно содержит регион, в котором по нажатию соответствующей RadioButton будет меняться содержимое. Для этого имеются соответствующие подокна и в стартовом модуле происходит их инициализация:
RegionManager.RegisterViewWithRegion("TypeSchemeRegion", typeof(SchemeAutoView)); RegionManager.RegisterViewWithRegion("TypeSchemeRegion", typeof(SchemeSingleView)); RegionManager.RegisterViewWithRegion("TypeSchemeRegion", typeof(SchemeSelectView));
При открытии окна из программы исполняется следующий код:
var schemeView = unityContainer.Resolve();
regionManager.Regions.Remove("TypeSchemeRegion"); RegionManager.SetRegionManager(schemeView, regionManager);
(SchemeView это самое запускаемое окно) В этом месте все три подокна имеются в списке Views у региона, активным окном (ActiveView) является SchemeAutoView. При старте окна отображается содержимое подокна SchemeAutoView. По нажатию соответствующей RadioButton исполняется код:
_regionManager?.RequestNavigate("TypeSchemeRegion", new Uri("SchemeSingleView", UriKind.Relative));
или:
_regionManager?.RequestNavigate("TypeSchemeRegion", new Uri("SchemeSelectView", UriKind.Relative));
Теперь, если проверить в Debuge содержимое региона, то активное окно соответственно меняется. Однако на экране ничего не происходит, по-прежнему отображается первое активное подокно. Для всех окон используется одна ViewModel. Самое интересное, что в главном окне приложения (Shell) используется эта же методика и все работает на "ура", а в отдельном окне не хочет работать. Что делаю не так?


Ответ

Нашел ошибку сам. Оказывается при работе с Prism, если стартуешь внутри программы новое окно, которое, скажем так, не находиться в контексте главного окна (Shell), необходимо процедуру регистрации окон в регионах повторять почти так же, как в стартовом модуле. Ну или, по крайней мере, у меня так произошло. Итак код при старте нового окна:
regionManager.Regions.Remove("TypeSchemeRegion"); var schemeView= unityContainer.Resolve(); RegionManager.SetRegionManager(schemeView, regionManager); RegionManager.RegisterViewWithRegion("TypeSchemeRegion", typeof(SchemeAutoView)); RegionManager.RegisterViewWithRegion("TypeSchemeRegion", typeof(SchemeSingleView)); RegionManager.RegisterViewWithRegion("TypeSchemeRegion", typeof(SchemeSelectView));
И еще очень важно сначала удалить необходимый регион, затем обязательно сделать Resolve соответствующего окна. В этот момент к окну привязывается ViewModel (если это необходимо) через Dependency Property, затем необходимо произвести переустановку RegionManager и новую привязку окон к региону. Дальше в соответствующих местах RequestNavigate работает без проблем.