Static binding doesn't update when resource changes
First of all, your property
is actually not a property, but a field. A minimal property declaration would look like this:
public static SolidColorBrush Property { get; set; }
Please note the name is starting with an uppercase letter, which is a widely accepted coding convention in C#.
Because you also want to have a change notification fired whenever the value of the property changes, you need to declare a property-changed event (which for non-static properties is usually done by implementing the INotifyPropertyChanged interface).
For static properties there is a new mechanism in WPF 4.5 (or 4.0?), where you can write a static property changed event and property declaration like this:
public static class AppStyle
{
public static event PropertyChangedEventHandler StaticPropertyChanged;
private static void OnStaticPropertyChanged(string propertyName)
{
StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
}
private static SolidColorBrush property = Brushes.Red; // backing field
public static SolidColorBrush Property
{
get { return property; }
set
{
property = value;
OnStaticPropertyChanged("Property");
}
}
public static void ChangeTheme()
{
Property = Brushes.Blue;
}
}
The binding to a static property would be written with the property path in parentheses:
Background="{Binding Path=(style:AppStyle.Property)}"
How to update binding dynamically when source object changes?
You don't have to make the PageInformationProperty a dependency property just for this binding. Implement INotifyPropertyChanged in the code behind.
Also since you are actually binding to "UserControlPath", make sure that this property actually sends change notifications.
Two-way data binding with converter doesn't update source
With hints from several similar questions and almost answers here on SO, I have a working solution that preserves the binding. You can manually force the binding to update the source in a strategically placed event, such as LostFocus:
private void mycontrol_LostFocus(object sender, RoutedEventArgs e)
{
if (mycontrol.IsModified)
{
var binding = mycontrol.GetBindingExpression(MyControl.SampleProperty);
binding.UpdateSource();
}
}
How to update property binding when changing the culture of the application at runtime in WPF .net core 5
The Answer
App.xaml.cs
public App()
{
CultureInfo CultureInformation = new CultureInfo("en-US");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
CultureInfo.DefaultThreadCurrentCulture = CultureInformation;
CultureInfo.DefaultThreadCurrentUICulture = CultureInformation;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
FrameworkElement.LanguageProperty.OverrideMetadata(typeof(FrameworkElement), new FrameworkPropertyMetadata(language));
}
MainWindow.xaml.cs
private void UpdateLanguage(string Language)
{
LanguageComboBox.SelectedValue = Properties.Settings.Default.Language = Language;
Properties.Settings.Default.Save();
//
ResourceDictionary Dictionary = new();
Dictionary.Source = new Uri(@$"..\Languages\{Language}.xaml", UriKind.Relative);
Resources.MergedDictionaries.Clear();
Resources.MergedDictionaries.Add(Dictionary);
//
if (Language == "العربية")
{
CultureInfo CultureInformation = CultureInfo.CreateSpecificCulture("ar-EG");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = CultureInformation;
Thread.CurrentThread.CurrentUICulture = CultureInformation;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
this.Language = language;
}
else if (Language == "English")
{
CultureInfo CultureInformation = CultureInfo.CreateSpecificCulture("en-US");
CultureInformation.DateTimeFormat.ShortDatePattern = "dd/MM/yyyy";
CultureInformation.DateTimeFormat.LongDatePattern = "ddd, dd/MM/yyyy";
Thread.CurrentThread.CurrentCulture = CultureInformation;
Thread.CurrentThread.CurrentUICulture = CultureInformation;
//
XmlLanguage language = XmlLanguage.GetLanguage(CultureInformation.IetfLanguageTag);
const BindingFlags kField = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly;
typeof(XmlLanguage).GetField("_equivalentCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_compatibleCulture", kField).SetValue(language, CultureInformation);
typeof(XmlLanguage).GetField("_specificCulture", kField).SetValue(language, CultureInformation);
this.Language = language;
}
}
There is NO ConverterCulture class
public class CultureAwareBinding : Binding
{
public CultureAwareBinding()
{
ConverterCulture = CultureInfo.CurrentCulture;
}
}
UserControl.xaml (Normal Binding)
<TextBlock Grid.Row="5" FontSize="14" FontFamily="{StaticResource Segoe Semibold}" Foreground="{DynamicResource BackgroundBrush}">
<TextBlock Text="{Binding Path=StartTime, StringFormat={}{0:hh:mm tt}}"/>
<TextBlock Text="" FontSize="12" FontFamily="{StaticResource Segoe Icons}"/>
<TextBlock Text="{Binding Path=EndTime, StringFormat={}{0:hh:mm tt}}"/>
</TextBlock>
WPF Bind to sys:Boolean not updating
ResourceDictionary
doesn't have any events that are raised when a resource is changed, and generally speaking, you don't use resources for this purpose. Usually, resources are used for things you want to create once and share, like styles, or things like images, brushes, etc. I would even go so far as to say you generally don't want to put something in your ResourceDictionary
that could change at some point.
Recommendation: use INotifyPropertyChanged
WPF relies on two interfaces for change notification: for properties, you need to implement INotifyPropertyChanged
. For collections, implement INotifyCollectionChanged
(or more simply, just use an ObservableCollection<T>
, which handles it all for you).
So you create a class:
public class CheckInternetModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool m_InternetConnected;
public bool InternetConnected
{
get { return m_InternetConnected; }
set
{
m_InternetConnected = value;
OnPropertyChanged();
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You can make this your control's DataContext
and change your binding to {Binding InternetConnected}
.
If you really want to use resources, you could add an instance of this class to your Resources:
<Window.Resources>
<vm:CheckInternetModel x:Key="CheckInternetModel"/>
</Window.Resources>
Your binding becomes...
<TextBlock Text="{Binding InternetConnected Source={StaticResource CheckInternetModel}, Converter={StaticResource BooleanToStringConverter}, StringFormat=Internet: {0}}" />
Your timer.Tick
becomes...
((CheckInternetModel)Application.Current.Resources["CheckInternetModel"]).InternetConnected = new CheckInternet().Status;
Workaround: manually invalidate the binding
If you insist on storing this as a boolean in the resource dictionary, the only solution left is to manually invalidate the binding using DependencyObject.InvalidateProperty
. So you'll have to give your TextBlock
a name and then from within your timer.Tick
handler, add:
textBlock.InvalidateProperty(TextBlock.TextProperty);
That's not enough though. Your binding is to a StaticResource
, so it will not query the ResourceDictionary
to get the resource again. You'll have to change the binding to:
<TextBlock Text="{Binding Source={DynamicResource InternetConnected}, Converter={StaticResource BooleanToStringConverter}, StringFormat=Internet: {0}}" />
A DynamicResource
forces the binding to look up the resource again each time it's requested, so when you invalidate the TextProperty
, it'll retrieve InternetConnected
from the dictionary again and it'll have the new value.
wpf using a static flag to update a property in a view model
The reason why your code doesn't work is that your static property has no change notification. So your triggers will never fire.
You may want to consider having your RefreshTitleBar
property as a standard INotifyPropertyChanged
property, buy put it into a singleton class. This way you will only have one instance of the class for your whole application and you'll get the change notifications you need.
You can implement change notification for a static property, but it's a little more difficult.
Binding static property and implementing INotifyPropertyChanged
I hope this helps.
Related Topics
End of Central Directory Record Could Not Be Found
3D Relative Angle Sum Calculation
How to Implement Gzip Compression in ASP.NET
Getting All Changes Made to an Object in the Entity Framework
C# - Volatile Keyword Usage VS Lock
How to Run Multiple SQL Commands in a Single SQL Connection
Get Number of Listeners, Clients Connected to Signalr Hub
Simple Way to Copy or Clone a Datarow
How to Load Assembly at Runtime and Create Class Instance
Windows 10 Scrollintoview() Is Not Scrolling to the Items in the Middle of a Listview
Resharper Warning - Access to Modified Closure
Wrap C# Application in .Msi Installer
Handling the Window Closing Event with Wpf/Mvvm Light Toolkit
How to Print Out a Tree Structure
Hosting Clr in Delphi With/Without Jcl - Example
.Net, Event Every Minute (On the Minute). Is a Timer the Best Option