WPF Data Triggers Set Object properties based on events - wpf

With DataTriggers in WPF its possible to set properties on controls based on the the object you have bound. For example you could set the Background of a TextBlock based on a IsAlive property on your object.
<DataTrigger Binding="{Binding Path=IsAlive}" Value="true">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
I want to know if its possible to go in reverse. Is it possible to set a property on a databound item based on the state of the control its bound to?
Say I want to set the IsAlive property to true when the control its bound to receives the mouseover event.
Can this be done in WPF & data triggers? Thanks.

I don't know if what you're asking is directly possible, but I suspect it isn't. On the other hand, I think you could make your example scenario work by binding the object's "IsAlive" property directly to the control's "IsMouseOver" dependency property, with Mode=OneWayToSource.

You might want to use EventSetter, then handle the setting by code using the DataContext property of the sender, or with GetBindingExpression.
This gives you an option to set a handler on the style level.

Related

WPF - Set child controls of a user control to be readonly using binding

I have a WPF application with many different controls. I need to be able to set all child controls to be read only based on a property in my view model that I want to bind to.
There are a couple of challenges that I see:
How to ensure that setting the parent control to read only, also sets the child controls
Not all controls have a ReadOnly property - some IsReadOnly, some only have an IsEnabled
Has anyone any views on a generic solution rather than me having to bind the appropriate property (ReadOnly, IsReadOnly, etc) for each individual control?
Is there some way that I could use an attached property? Is there anyway, for example, that I could set a property on a grid, then in the code iterate through each child control setting it's appropriate property (if applicable at all)?
Any ideas welcomed.
David
I would recommend to do this using WPF implicit styles. The style would contain the Binding to the view model, for example:
<Style TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="{Binding IsNotProcessing}" />
</Style>
As this style does not have the x:Key attribute set and uses the x:Type markup extension on the TargetType attribute, it is implicitly applied to all buttons in this case.
You would have to write an implicit style for each distinct control in your view as the following style would not be applied to all your buttons, text boxes and whatever controls you use (although the IsEnabled property is defined on FrameworkElement):
<!-- This implicit style is not applied as the x:Type must be the same type as
the targeted control; inheritance does not work here. -->
<Style TargetType="{x:Type FrameworkElement}">
<Setter Property="IsEnabled" Value="{Binding IsNotProcessing}" />
</Style>
Another option would be to make a single style that has a resource key an then reference this from every control, which is also quite cumbersome, but could be done relatively easy using Blend if you know all the controls at design time (you would select all controls and then apply the style using the properties window).
Hope this will help you.
Use the property IsHitTestVisible in xaml file to make real read only
<Grid IsHitTestVisible = "False">
//put a control
</Grid>

Let one control be enabled/disabled based on another control

I have two DataGrid's that I want do have enabled/disabled based on whether precisely 1 element is selected in another DataGrid. What is the simplest way to accomplish this dependency control in WPF?
You could use a trigger:
<DataGrid.Style>
<Style TargetType="DataGrid">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItems.Count,
ElementName=datagrid1}"
Value="1">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
You could:
Create an IValueConverter, perhaps it is called NotEqualToOneBooleanConverter
Bind IsEnabled from one DataGrid to the SelectedItems.Count on the other
Set the Converter on this Binding to be the NotEqualToOneBooleanConverter
This approach is nice since once your converter is created, it can be applied throughout your XAML and to any type and any property (not just DataGrid or SelectedItems.Count). To make it even more flexible, you could have a more generic version of this converter that could compare any two values specified directly from XAML (one from the Binding and one specified as property on the Converter).
The downside to this approach - it's XAML only, and difficult to test especially if what you are trying to achieve is a business requirement and not just a graphical effect.
Hope this helps!
This is my quick hack:
tablesControl.SelectionChanged += (sender, sce) =>
{
var c = tablesControl.SelectedItems.Count;
var orderingPossible = c == 1;
itemsControl.IsEnabled = orderingPossible;
};
In the first Grid have an event or Command that is fired when you click on that cell, in this event you need to have some bool property you can set to false, then bind the Enabled property to this bool. If you are using MVVM this will be very easy, have a look at this to see how - http://www.youtube.com/watch?v=tKfpvs7ZIyo

Reset dependency property value from binding

Say I have a Grid, with a lot of cells on it, and I bind background of this cell to some property of my data class in a style (actually data class property is type of Color, but this is not an issue, because we can use a converter to convert it to a Brush),
Now when some condition in my data class is true I want the background to be red, and if not, I want it to be the default value, data may change, so condition may become true and false, and I should fill Background red or default
I know about Binding.DoNothing and DependencyProperty.UnsetValue both are not case, I tried also Cell.BackgroundProperty.DefaultValue but it is null.
So Is there any value, that I can return from my bound data property, to force the dependency property to reset its value?
Thanks!
If you only have a boolean property that is quite convenient as you can use a DataTrigger and just bind the value if the property is true, that way the property is not always bound.
<Style.Triggers>
<DataTrigger Binding="{Binding MyCondition}" Value="True">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
If you only have the decision between default and red you do not even need the additional property or any binding at all.
(Resetting values is not possible in a binding to my knowledge)

What's the difference between a Trigger and a DataTrigger?

They seem the same. Is there a significant difference? I think I am missing something.
A regular Trigger only responds to dependency properties.
A DataTrigger can be triggered by any .NET property (by setting its Binding property). However, its setters can still target only dependency properties.
Another difference is that a DataTrigger can be bound to another control, a StaticResource, etc etc.
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger
Binding="{Binding SomeProperty,
ElementName=someOtherControl"
Value="Derp">
<!-- etc -->
You can only examine the instance on which the style is set when using a Trigger. For example, a Trigger applied to a Button can inspect the value of IsPressed, but it would not be able to inspect the (for example) Text value of a TextBox on the same form if you wished to disable the Button if the TextBox was empty.
The short answer (as I'm about to sleep)- A trigger works on dependency properties (typically GUI properties) whereas data triggers can be triggered by any .NET property (typically a property in a ViewModel that implements INotifyPropertyChanged).

How to expose properties of a WPF DataTemplate?

I have a data template that I use in many pages, the data template contains a few buttons, I want to hide some of these buttons by triggers (I mean setting the IsEnabled Property of these buttons in the page where I use this DataTemplate).
In other words, I would even like to set in style triggers/setters a property 'ButtonXIsEnabled', 'ButtonYIsEnabled' as part of the DataTemplate settable from the ListBox where I use this DataTemplate.
I really hope I am clear enough, please leave comments for any further details.
Any discussion will be really appreciated!
Thanks in advance.
Basically this depends on what object your using for your datatemplate. Instead of using some ButtonYIsEnabled, etcs. Try to use some words that fit better in to your domain model.
For example say you have a list of customers, and some of those customers have the ability to purchase discounted products. Then add a property to your Customer called CanPurchaseDiscountedProducts, and use that property in your DataTemplate
<DataTemplate TargetType="{x:Type local:Customer}">
<!-- Other Items -->
<Button Content="Purchase Discounted Products" x:Name="discounts" Visibility="Hidden" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding CanPurchaseDiscountedProducts}" Value="True">
<Setter TargetName="discounts" Property="Visibility" Value="Visible"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
A WPF data template is a view of a certain object type... how you want an instance of ObjectTypeX to look. The data template can bind to properties on the underlying instance.
So if you have a ButtonXIsEnabled property on your instance, you can bind the corresponding Button's Visibility property to the instance property. The button would be shown or hidden based on the value in the underlying object.

Resources