I read on many places that a DataTrigger is not limited to dependency properties only (like a Trigger), but it can also respond to any .NET property.
So is the DataTrigger a superset of the Trigger in its capability?
Why does a Trigger exist when we have the DataTrigger?
There are three types of triggers in WPF.
Property Triggers (Simply Trigger)
Data Triggers
Event Triggers
Trigger in WPF are actually property triggers. So, they only work with Dependency property. They are mainly for depedency property values to performs actions conditionally. (When Dependency Property meets a specified condition)
Whereas DataTriggers are more powerful. They can bind to normal .net property to monitor for changes or any dependency property or another control or StaticResources and so on. They perform action through bindings. (When bound data meets a specified condition)
So, you could say that Triggers exists to provide a more specific action to Dependency Properties, instead of using more generic Data Triggers which is for any .net data ( of course mainly through change notification)
So, to answer your question, AFAIK, No, there is nothing that property trigger can do that data-trigger cannot.
Related
I have a WPFToolkit DataGrid with at least one column bound (via a proxy object as columns are not part of the visual tree) to a property. I wish to toggle all columns to Visible so that I can perform a calculation based on the DataGridColumnHeader (which is only created when its column is visible for the first time). Having done the calculation I want to reset the column to use the binding that was previously set.
I've attempted to get and store the Binding Expression etc, but with no joy. I have also attempted to use the DependencyObject.SetValue() method to change the property value non-destructively, but this doesn't event correctly change the value, let alone retain the original binding.
Any ideas?
You need to call SetCurrentValue() so that it won't clear the binding. SetValue destroys the old binding.
From MSDN:
This method is used by a component that programmatically sets the value of one of its own properties without disabling an application's declared use of the property. The SetCurrentValue method changes the effective value of the property, but existing triggers, data bindings, and styles will continue to work.
Given you have this
<TextBox Text="{Binding TestProperty}"/>
The SetValue you will overwrite the binding with whatever you provide. If you call SetCurrentValue, however, will ensure that the property takes on the given value, but won't destroy any bindings.
Be aware that you should not use SetCurrentValue in your dependency properties' setter/getter.
SetCurrentValue is more useful in scenarios where you need a property to take on a given value but don't want to overwrite any bindings, triggers, or styles that have been configured against your property.
i have created a user control with three dependency properties
selected value
selected item
selected index
when one of them changes in the call back i am setting the other two e.g if selected value changed i am setting Selected index and selected item which in result triggering the callback of each of other properties where it sets the other two properties and keeps on in loop .how to avoid this situation
That's easy,
in each Property Setter only set the other two when the value you're setting is different from the the existing value (through the call of GetValue()). Add a If statement to check this in each of the Property setters.
You should be more careful with these type of situations, either check if you really need those 3 properties as Dependency Properties or change some of them to normal properties in the ViewModel if you're using an MVVM framework.
If you're using MVVM, many frameworks provide a method to suppress notifications like ReactiveUI (ReactiveObject.SuppressChangeNotifications()) or MVVM Light Tookit.
I'm developing a WPF/MVVM application and I have a listbox binding to data in a ViewModel. At various points I need the view model to cause the listbox to scroll to a given element.
How can I do this without creating a custom control and while still maintaining good separation of concerns?
I've currently got it working by creating a custom behavior class in the view layer with a dependency property VisibleIndex which the XAML code then binds to an integer in the view model:
<ListBox x:Name="myListBox"
local:ListBoxVisibilityBehavior.VisibleIndex="{Binding VisibleIndex}">
When the integer is set it triggers the dependency properties update handler which tells the listbox to scroll to the associated index.
This seems a bit hacky though because the dependency property value is never changed by the listbox and the update handler only gets called when the value changes, so the only way to ensure that the relevent item is visible is to do something like this:
// view-model code
this.VisibleIndex = -1;
this.VisibleIndex = 10;
The only reason I'm using a behaviour class at the moment is for binding my custom dependency property, is there a way to do something like this with events instead?
Attached properties are somewhat required in your case - as at some point, 'somewhere' you need to call the following method...
ListBox.ScrollIntoView(item)
or
ListBoxItem.BringIntoView();
And for that you need some sort of code behind - and attached properties/behaviors are a nice way of packaging that, w/o impacting your MVVM.
Having said that - if you just need to have your 'selected item' scrolled into view at all times (which is the case most of the time). Then you could use a different attached-property based solution (that again):
mvvm how to make a list view auto scroll to a new Item in a list view
All you have to do then is to set or bind to SelectedItem.
That's a bit 'nicer' if you wish - but the mechanism is the same.
For anyone else interested in the answer to this one of the MS engineers on the WPF forum cleared it up for me. Instead of binding to an event directly you bind to a wrapper object that encapsulates that event. The behaviour can then grab the reference to the wrapper from its DP and do whatever it wants with it i.e. subscribe to the event, trigger it etc.
Using MVVM, my viewmodel is my WPF window's data context. In the viewmodel is an observablecollection that holds the items in a listbox. When I add items to the collection, the listbox updates as expected
As part of my generic undo function, the observablecollection can be replaced with an older version. This happens by passing the collection to a method by reference and changing the reference. Everything after the undo works correctly except for the listbox. This continues to show data from the old reference.
How can I either stop this from happening or change the reference that the datacontext uses so that my listbox is "undone" and then continues working?
You need to provide some change notification in order to trigger the UI to update which you won't get from reassigning a ref variable to another instance. To get the notification you can either Clear and re-fill the original ObservableCollection instance or fire a PropertyChanged event for the collection property's name after swapping the instances.
Using the MVVM pattern, properties are changed in the ViewModel, with setters raising the PropertyChanged event. The event is handled in the View (automatically by WPF) and bindings are refreshed.
In your case, the value is being changed without the setter being called, so the PropertyChanged event (if it exists) is not being raised.
One option might be to manually raise the PropertyChanged event from the undo code. This would allow you to keep your existing design (please note that INotifyPropertyChanged.PropertyChanged is different to ObservableCollection.CollectionChanged - do a bit of research if this is not clear).
The second option would be to handle the CollectionChanged event, and keep a record of ItemsAdded and ItemsRemoved.
Your undo mechanism can then re-add any items which were removed, or remove any items which were added. This might require a bit of design tweaking.
I would go with the second design, as I think the design rethink might be a good idea. If you are using MVVM, you should be using Commands, and if you are using Commands you can implement Undo/Redo functionality neatly by extending the Commands (remember that an action made by a user is usually a bit more than a value change).
Basically I want to use the WPF Binding framework to "observe" a property in the data context, and when that value changes to call an event handler. I do not actually want to bind it to any target.
Sounds simple but from what I can see Binding is too coupled (to the visual tree and various other bits) to be able to use it flexibly.
Any thoughts?
You are correct that bindings are associated with the visual tree: they're about hooking UI elements up to data elements. So if you wanted to use a binding for this, you would indeed have to set it on a dummy framework element.
However, if WPF can observe the property then you can too. WPF is just using the data context object's INotifyPropertyChanged interface. So rather than setting up a binding, you can just cast the object you want to observe to INotifyPropertyChanged, and subscribe to its PropertyChanged event. Internally, that's all WPF is doing anyway.
(If you're concerned about lifecycle issues, WPF provides the PropertyChangedEventManager which uses weak references. Call PropertyChangedEventManager(dataObject, listenerObject, "WhateverPropertyYouWant") where listenerObject is the object you want to receive the change notifications.)