I am trying to come up with a solution for the following problem:
I have a DateTimeRange class which contains 3 properties:
Start: DateTime
End: DateTime
Length: Length (=End-Start)
This class is used throughout my project as dependency property on various controls. This values are mutable, for example, if the Start changes, the End will be moved with the same offset (keeping the same Length).
My problem is that in code that listens for updates of the range, does not recieve an event when any of the properties have changed, only when the complete object is replaced.
I want to let the DateTimeRange class notify the user that the whole object has changed when a property is changed, not just one property.
I have tried to make DateTimeRange an immutable struct. But this makes two way DataBinding to any of it's properties impossible.
Does anybody have a suggestion how to do this? IMO this problem is very frustrating, as the same problem happens with Margins for example (you cannot bind to Margin.Left of a control).
The framework does not really support this requirement. The approach I would take would be to make DateTimeRange implement INotifyPropertyChanged, raising the event whenever any of its properties change. On a class that has DateTimeRange as a dependency property add / remove handlers for the INotifyPropertyChanged as the property changes. Within your handler for this event you can then perform the action you require.
Note, you could make DateTimeRange a DependencyObject, which would allow you to create two way bindings to its properties.
Related
I have a class with properties and collections. It also has a property called Dirty. I want to set this Dirty flag if the state of an instance of this class changes in any way.
Obviously for the properties, I can just set this in the setter. However, I'm unsure of the best way of detecting a change in the collection. Whilst I could create my own collection class that derives from the .NET collection class and do it that way, I'm wondering if there's another way which doesn't require my own custom collection type?
Update for clarification
Just to clarify, I don't need to track in a nested way - I literally just want to know if items have been added/removed from the collection.
With your edit, ObservableCollection<T> would be an excellent choice. It implements INotifyCollectionChanged, so it will raise an event whenever an item is added or removed.
Note that this class is used all the time in WPF for that exact purpose, so the framework can listen to that event and add/remove UI elements as necessary.
See ObservableCollection which contains the CollectionChanged event.
Be wary however that ObservableCollections are not thread-safe, though there are several tutorials/articles/projects on how to implement such a thing
I have a custom Control with dependency property attached by its parent and i need to implement some hook that will be triggered on all attached property changes. In WPF it was rather easy but i have no idea how this can be achieved in WinRT environment.
For example, i have Control with attached property X and its parent is GraphArea. So attached property for Control is GraphArea.X.
Please give me some clues, thanks :)
Found the way to do this though not exactly as i wanted to. Instead of hooking to X change inside every Control i've hooked to attached property changed callback of the parent.
Additionaly, i've implemented new interface for all children that must receive notification when this property changes. And as i've implemented interface methods as explicit interface implementations they are not be visible from derived classes (which is good as this operation must be internal).
Another solution is to make code-behind binding between dependency property and attached property and define OnChanged callback for DP. But in WinRT this approach only works for internal Attached Properties (not the custom created).
I am doing an app in C#, Windows Forms.
In this app I have a main form that has several Elements in it. This "Element" class is inherited by others ("ElementLabel","ElementPicture","ElementGraph").
At some point i might want to change in "batch" mode some property of several elements, whichever they are. For example, I might want to change the property "Value" of all the selected elements.
The problem is, for example, when the property "Value" is changed in the parent class, I also want to change the property "Text" of a "Label" that exists in the child class "ElementLabel". I've seen a lot of topics on changing the parent through the child, but not otherwise.
Am I missing something here or do I just have a bad design and a situation like this isn't even supposed to happen?
Thanks in advance
Well its hard to say what the best option is without knowing more about your architecture, but subclasses can intercept events in the parent class by overriding methods. For example, in your ElementLabel class:
public override void set(String key, object newValue) {
if (key.Equals("Value"))
set("Text", "New label text!");
base.set(key, newValue);
}
If you want a more general solution, you could include an observer pattern in your parent class; see the wikipedia page
You could use for the data a class (or classes) that implements INotifyPropertyChanged.
Then you would have to pass to the child controls references to a "master" property that you used to control the state. (It would be ideally used by a Controller class.) (I'll refer to this object as the "master property object".)
Each of the child controls would subscribe to the PropertyChanged event.
Then when the Controller changes the value of one of the master property object's properties, it will raise the PropertyChanged event, and each interested child can respond appropriately.
This approach helps to decouple the controller from the views.
The sequence is:
Before creating the child controls, create the master property object. Keep a reference to this in the Controller or Main Form (if you're using that as a controller).
Pass to each child control that needs it, a reference to the master property object.
Each child control should subscribe to the master property object's PropertyChanged event.
Write an appropriate handler for each child. It will have access to a reference to the master property object, so it will be able to see the new values of any properties.
When a property needs to be changed, the Controller simply sets the property as desired. The property setter implementation should raise the PropertyChanged event, and that will notify all the interested child controls, who will update their UI in response.
[EDIT] This is in fact an implementation of the Observer pattern that Reyan mentioned above.
I have an ObservableCollection that's binded to a WPF ListView, and all the values appear correct. But how can I get a notification when something that has a 2-way binding changes?
Should I use INotifyPropertyChanged just like in Winforms? Or are there better practices to do these?
I saw some people suggesting using dependency properties online, but not sure if that's what should do.
If the class I want to add a property is a DependencyObject, I generally add a DependencyProperty. If the class is a POCO (plain old clr objects), then I implement INotifyPropertyChanged.
In generall, all my business objects are POCOs and therefore I use INotifyPropertyChanged. In the WPF world, I mostly use DependencyObjects (view models, custom controls, UserControls...) and therefore they are DependencyProperties. An exception are ViewModels representing items (to be used as items in an items source). In this case I think DependencyProperties are not very practical (Because Equals() and GetHashCode() of DependencyObjects are sealed and DependencyObject is thread-dependent).
If your class already is a DependencyObject, using DependencyProperties may give you some nice advantages: You don't have to back every value, a powerfull inheritance system, default-values, property changed callbacks per property, value coercion ... (I like DependencyProperties probably more than other people them like :)
Conclusion:
Based on the title of your question: How to get notified when something changes in a WPF window?, my way would be to add a DependencyProperty and not a clr-property because the Window is a DependencyObject. By the way, Visual Studio has a nice Snippet to create DependencyProperties.
There are really two scenarios:
1) Notifying the UI when a piece of data changes-either in the ViewModel or a Model that is bound to some UI elements (usually due to a data binding). In this scenario you'd use INotifyPropertyChanged.
Example: you have a Person object that binds it's Name to a TextBox. Person needs to implement INotifyPropertyChanged and the appropriate code needs to be attached to the Name Property's setter.
2) Creating custom UI elements where you'd want data to be bound. In this case, you'd use custom dependency properties.
Example: you have a custom UI element that spins when a certain condition is met. So you create an IsSpinning dependency property that you can bind to your ViewModel's IsLoading property. The custom control then uses the IsSpinning property to modify its behavior.
I hope that was clear...
You are right. You can use INotifyPropertyChanged or you can implement dependency properties. Personally I prefer INotifyPropertyChanged, it's more light and easyer to implement than dependency property.
I've generally used INotifyPropertyChanged for my data objects.
DependencyProperties can only be implemented on framework elements I believe.
Edit: I take that back... DependencyProperties can only be implemented on DependencyObjects (A FrameworkElement is an example of that as it derives from UIElement which derives from Visual which derives from DependencyObject).
If you have a UserControl, you may wish to implement a Dependency Property so you can Bind that Property (in XAML) to some other property. You could not do this scenario with INotifyPropertyChanged.
I sometimes think I maybe using Dependency Properties unnecessarily. When do I need to use it? When I have a property that dependes on other properties? Say I have a Color property that I want it to be dependent on properties Hue, Saturation, Luminosity do I use a dependency property? Or what do I use? I controls thats bound to Color to update when properties Hue, Saturation, Luminosity are changed.
for now what I did was
public byte Hue {
get { return _hue; }
set
{
if (_hue == value)
return;
_hue = value;
NotifyPropertyChanged("Hue");
NotifyPropertyChanged("Color"); // to update controls bound to color
}
}
But I think this is not the right way of doing things? If I have more properties that affect color, I will have 1 extra line in all those properties?
You should only use a DependencyProperty when you want to be able to bind its value to something through XAML, e.g.
<local:MyObject MyDependencyProperty="{Binding ...}" />
Update: as mentioned by Ian below, dependency properties are also required if you want to be able to animate your property or set it through a style
If you do not need to work in this way then it is unnecessary. e.g. If you just want to be able to set the value to a constant through XAML (as below) this will work without using a DependencyProperty
<local:MyObject MyRegularProperty="Some Value" />
Similarly, if you want to bind to the value of a property on (for example) your view model:
<TextBlock Text="{Binding MyViewModelProperty}" />
then you do not need to use a DependencyProperty. Provided that you implement INotifyPropertyChanged then the Text will still be updated when the property changes.
Edit: on re-reading your question, I am not sure whether or not your situation will be affected by whether or not you use a DependencyProperty - if I'm reading it correctly, all you want to do is cause a number of properties to be updated on the UI when any one of those properties changes, right?
I don't think there is anything wrong with how you are implementing things at the moment (i.e. raising a lot of PropertyChanged events in each setter), but if you aren't keen on in then you could try having a single property that exposes relevant child properties to bind to that are all calculated:
class ColorWrapper
{
public Color Color { get; set; }
public byte Hue
{
get { return this.Color.Hue; } //or however this is calculated
}
Then have a Color property on your ViewModel that raises the PropertyChanged event and bind to that through the View:
<TextBlock Text="{Binding Color.Hue}" />
As I said, I wouldn't say that this is particularly an improvement on what you have already though.
The general rules are:
For XAML controls, use dependency properties;
For data (which you bind to in the interface), use INotifyPropertyChanged.
There are exceptions, but they are rare.
Another use of dependency properties is with navigation journal. Custom dependency properties on a Page with Juornal flag in the meta-data are included in the state that WPF saves for the page.
Remember that Dependency Properties, although they allow Binding either as a source or a target, are also Thread-Sensitive, and when serializing you will have to use a surrogate, serialization as DependencyObject isn't serializable.
Oh, and Equals and GetHashCode are sealed :(
Another usage of DP is Attached Property. Attached property is a type of DependencyProperty where the property can be used in any other controls.
For example, you can declare AttachedProperty in class MyAttachedProperties and used it for TextBlock, Button, Label,...
Some examples of Attached Properties: Grid.Row, Grid.Column. A customized one:
public static readonly DependencyProperty DarkThemeProperty =
DependencyProperty.RegisterAttached("DarkTheme", typeof(Theme), typeof(Page));
public static Theme GetDarkTheme(DependencyObject obj)
{
return (Theme)obj.GetValue(DarkThemeProperty);
}
public static void SetDarkTheme(DependencyObject obj, Theme value)
{
obj.SetValue(DarkThemeProperty, value);
}
I was stepping into the "trap" of DependencyProperty often.
At some point I realized that every single Change of any value is triggered somehow and somewhere, that can be an algorithm, a process, a user-input... and a lot of things, but NEVER it just changes by itself.
Get control about that triggers, hook directly at source and you never need DependencyProperty and even no INotifyPropertyChanged. I mean maybe I do something wrong or right, but all problems, and they are sometimes of serious difficulty, I solve with only RoutedEvents and Properties { get , set } -> And inside of get, set you can do SO much. Everthing that cannot be solved here, can be done with AddHandler and don't forget to RemoveHandler when not needed anymore.
Also needed is a solid understanding of Threading and Dispatching in some cases.
Also needed is a good knowledge how to work with Lambda expressions and Actions.
(Probably not useable for windows phone etc. applications, guessing)
Respectively: A serious drawback is coding control and effort. For that approach I need to write more Code and have better documentation, the big advantage is better understanding what is actually happen within your application and what could happen, what are the extends. There is NO drawback in performance, it is even faster, because when you hook directly into your triggers, you are using the lightest and most appropriate form of an Approach - Executing Code ONLY when it is necessary and only that heavy that it is necessary.
Finally: DependencyProperties could make sense in very responsive applications where you actually DON't KNOW the possible relations and reactions. That could be over a million possible cases -> You don't want to have control over those, you would never finish your product.
Caveats: Not everything that looks like it is producing a ton of unknown cases are unknown. You can work with RANGES (from x to y) and write algorithms to regain control over thousands of possible cases with just one method.
So that are my two cents: DependencyProperties and INotifyPropertyChanged is not needed in most of the cases and just a way of having an easier coding life at the cost of actually understanding your product and (sometimes) performance.
(Notification to myself: I write this because I just came into a situation where I was thinking I need DependencyProperty, this time for real.. but no.. one hour of thinking and the solution was easy, found the trigger.)