wpf datatrigger + value binding - wpf

I have a custom component that should change your alignment as a property of the window changes and getting the value of another property of itself. The property of the window is changing correctly, however, the alignment of the component is not changing. The converter that returns the alignment is also working correctly (it returns Left, Right or Center, depending on the other property of the component). So where is the error? Here is the code of the DataTrigger:
<myComponent.Resources>
<lib:HorizontalAlignmentConverter x:Key="HorizontalAlignmentConverter"/>
<Style TargetType="{x:Type myComponent}" x:Key="HorizontalAligner">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=MainWindow1, Path=myWindowResizedProperty}" Value="True">
<Setter Property="HorizontalAlignment" Value="{Binding Path=myOtherProperty, RelativeSource={RelativeSource Self}, Converter={StaticResource HorizontalAlignmentConverter}}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</myComponent.Resources>
Thanks in advance!
Another question: Is there any way I can reference, in the expression of DataTrigger Binding, the Window object, without using his name? This way would be more generic.
Thanks again!

Related

wpf visibility based on a condition

I want to show a StackPanel based on a particular condition. In this example I've used the BorderThickness property:
<ContentControl x:Name="gridDati" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.ScrollUnit="Item" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items}" Value="{x:Null}">
<Setter Property="BorderThickness" Value="0" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=Items.Count}" Value="0">
<Setter Property="BorderThickness" Value="12" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="pnlLoading" Visibility="Visible">
<Label Content="">
<Label.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=BorderThickness, ElementName=gridDati, UpdateSourceTrigger=PropertyChanged}" Value="0">
<Setter Property="TextBlock.Text" Value="" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=BorderThickness, ElementName=gridDati, UpdateSourceTrigger=PropertyChanged}" Value="12">
<Setter Property="TextBlock.Text" Value="STAND BY" />
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
</StackPanel>
Basically when in the code behind I apply a template on gridDati, while the item counter is still zero, the border is set correctly to 12. After that it turns to zero (item binded) and this behevior is what I want.
So, I also would like to show a StackPanel at the same condition, so I used a DataTrigger but seems that is not fired at all. How can I "link" these two condition? so show a stackpanel when I have items in the datagrid?
This is the proper way to declare the Label so you get the desired result.
<Label>
<Label.Style>
<Style TargetType="Label">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count}" Value="0">
<Setter Property="Content" Value="STAND BY"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Label.Style>
</Label>
But there are a few points I need to explain to make sure you understand what I changed and why. I'm going to go through the XAML from the inside out.
First, I changed the Setter to use the right property name. You're using a Label, and your old Setter had Property="TextBlock.Text". TextBlock.Text is not a valid property name for a Label (no such property exists), so that wasn't going to work. The property you want is called Content.
Moving up one level to the DataTrigger. Instead of binding to gridDati that is binding to Items, I just bound directly to Items. You could do it the other way, but in my opinion it would be unusual and it might cause unforeseen bugs.
Next, you'll notice I removed the first DataTrigger. WPF dependency properties can be set in a number of different ways, and there is an order of precedence for which value will be taken over others. The default value (lowest precedence) for a Label's content is for it to be empty. When the DataTrigger applies the Setter, it overrides that value (it has higher precedence). When the DataTrigger condition is no longer fulfilled (Items.Count != 0), WPF stops applying the Setter and the value reverts back to the default, because there is no longer any value of higher precedence overriding it. So you don't need to add a second DataTrigger resetting to default, wit ill do that automatically.
Moving up further you'll see I changed the opening Style tag to <Style TargetType="Label">. It's common practice to set the TargetType of a Style. Doing this also gives you IntelliSense options for Setters in that Style, which might have helpped you catch the mistake you made by trying to use TextBlock.Text as a property name.
Finally, I removed Content="" from the opening Label tag. Setting the value of a property directly on an element in XAML has a very high precedence, which overrides all Styles and DataTriggers. As long as this was there, nothing you did in any Style would change anything for the Label's Content.

Change Dependency Property value on Textbox ValidationRule

