Static Property Using Inotifypropertychanged. C#

INotifyPropertyChanged and static properties

If you're inclined to maintain that design then I would go with a solution like the following:

public static int MinimumLength
{
get { return _MinimumLength; }
set
{
if (_MinimumLength != value)
{
_MinimumLength = value;
OnGlobalPropertyChanged("MinimumLength");
}
}
}
static event PropertyChangedEventHandler GlobalPropertyChanged = delegate { };
static void OnGlobalPropertyChanged(string propertyName)
{
GlobalPropertyChanged(
typeof (ExampleClass),
new PropertyChangedEventArgs(propertyName));
}
public ExampleClass()
{
// This should use a weak event handler instead of normal handler
GlobalPropertyChanged += this.HandleGlobalPropertyChanged;
}
void HandleGlobalPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "MinimumLength":
if (length > MinimumLength)
length = MinimumLength;
break;
}
}

This is pretty much equivalent to maintaining a list of instances but I find it more maintainable and clearer. Also, you really need to use a weak event handler strategy, otherwise, your instances will not be garbage collected because they will always be associated with the static event which acts like a GC root.

You can read more about weak event handlers in the following blog posts (which were written by me so I'm biased):

.NET Weak Event Handlers – Part I

.NET Weak Event Handlers – Part I

In an unrelated note your code is currently firing property changed when in fact the property value did not change. For example:

  1. Set MinimumLength to 5;
  2. Set length to 10; (event fires since the value changes from the default 0 to 5)
  3. Set length to 11; (event fires but it should not since the length is still 5)

Static property using INotifyPropertyChanged. C#

Just pass null instead of this:

public static event PropertyChangedEventHandler StaticPropertyChanged;

private static void NotifyStaticPropertyChanged([CallerMemberName] string name = null)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(name));
}

See this blog post for details about static property change notification.

INotifyPropertyChanged for static variable

INotifyPropertyChanged works on instance properties. One solution is to use a singleton pattern and keep INotifyPropertyChanged, the other is to use your own event to notify listeners.

Singleton example

public sealed class MyClass: INotifyPropertyChanged
{
private static readonly MyClass instance = new MyClass();
private MyClass() {}

public static MyClass Instance
{
get
{
return instance;
}
}

// notifying property
private string privMyProp;
public string MyProp
{
get { return this.privMyProp; }

set
{
if (value != this.privMyProp)
{
this.privMyProp = value;
NotifyPropertyChanged("MyProp");
}
}
}

// INotifyPropertyChanged implementation
public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String info)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(info));
}
}
}

EDIT: In WPF 4.5, they introduced property changed mechanic for static properties:

You can use static properties as the source of a data binding. The
data binding engine recognizes when the property's value changes if a
static event is raised. For example, if the class SomeClass defines a
static property called MyProperty, SomeClass can define a static event
that is raised when the value of MyProperty changes. The static event
can use either of the following signatures.

public static event EventHandler MyPropertyChanged;
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged;

Notify binding for static properties in static classes

Similar to an implementation of INotifyPropertyChanged, static property change notification only works if you use the correct property name when firing the StaticPropertyChanged event.

Use the property name, not the name of the backing field:

public static string ErrorMessgae
{
get { return errorMessage; }
set
{
errorMessage = value;
NotifyStaticPropertyChanged("ErrorMessgae"); // not "errorMessage"
}
}

You should certainly also fix the misspelled property name:

public static string ErrorMessage
{
get { return errorMessage; }
set
{
errorMessage = value;
NotifyStaticPropertyChanged("ErrorMessage");
}
}

The binding should look like this:

Text="{Binding Path=(error:InteractionData.ErrorMessage)}"

See this blog post for details about static property change notification.


You may also avoid to write property names at all by using the CallerMemberNameAttribute:

using System.Runtime.CompilerServices;
...

public static event PropertyChangedEventHandler StaticPropertyChanged;

private static void NotifyStaticPropertyChanged(
[CallerMemberName] string propertyName = null)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
}

You could now call the method without explicitly specifying the property name:

NotifyStaticPropertyChanged();

Static property Not Updating Data

