I have 3 ViewModel : base, and 2 child. I want with the help of ViewModelLocator be able to manage the property that is in the base VM from the children so that they work with the same instance, and not each with its own, and accordingly both react to the changes. Specifically, in the base VM there is a bool property, which should change from other VMs.
Used this article ( https://msdn.microsoft.com/en-us/library/hh821028.aspx ). I created App.xaml instance of ViewModelLocator in App.xaml , the class itself must give an instance of the required VM when I do Binding on it on 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 elements which are zabindeny on the necessary me sv-va from BaseViewModel

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

With a control, there is generally a separate problem, with such a record, something transparent is superimposed on a part of the screen (I suspect that this is control, although the bool initially false )

In the base VM, there are bool properties that change from the child VMs using the word this. but no result

  • one
    If the child VMs want to work with the base one, why not just pass the link to the base one in the constructor? Locator is needed rather for some more advanced and complex scenarios. - VladD
  • The constructor of the child VM should get a reference to the base one? Or should both get links? - SmiLe
  • Well, I would do that, yes. Would distribute in the designer of child VM to them the link to basic VM. - VladD
  • And if I already have instances of these VMs in App.xaml , I can immediately refer to them or need to write BaseViewModel = new BaseViewModel() - SmiLe
  • @VladD Xaml swears that it cannot use constructors, because I specified BaseViewModel - SmiLe

3 answers 3

To solve the problem, I created the Singleton class in which I placed all the necessary properties. To refer to them, I used

 MySingletonClass.InstanceProperty.PropertyToChange=/*value*/ 

during Binding it is also necessary to add Instance in order to refer to an existing instance of the class and, accordingly, properties

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

    Oh, it's a UWP, everything is strange.

    I did not find an out-of-box method for making View not aware of VM. But it can be simulated. I do not know how good my method is, I have little experience with UWP.

    So what we do.

    To begin with, we create the master VM and slave VMs in the App class:

     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; } 

    Further, since the navigation is only through Frame.Navigate , in which it is impossible to specify an instance, but only the type (why ??), I pass the VM as a parameter so that the window itself will set it as a 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(); } 

    Now in the page code:

     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); // это новое окно тоже должно будет вытащить его из параметра, как и это } } 

    Now, nested UserControl . It needs to pass the correct DataContext :

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

    Finally, for some action inside UserControl, it gets control of its VM, which has a link to MainVM .

    Everything!

    • In the navigation parameters it is recommended to pass primitive types (“recommended” in this case means that only they should be transferred), because when the application goes to sleep it will fall, because will not be able to serialize something complicated. If you need to pass an object, you should serialize it and pass it as a string. - Make Makeluv
    • @VladD var partVM = new PartVM (mainVM); The PartVM constructor has no parameters, but takes 1 argument, the same as the next line. If you add a basic VM to the PartVM constructor then says that the basic view model is type, invalid in the current context joxi.ru/RmzYVGOiKWZVrO - SmiLe
    • @MakeMakeluv: Oh my gosh! And how then to transfer VM for View outside? - VladD
    • @SmiLe: Uh ... Well, damn, would you read the textbook for a start. BaseViewModel is a type, not a variable. Formulate in words where your main VM is, and where its nested, and what types they have. In accordance with this, it will be clear what to do. - VladD
    • @VladD Why send it? On the topic of the question - why should this property be stored in the VM? You can render it as a static property in an external static class. And you can also use EventAggregator if you use Prism again. - Make Makeluv

    Why make your bike if you can use ready? Prism