ViewModel Locator

412
09 декабря 2016, 08:45

У меня есть 3 ViewModel: базовая, и 2 дочерних. Хочу при помощи ViewModelLocator иметь возможность управлять свойством, которое находится в базовой ВМ, из дочерних, так чтобы они работали с одним и тем же экземпляром, а не каждый со своим, и соответственно обе реагировали на изменения. Конкретно в базовой ВМ есть bool свойство, которое должно меняться из других ВМ.
Пользовался этой статьей(https://msdn.microsoft.com/en-us/library/hh821028.aspx). Создал в App.xaml экземпляр ViewModelLocator, сам класс должен отдавать экземпляр нужной ВМ, когда я делаю на него Binding на Xaml.

UPD

Locator

public class ViewModelLocator
{
    private BaseViewModel baseVm;
    public BaseViewModel BaseVm
    {
        get { return new BaseViewModel(); }
    }
}

App.xaml

<viewModels:ViewModelLocator x:Key="ViewModelLocator"/>

MainPage.xaml элементы которые забиндены на нужные мне св-ва из BaseViewModel

<Image Visibility="{Binding IsFilterImgVisible, Source={StaticResource ViewModelLocator} ,Converter={StaticResource BooleanToVisibilityConverter}}"/>

<controls:ImageManipulatorControl 
      Visibility="{Binding IsUserControlVisibile, Converter={StaticResource BooleanToVisibilityConverter}}">
</controls:ImageManipulatorControl>

C контролом вообще отдельная беда, при такой записи, что-то прозрачное накладывается на часть экрана(подозреваю что это контрол, хотя bool изначально стоит false)

В базовой VM лежат bool свойства, которые меняются из дочерних VM применяя слово this., но результата никакого

Answer 1

Для решения проблемы создал Singleton класс в котором разместил все нужные свойства. Для обращения к ним использовал

MySingletonClass.InstanceProperty.PropertyToChange=/*value*/

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

"{Binding Instance.IsFilterImgVisible , Source={StaticResource EditModeSwitcher}"
Answer 2

Ох, это же UWP, там всё странно.

Я не нашёл метод «из коробки», как сделать так, чтобы View не знало о VM. Но это можно симулировать. Не знаю, насколько мой метод хорош, у меня мало опыта с UWP.

Итак, что мы делаем.

Для начала, главную VM и подчинённые VM создаём в классе App:

sealed partial class App : Application
{
    MainVM mainVM;
    public App()
    {
        SetupVM();
        // стандартный код, сгенерированный шаблоном:
        this.InitializeComponent();
        this.Suspending += OnSuspending;
    }
    void SetupVM()
    {
        mainVM = new MainVM();
        var partVM = new PartVM(mainVM);
        var anotherPartVM = new AnotherPartVM(mainVM);
        mainVM.Part = partVM;          
        mainVM.AnotherPart = anotherPartVM;  
    }

Далее, поскольку навигация идёт лишь через Frame.Navigate, в котором невозможно указать экземпляр, а только тип (почему??), я передаю VM как параметр, чтобы окно само себе установило его в качестве VM:

    protected override void OnLaunched(LaunchActivatedEventArgs e)
    {
        // тут много сгенерированного кода
        if (rootFrame.Content == null)
        {
            // здесь добавил mainVM вместо параметра
            rootFrame.Navigate(typeof(MainPage), mainVM);
        }
        // Ensure the current window is active
        Window.Current.Activate();
    }

Теперь в коде страницы:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        InitializeComponent();
    }
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        base.OnNavigatedTo(e);
        // вытаскиваем DataContext из параметров навигации
        DataContext = e.Parameter;
    }
    void OnNextClick(object sender, RoutedEventArgs e)
    {
        // при навигации в другое окно передаём ему DataContext
        Frame.Navigate(typeof(NextPage), DataContext);
        // это новое окно тоже должно будет вытащить его из параметра, как и это
    }
}

Теперь, вложенный UserControl. Ему нужно передать правильный DataContext:

<local:InnerControl DataContext="{Binding Part}"/>

Наконец, при каком-нибудь действии внутри UserControl'а получает управление его VM, которая имеет у себя ссылку на MainVM.

Всё!

Answer 3

Зачем делать свой велосипед, если можно воспользоваться готовым? Prism

READ ALSO
Наложение штампа времени на подпись

Наложение штампа времени на подпись

Добрый день! Как через C# CryptoApi вставить в подпись штамп времени, полученный от службы штампов времени (http://cryptoproru/tsp/tsp

411
Можно ли вызвать async/await действия в @Html.Action()

Можно ли вызвать async/await действия в @Html.Action()

Добрый день, господа! Есть необходимость вызвать дочерний action метод через @HtmlAction() (речь идет об ASP

379
Матрица (двумерный массив) в C# Windows Forms

Матрица (двумерный массив) в C# Windows Forms

Подскажите, пожалуйста, какой компонент в виде таблицы можно использовать в C# Windows Forms для ввода/вывода матрицы? (Что-то вроде StringGrid'а в Delphi)

617
Отправить почту, чтобы &ldquo;От кого&rdquo; стоял произвольный email

Отправить почту, чтобы “От кого” стоял произвольный email

Есть обратная связь, пользователь должен заполнить обязательное поле EmailПри нажатии на кнопку отправить, письмо отправляется на support@домен

284