I have implemented Custom Control inheriting from ContentControl,which has dependency property called "CanNavigate"(bool).
In a Window.xaml,I have a text box with some ValidationRule checking for Textbox emptiness.I want to set "CanNavigate" to true/false based on TextBox.Validation.HasError as shown below code:
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
<Setter Property="{Binding CanNavigate}" Value="false"></Setter>
</Trigger>
</Style.Triggers>
</Style>
Having this code,gives an error "'Property' property cannot use markup extensions or property element syntax on Setter. Only the Value property can use markup extensions or property element syntax. Error at object 'System.Windows.Setter' in markup file"
Is there a way where I can set CanNavigate property based on TextBox.validationError.
Regards,
Patil
Concerning your first setter I think you should replace this setter with a Binding on the ToolTip property and use a ValueConverter when neccessary, triggers can not.
It's better to do it like this (note I haven't tested this piece of code I'm just trying to point to this way):
<TextBox ... ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
Concerning the second setter: In a setter when defining the Property you don't need to specify a Binding you just provide the property name just like this:
<Setter Property="CanNavigate" Value="False" />

How to set a viewmodel property if a listbox item selected?

I have a listbox...and it is bound to list of items of type (class) "A". Class "A" has a boolean property "IsCurrentViewActive". This is false by default. When user select an item in listbox....i need to set the "IsCurrentViewActive" property of corresponding item to TRUE.
I tried the below code in my listbox...but it is not working..Any help would be appreciated.
<Style x:Key="ListBoxItemTabStyle2Extended" TargetType="{x:Type ListBoxItem}" >
<Setter Property="IsSelected" Value="{Binding Path=IsCurrentViewActive, Mode=TwoWay}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Value="True">
<Setter Property="IsSelected" Value="{Binding Path=IsCurrentViewActive, Mode=TwoWay}"/>
</DataTrigger>
</Style.Triggers>
</Style>
EDIT : Can we do this way or Do I need to use attached property ?
The above XAML worked fine for me actually. I think it's just a matter of getting the context right. I have created a sample that you can download where this works fine. I think the difference might be that in my version, I store the style in ListBox's parent control's resources. I don't think you can store them in the ListBox's resources.
https://www.dropbox.com/s/s64kp9p0b2w1imk/ListBoxMenu.7z?dl=0

Updating style on runtime in wpf

I have a style for a ItemContainer that is based on the Item being contained (With a StyleSelector). It works fine. However on runtime the property might be changed but the style isn't updated instantly.
Is there anyway for me to get it to update as soon as the changes are saved?
Use a DataTrigger and a Converter which returns the Type of an object
For example,
<Style.Triggers>
<DataTrigger Binding="{Binding Converter=ObjectToTypeConverter}"
Value="{x:Type local:Person}">
<Setter Property="ItemTemplate" Value="{Binding PersonTemplate}" />
</DataTrigger>
<DataTrigger Binding="{Binding Converter=ObjectToTypeConverter}"
Value="{x:Type local:Business}">
<Setter Property="ItemTemplate" Value="{Binding BusinessTemplate}" />
</DataTrigger>
</Style.Triggers>
Use binding. Then you will need to implement INotifyPropertyChanged. The value you are setting should be a property and at the end of the setter, raise the property changed event.
If you give an example of your XAML, I can write it out for you.

How do I trigger a style change if DataContext is null or not using WPF

I have a page with several controls. The controls are bound to display values which they get from the page's DataContext. What I would like to do is display another look of the page should the DataContext be null. In some cases the controls of the page should display differently if "their" property is set or not.
Is is possible to create a binding to see if the DataContext is set?
What I did as a workaround was to add a IsDataContextSet property to the page and the specify a binding like:
Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Page}}, Path=IsDataContextSet}" Value="false"
This works as I expect but I have a feeling that their is more elegant way to do this. Or at least or more WPFish way.
Given the scenario you describe, I would set the properties with a style and a data trigger. The data trigger would use the default binding which is the data context.
An example might look like this:
<Border>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background"
Value="Orange" />
<Style.Triggers>
<DataTrigger Binding="{Binding}"
Value="{x:Null}">
<Setter Property="Background"
Value="Yellow" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
</Border>
The border will be orange unless the data context is null, in which case the background is yellow.

Resources