To implement data changed notify, you need to implement INotifyPropertyChanged Interface in Xamarin.forms.

Unfortunately, static classes cannot implement interfaces, so your solution will not work.

Usually, I create class and implementing INotifyPropertyChanged interface.

 public class DownloadDataPageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
private string _texty;
public string Texty
{
get => _texty;

set
{
_texty = value;
RaisePropertyChanged("Texty");
}
}
}

<ContentPage.Resources>
<local:DownloadDataPageViewModel x:Key="model1" Texty="this is test" />

</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="{Binding Texty, Source={StaticResource model1}}"
VerticalOptions="CenterAndExpand" />
</StackLayout>
</ContentPage.Content>

If you still want to use static property, you can take a look:

Can't bind static property in XAML (Xamarin Forms)

Inherit INotifyPropertyChanged for Static Event from abstract Class

WPF 4.5 supports binding to static properties, all you have to do is create a static event handler of the same name with the text "Changed" appended, and you invoke that instead of your StaticPropertyChanged:

public class MyStaticClass
{
public static event EventHandler MyStaticPropertyChanged;

private static string _MyStaticProperty = "Hello World!";
public static string MyStaticProperty
{
get { return _MyStaticProperty; }
set
{
if (_MyStaticProperty != value)
{
_MyStaticProperty = value;
MyStaticPropertyChanged?.Invoke(null, EventArgs.Empty);
}
}
}
}

Which you would bind to like this:

<TextBlock Text="{Binding Path=(vm:MyStaticClass.MyStaticProperty), Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />

Honestly though, this looks like more of an architectural issue to me. If you're using a dependency injection framework...and you should be....then there's absolutely no need to use static properties for anything, just place them in their own class and set up your DI to make it a singleton.

How can I bind property in a static class?

The Source expression must be Source={x:Static local:Global.Theme} - with braces:

<Border Background="{Binding Source={x:Static local:Global.Theme},
Path=PrimaryBackground}">

Since WPF 4.5 you can also bind directly to static properties.

Turn Theme into a property

public class Global
{
public static Themes.ThemeBase Theme { get; set; } = new NormalWhite();
}

and bind to it with a path expression in parentheses:

<Border Background="{Binding Path=(local:Global.Theme.PrimaryBackground)}">

In case you want to change the Theme value at runtime, you must also implement a change notification, as e.g. shown here: https://stackoverflow.com/a/41823852/1136211

Binding to a static property is not responding to PropertyChanged

The Source property is used to store the object which will be used as the alternative binding source (by default, bindings use DataContext).

<Button IsEnabled="{Binding Source={x:Static local:Analyze.DataPresent}}" />

So when you use the code above then the Static extension provides the current value of the DataPresent property and that value is stored in the Source property. In this case the binding uses a boxed constant value (true or false) as the source.

<Button IsEnabled="{Binding Path=(local:Analyze.DataPresent)}" />

But when you specify the Path property, the binding locates your static class and binds to the property. In this case the static DataPresent property is the source and the StaticPropertyChanged event is used to notify the binding about updates.

The INotifyPropertyChanged cannot be used in the case of binding to a static property because there is no instance is used to access that property. The corresponding static event must be used instead.

The name of the event must be equal to StaticPropertyChanged and its type must be EventHandler<PropertyChangedEventArgs>. Or the name must consist of two parts: the property name and suffix Changed. In the last case the event's type must be EventHandler because the event notifies only about changes of the corresponding property.

This means that:

  1. The class Analyze can be static because INotifyPropertyChanged isn't necessary.
  2. The event StaticPropertyChanged can be renamed to DataPresentChanged and its type can be changed to EventHandler.

In other words:

public static class Analyze
{
public static DataSet moodleData; // Dataset containing the log data for analysis
private static bool dataPresent = true;

public static Boolean DataPresent
{
get { return dataPresent; }
set
{
if (dataPresent != value)
{
dataPresent = value;
DataPresentChanged(null, EventArgs.Empty);
}
}
}

public static event EventHandler DataPresentChanged = delegate { };
}

Useful links:

  1. Binding.Source Property
  2. Binding to static properties


Related Topics



Leave a reply



Submit