0

I have a static bool property in a Model class, which I expose to two different ViewModel classes. One of these ViewModel's has a bool property linked to said static property and is bound to the Visibility of a button via a converter. This can then be set within that ViewModel to true or false and the button's visibility changes accordingly. (The instance of this ViewModel is set in the XAML of the View, via DataContext, in which the button resides) I want to be able to change this buttons visibility from within a different View, and I thought that by having a property in my separate View's ViewModel that is also linked to my static bool in my original model, I could do this, but it isn't doing anything.

Here's my code:

MainModel

public class MainModel
{
    static bool _ButtonIsVisible = true;

    public static bool ButtonIsVisible
    {
        get { return _ButtonIsVisible; }
        set { _ButtonIsVisible = value; }
    }
}

MainViewModel

class MainViewModel: ObserveableObject
{
    public bool ButtonIsVisible
    {
        get { return MainModel.ButtonIsVisible; }
        set
        {
            MainModel.ButtonIsVisible = value;
            RaisePropertyChanged("ButtonIsVisible");
        }
    }
}

MainView

<Window x:Class="MVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    xmlns:local="clr-namespace:MVVM"  
    mc:Ignorable="d"
    Title="MainWindow" Width="1920" Height="1080" WindowState="Maximized" WindowStyle="None">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Window.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVisConverter"/>
    </Window.Resources>

    <Button Visibility="{Binding ButtonIsVisible, Converter={StaticResource BoolToVisConverter}}" />
</Window>

ButtonIsVisible from MainViewModel is changed within a command and this works as is expected. This is where my troubles occur.

AnotherViewModel

class AnotherViewModel: ObserveableObject
{
    public bool ButtonIsVisible
    {
        get { return MainModel.ButtonIsVisible; }
        set
        {
            MainModel.ButtonIsVisible = value;
            RaisePropertyChanged("ButtonIsVisible");
        }
    }
}

An instance of AnotherViewModel is created via the DataContext of it's corresponding view, and a command is bound to a button within this view in which I change the ButtonIsVisible property from AnotherViewModel, at which point I would expect my button from my MainView to change, seeing that both ViewModels get and set the values of the properties in question from a static property in my MainModel, but this isn't working. Can anyone tell me what I'm doing wrong?

howamith
  • 181
  • 3
  • 15
  • Now i can't tell you why it's not working but I really sounds bad to me using a static property to do this. I'd rather change `MainViewModel` `ButtonIsVisible`property from `AnotherViewModel`,maybe sending `MainViewModel`instance to `AnotherViewModel` in a constructor. – Pikoh May 05 '16 at 14:34
  • Now that I think about it, in `AnotherViewModel` you call `RaisePropertyChanged`, but that would affect to the view of `AnotherViewModel`, not to `MainView`. `MainView` is not getting the property changed event... – Pikoh May 05 '16 at 14:42
  • I have to admit even I myself don't like using static properties to do this. I may find a better way at a later date but I'm going with this for now to get the ball rolling. Your second comment makes sense, but is there any way I can get around this? Can I notify `MainViewModel` of a change made in `AnotherViewModel`? – howamith May 05 '16 at 14:44
  • @Howard_Schmidtt Here, a better way means a way that actually works. Your approach simply doesn't, because setting the property in one view model won't fire the PropertyChanged event in the other – Clemens May 05 '16 at 14:47
  • @Clemens the only other way I can think of to achieve what it is I'm trying to do is to do this stuff in the code behind for my views, but I thought that was somewhat frowned upon in MVVM? – howamith May 05 '16 at 14:50
  • 3
    Well, there are several ways to do this, from very simple to very complicated. You could, for example, use an EventHandler to notify the mainview that it has changed. But I would go with the simple solution I told you before: passing the MainViewModel instance to th AnotherViewModel and change the property from there. Also, that way you get rid of that ugly static property – Pikoh May 05 '16 at 14:50
  • I'm more than happy to give that a go however I'm not entirely sure what you mean and how I would do that - do you mean pass the instance of `MainViewModel` I create in the xaml to `AnotherViewModel`? – howamith May 05 '16 at 14:56
  • I'll try to explain it better in an answer, but first of all..i guess you show the `AnotherView` window from `MainViewModel` doing something like `AnotherView w= new AnotherView(); w.Show()`? – Pikoh May 05 '16 at 15:02
  • `AnotherView` is actually a UserControl that I bring into sight via a ControlControl as Sheridan suggests [here](http://stackoverflow.com/questions/19654295/wpf-mvvm-navigate-views) minus the command at the bottom of the answer. – howamith May 05 '16 at 15:45
  • Ok, see my answer and tell me if it fits you. – Pikoh May 05 '16 at 16:02

1 Answers1

1

As per your comments, you've got something like this:

<ContentControl Content="{Binding ViewModel}" />

And when you want to show it, you are doing this:

ViewModel = new AnotherViewModel();

So what you need in your AnotherViewModel is:

MainViewModel MVM;

public AnotherViewModel(MainViewModel _mvm)
{
     this.MVM=_mvm;
}

You must then change your AnotherVieModel Instantation to:

ViewModel = new AnotherViewModel(this);

And when you want to change the button's visibility,you'll just need to do this:

this.MVM.ButtonIsVisible=true;

As I told you,this is just a way to do it, but I think is pretty straightforward and understable. If you've got doubts, feel free to ask.

Pikoh
  • 7,582
  • 28
  • 53
  • I see where you're coming from and it does indeed look relatively straight forward and simple, which is great! I do have one question though, when you say: "You must then change your AnotherViewModel Instantation to: `ViewModel = new AnotherViewModel(this);`" where exactly would this go? As it stands my instantation of my AnotherViewModel is done in the xaml of it's corresponding View. – howamith May 05 '16 at 17:50
  • Well,i always do the instantation of the viemodel in the code behind. I suggest that you remove it from xaml and in your MainViewModel do something like `AnotherView w=new AnotherView(); w.DataContext=new AnotherViewModel(this); w.Show();` but without seeing how exactly is your code i can't tell you any more :) – Pikoh May 05 '16 at 18:02
  • I managed to do `SelectedViewModel = new AnotherViewModel(this);` when I go to switch views which works, however when I try `this.MVM.ButtonIsVisible = true;` I get a NullReferenceException, telling me that MVM has not been set to an instance of an object, however I can see it is being set to my MainViewModel when I change views, so why it becomes null afterwards is beyond me? Thanks for your help by the way! I'm definitely moving in the right direction, I feel I'm nearly there with this now! – howamith May 05 '16 at 18:13
  • Without seeing your code i just can guess. Maybe you are still instantiating the viewmodel in you xaml? If so,remove it – Pikoh May 05 '16 at 18:26
  • Stepping through the code I can see that when I switch views, I'm passing in my `MainViewModel` and that's fine, however as I'm creating a design time instance of `AnotherViewModel` in my AnotherView xaml it is of course null! looks like I am indeed going to have to Instantiate in the codebehind files of my views. – howamith May 05 '16 at 18:28
  • I removed my designtime instance and it works! Thanks a lot! – howamith May 05 '16 at 18:50