Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

View is not getting notified when value of static Property Changes

Tags:

c#

wpf

xaml

I have a ViewModelBase class as follows:

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public static event PropertyChangedEventHandler GlobalPropertyChanged = delegate { };
    public static void OnGlobalPropertyChanged(string propertyName, Type className)
    {
        GlobalPropertyChanged(className,new PropertyChangedEventArgs(propertyName));
    }
}

Now, I have another viewModel called GroupViewModel which inherits ViewModelBase:

public class GroupViewModel : ViewModelBase
{
    public GroupsViewModel()
    {
        CurrentGroup = new Group();
    }

    private static Group _currentGroup;
    public static Group CurrentGroup
    {
        get
        {
            return _currentGroup;
        }
        set
        {
            _currentGroup = value;
            OnGlobalPropertyChanged("CurrentGroup", typeof(Group));
        }
    }
}

Now in Groups.xaml Page :

<Grid DataContext="{Binding CurrentGroup}">
    .....
    .....
    <TextBlock Text="{Binding GroupName, TargetNullValue=''}" />
    .....
    .....
</Grid>

I have another ViewModel called MainWindowViewModel, I try to save CurrentGroup to Database like below code and then I set CurrentGroup = new Group(); but in Group.xaml the text of TextBox is not cleared :

Group group = GroupViewModel.CurrentGroup;
db.Groups.Add(group);
db.SaveChanges();
GroupViewModel.CurrentGroup = new Group();

Update:

If I use the below code in GroupsViewModel, the output is as expected. I mean View is updated when Static property changes.

public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged
         = delegate { };
private static void NotifyStaticPropertyChanged(string propertyName)
{
   StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
}

If I use that same code in ViewModelBase (Please note that GroupsViewModel inherits ViewModelBase) then View is not updated when value of static property changes. Also I have marked the NotifyStaticPropertyChanged as public in this case to avoid the compile time errors like errors about protection level.

like image 269
Vishal Avatar asked Dec 11 '22 07:12

Vishal


2 Answers

For Static PropertyChanged you have to create generic static event like this in your class:

public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged
         = delegate { };
private static void NotifyStaticPropertyChanged(string propertyName)
{
   StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
}

and you have to call like you use to do instance properties:

NotifyStaticPropertyChanged("CurrentGroup");

But main catch is in XAML where you are binding -

You'll use parentheses around the namespace, class, and property because WPF binding engine parse the path as ClassName.PropertyName rather than PropertyName.PropertyName.

So, it will be like this:

<Grid DataContext="{Binding Path=(local:GroupViewModel.CurrentGroup)}">
  .....
  .....
  <TextBlock Text="{Binding GroupName, TargetNullValue=''}" />
  .....
  .....
</Grid>

Source here INPC for static properties.


UPDATE

If I use that same code in ViewModelBase (Please note that GroupsViewModel inherits ViewModelBase) then View is not updated when value of static property changes.

StaticPropertyChangedEvent have to be in same class where property resides. It won't work like traditional INotifyPropertyChanged for instance properties.

I don't have any MSDN documentation to assert that but I verified it by tweaking event code a bit to see if XAML is hooking onto StaticPropertyChangedEvent from XAML.

Replace event code to this and you can see yourself:

private static event EventHandler<PropertyChangedEventArgs> staticPC
                                                     = delegate { };
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged
{
   add { staticPC += value; }
   remove { staticPC -= value; }
}
protected static void NotifyStaticPropertyChanged(string propertyName)
{
   staticPC(null, new PropertyChangedEventArgs(propertyName));
} 

Put a breakpoint on add and you will see it will get hit since WPF binding engine internally hook to it to listen to static property changed events.

But as soon as you move that to base class ViewModelBase, breakpoint won't get hit. Since, WPF haven't hook to it so any changes in property won't update UI obviously.

like image 119
Rohit Vats Avatar answered Jan 26 '23 00:01

Rohit Vats


Whenever you want to update the property changes of a particular data type, you need to implement the INotifyPropertyChanged interface in that data type. This means that if you want to update the property changes of a view model, in your case a change to the CurrentGroup object, you'd need to implement the INotifyPropertyChanged interface in your view model.

However, it seems as though you actually want to update the property changes that have been made inside the CurrentGroup class (to clear them), so in that case, you'd need to implement the INotifyPropertyChanged interface in your CurrentGroup class as well. I believe that that is what @Silvermind meant by You would need to raise the event that is associated with the instance.

like image 35
Sheridan Avatar answered Jan 26 '23 01:01

Sheridan