Binding Window Title through Style && triggers in XAML - wpf

I've code like that
<Window x:Class="SolutionName.ClassName"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300" WindowStartupLocation="CenterOwner">
<Window.Style>
<Style TargetType="Window">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ItemKind}" Value="SomeKind">
<Setter Property="Title" Value="SomeTitle"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=ItemKind}" Value="SomeKind2">
<Setter Property="Title" Value="SomeTitle"/>
</DataTrigger>
I want is to change window title depending on a property ItemKind implemented in the viewmodel (set as datacontext). The code above won't work and I'm really confused because can't find any mistakes.

The code seems fine and working at my end. Have you implemented INotifyPropertyChanged in your ViewModel class. You need to implement it to so as to propagate any change in property value in your ViewModel class to reflect back on your UI.
How to: Implement Property Change Notification

Related

Setting 'style' on my user control in xaml replaces the TextBox element with a string 'system.windows.style'

I have a very basic user control
<UserControl x:Class="Framework_Base.UserControls.NumberPicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Framework_Base.UserControls"
mc:Ignorable="d"
d:DesignHeight="21" d:DesignWidth="60">
<TextBox Name="ValueTextBox" Width="60"
PreviewTextInput="TextBox_PreviewTextInput"
TextChanged="ValueTextBox_TextChanged"
DataObject.Pasting="TextBox_Pasting" />
</UserControl>
When I add it to my view it's fine, works fine etc.
When I try to add a style like so:
<uc:NumberPicker Value="{Binding MyValue}" MinWidth="60">
<Style TargetType="{x:Type uc:NumberPicker}">
<Setter Property="Background" Value="Red"/>
</Style>
</uc:NumberPicker>
The user control looks like this:
And I really don't know why, can't find anything on Google searching, but also finding it difficult to know what terms to use in the search.
Any help would be appreciated.
The XAML declaration
<uc:NumberPicker ...>
<Style TargetType="uc:NumberPicker">
<Setter Property="Background" Value="Red"/>
</Style>
</uc:NumberPicker>
does not set the Style property of the control, but its Content property (this is because of a [System.Windows.Markup.ContentProperty("Content")] declaration at the ContentControl class declaration).
To set the Style, you need to write
<uc:NumberPicker ...>
<uc:NumberPicker.Style>
<Style TargetType="uc:NumberPicker">
<Setter Property="Background" Value="Red"/>
</Style>
</uc:NumberPicker.Style>
</uc:NumberPicker>

Inherit style from control's default style

The title says it all. How do I apply a custom style on a DataGrid's column header while still inheriting the default style values for the properties that I do not override? I have already tried the method given in this SO post, but it doesn't seem to work in my case. My column header looks slightly different than the default. Here's my XAML:
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="0,0,1,0" />
</Style>
Here's the output:
As you can see, the left column (this has custom style) has no padding, unlike the right column that has default style. Any clues?
(I can of course set padding in my style to get the look I want; I just need to know why didn't it inherit the padding from the default control style).
Sample code to reproduce the bug
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<DataGrid AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Width="100" Header="No Padding">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="DataGridColumnHeader" BasedOn="{StaticResource {x:Type DataGridColumnHeader}}">
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="0,0,1,0" />
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
<DataGridTextColumn Width="100" Header="Padding" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
I used Blend to check Template of DataGridColumnHeader. I have noticed that in the Template is used DataGridHeaderBorder which derives from Border.
http://msdn.microsoft.com/en-us/library/microsoft.windows.themes.datagridheaderborder(v=vs.110).aspx
There is remark "If the Background or BorderBrush properties are set on the DataGrid, the rendering reverts back to the default Border implementation." and it explains your problem.
DataGridHeaderBorder overrides OnRender method and renders header differently depending on whether the Background or BorderBrush is null or not. In one case OnRender method adds Padding and in the second case doesn't add. http://referencesource.microsoft.com/#PresentationFramework.Aero/DataGridHeaderBorder.cs,257

Textbox Disabled background from a local trigger without using template

<Window x:Class="AiweeeTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<SolidColorBrush x:Key="backcolorType" Color="Red"></SolidColorBrush>
<SolidColorBrush x:Key="forecolorType" Color="Green"></SolidColorBrush>
<Style x:Key="TextboxStyle" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="Yellow"/>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" Value="{StaticResource backcolorType}"/>
<Setter Property="Foreground" Value="{StaticResource forecolorType}"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<TextBox Name="textbox1" Width="100" Height="25" Style="{StaticResource TextboxStyle}" IsEnabled="False"/>
</Grid>
</Window>
I am not able to update the background of a textbox using the trigger defined above, however when I copy the entire textbox control template template and replace the "DisabledBackgroundBrush" with my own color it does. What's the difference, I've already seen some links over this matter; however I am not able to understand the reason behind it. As I understand, Triggers are fired in the order they are defined, then the trigger defined locally in the window should be able to override the background color of the textbox when disabled. Please clarify.
PS: I am not trying to achieve anything special here, but just want to understand why is this so. This gives me a bit of frustration of WPF not being intuitive for situations like such.
I am guessing it has something to do with the order in which WPF will apply values for a DependencyProperty. This MSDN article has some good information on Dependency Property Precedence
Basically the order goes:
Property system coercion
Active animations, or animations with a Hold behavior.
Local value
TemplatedParent template properties
Triggers from the TemplatedParent template
Property sets (typically through XAML attributes) in the TemplatedParent template
Implicit style
Style triggers
Template triggers
Style setters
Default (theme) style
Active triggers in the theme style
Setters in the theme style
Inheritance
Default value from dependency property metadata

Datatrigger on textbox not working

Hi i am trying to write a datatrigger in which i have to clear a textbox content on checkbox checked.My Code is given below
It works as long as you dont type anything in the textbox.As soon as i type in the textbox the datatrigger fails to work.How can i solve this
<Window x:Class="CheckboxTextbox.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style x:Key="cbStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=Chk,Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{x:Null}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel>
<CheckBox Name="Chk" Content="test"/>
<TextBox Style="{StaticResource cbStyle}">
</TextBox>
</StackPanel>
</Window>
Unlike an animation which can "hold" a dependency property at a specified value once the animation ends, a DataTrigger sets the target property and then is done until the source property changes.
In other words, in your example if you put some text in the text box, then check the box, the text will be cleared. But then if you start typing in the text box again, DataTrigger isn't going to do anything until the check box changes again. That's why when you uncheck and re-check the box, the text is cleared again.
So what you may want to do is in your DataTrigger, set the text box's IsReadOnly property to true. This will prevent you from typing in the box while the DataTrigger is active.
<DataTrigger Binding="{Binding ElementName=Chk,Path=IsChecked}" Value="True">
<Setter Property="Text" Value="{x:Null}"/>
<Setter Property="IsReadOnly" Value="True"/>
</DataTrigger>

changing background color of container when textbox is in focus

I have a simple user control with a TextBox. I want to change the color of user control when the TextBox gets the focus. This is what I have:
<UserControl x:Class="OutLookContactList.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root" MinHeight="30" Loaded="UserControl_Loaded">
<UserControl.Resources>
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter TargetName="root" Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
But I get the errot "TargetName property cannot be set on a style Setter". How can I Set the back ground color of user control when text box gets the focus?
Thanks a bunch
Will it work to wrap the contents of your UserControl inside a Border object? If so, you can simply style the Border like so:
<UserControl x:Class="Sample2.ContactSearchControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="75" Width="300">
<Border>
<Border.Style>
<Style TargetType="Border">
<Setter Property="Background" Value="White" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocused, ElementName=txtSearch}" Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<StackPanel>
<TextBox x:Name="txtSearch" Text="Search" />
<TextBox Text="Other" />
</StackPanel>
</Border>
</UserControl>
Update: (Answering Sheraz' Questions)
I'm not sure why ElementName doesn't work for accessing children within a UserControl. It might have something to do with the way the visual tree is constructed.
As for Trigger vs DataTrigger: Trigger is for dependency properties and DataTrigger is for databound properties (data or other controls). Since you are trying to style the Border, it makes more sense to place the DataTrigger there and have it watch the TextBox than to have the TextBox change the appearance of the Border.
As I understand it, the TargetName property of Setter is only applicable within a DataTemplate or ControlTemplate. (Info from Dr. WPF in this forum post)
If you were changing the background of the text box you need to remove the TargetName property:
<Style x:Key="searchTextBoxStyle" TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="IsFocused" Value="true">
<Setter Property="Background" Value="{StaticResource OnMouseOverColor}" />
</Trigger>
</Style.Triggers>
</Style>
and change the TextBox that wants this style to be:
<TextBox Style="{StaticResource searchTextBoxStyle}" .... />
However, as you want to change the value of the parent user control this won't give you want you want.
You could certainly do it in the code behind by adding a GotFocus event handler and putting the code to change the background colour in there.
Here's some XAML that works in Kaxaml:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Style>
<Style TargetType="Page">
<Setter Property="Background" Value="#CCCCD0" />
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=txtSearch, Path=IsFocused}"
Value="true">
<Setter Property="Background" Value="Black" />
</DataTrigger>
</Style.Triggers>
</Style>
</Page.Style>
<TextBox x:Name="txtSearch" Width="100"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Page>
You would change the Page object with your UserControl. I find it much easier to test these sorts of things out in a rapid prototyping tool such as Kaxaml before coding up the UserControl in VS.
Note that you have to set the default colour (in this case #CCCCD0) via a property setter and not via an attribute on the Page itself. This is because the attribute would override the value set by the trigger (because it's a style trigger), so even though the trigger would fire, it would always be trumpted by the local attribute specification, meaning that it wouldn't change. I only point this out because it's a fairly common gotcha.

Resources