Binding WPF DatagridCell to the source - wpf

My original datagrid does have a few columns wherein the bound value is bool.[By default this would show up as check boxes]
I have defined a cell template and could create
I would like to use a common datagrid controltemplate for this, like the one defined below.
However it doews not bring in the binding value - it shows up blank.
Could someone help spot me on what I am doing wrong?
<Style x:Key="dgCellBool" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Ellipse>
<Ellipse.Height>10</Ellipse.Height>
<Ellipse.Width>10</Ellipse.Width>
<Ellipse.Style>
<Style TargetType="Ellipse">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Binding}" Value="True">
<Setter Property="Fill" Value="Red"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Binding}" Value="False">
<Setter Property="Fill" Value="Green"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Thanks
Rajesh

You are trying to bind Binding property of DataGridCell but DataGridCell dont have any Binding property. Yoy should set Path=Column.Binding. DataGridCell has Column property which further has Binding Property.
Binding="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Column.Binding}"
I hope this will help.

You need to provide a ContentPresenter to present the content and make sure you add the Border that you will lose from the original Template:
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
UPDATE >>>
If you want your Ellipse instead of a Border, just add it back in with a Grid... Ellipse objects cannot have any content:
<Style x:Key="dgCellBool" TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Grid>
<Ellipse Height="10" Width="10">
<Ellipse.Style>
<Style TargetType="Ellipse">
<Setter Property="Fill" Value="Red" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={
RelativeSource TemplatedParent}, Path=Binding}" Value="False">
<Setter Property="Fill" Value="Green" />
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
</Ellipse>
<ContentPresenter VerticalAlignment="Center"
HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Related

WPF Listview Scrollbar Visibility Trigger

I'm trying to set up a trigger that removes the padding on the listview when the scrollbar is hidden.
I put the trigger on the listview style but I'm getting inconsistent results. For example the background property in the trigger is always active no matter what the scrollbar visibility is.
I've taken a look at the MSDN for the ScrollViewer.ComputedVerticalScrollBarVisibility Property but am not having much luck figuring out what's wrong.
<ListView Grid.Row="1" Grid.Column="1" BorderBrush="{x:Null}" BorderThickness="0" ItemsSource="{Binding Tasks}" Margin="5"
ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate>
<DataTemplate>
<!-- SNIP -->
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Style>
<Style>
<Setter Property="ListView.Padding" Value="0,0,5,0"/>
<Setter Property="ListView.Background" Value="{x:Null}" />
<Style.Triggers>
<Trigger Property="ScrollViewer.ComputedVerticalScrollBarVisibility" Value="Hidden">
<Setter Property="ListView.Padding" Value="0"/>
<Setter Property="ListView.Background" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</ListView.Style>
</ListView>
I write an ListView style example which worked for me. I tried it.
<Style TargetType="ListView">
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListView">
<ScrollViewer>
<ScrollViewer.Style>
<Style TargetType="ScrollViewer">
<Style.Triggers>
<Trigger Property="ComputedVerticalScrollBarVisibility" Value="Visible">
<Setter Property="Padding" Value="100"/>
</Trigger>
<Trigger Property="ComputedVerticalScrollBarVisibility" Value="Collapsed">
<Setter Property="Padding" Value="10"/>
</Trigger>
</Style.Triggers>
</Style>
</ScrollViewer.Style>
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

Can someone explain me this behaviour about style and datatrigger?

Basically, i have a checkbox which has the IsChecked property binded in the viewmodel. This property is then evaluated inside a datatrigger to decide the color of a progress bar. The Progress bar itself, is styled with the code that i'm going to present.
Now, this code work:
<Style x:Key="CustomProgressBar" TargetType="ProgressBar">
<Style.Triggers>
<DataTrigger Value="True" Binding="{Binding Path=IsChecked}">
<Setter Property="Background" Value="Red"/>
</DataTrigger>
<DataTrigger Value="False" Binding="{Binding Path=IsChecked}">
<Setter Property="Background" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Border BorderBrush="{DynamicResource ProgressBorderBrushColor}" BorderThickness="0" Background="{DynamicResource ProgressBackgroundColor}" CornerRadius="0" Padding="0">
<Grid x:Name="PART_Track">
<Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="{Binding}"/>
</Style>
</Rectangle.Style>
</Rectangle>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
while the following not:
<Style x:Key="CustomProgressBar" TargetType="ProgressBar">
<Setter Property="Template" >
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Border BorderBrush="{DynamicResource ProgressBorderBrushColor}" BorderThickness="0" Background="{DynamicResource ProgressBackgroundColor}" CornerRadius="0" Padding="0">
<Grid x:Name="PART_Track">
<Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left">
<Rectangle.Style>
<Style TargetType="Rectangle">
<Style.Triggers>
<DataTrigger Value="True" Binding="{Binding Path=IsChecked}">
<Setter Property="Fill" Value="Red"/>
</DataTrigger>
<DataTrigger Value="False" Binding="{Binding Path=IsChecked}">
<Setter Property="Fill" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Can you tell me what is missing or what is wrong in the second xaml? (don't mind to the border part)
I think you have those backwards: the second example works, while the first does not.
The first example doesn't work because the Rectangle.Fill binding doesn't make sense. You're binding the Fill to whatever ProgressBar.DataContext is. Change the Rectangle definition to:
<Rectangle x:Name="PART_Indicator"
HorizontalAlignment="Left"
Fill="{TemplateBinding Background}" />
{TemplateBinding XYZ} is a short form of {Binding Path=XYZ, RelativeSource={RelativeSource TemplatedParent}. It means "bind to property XYZ on the control to which this template is applied". In this case, the template is applied to a ProgressBar, so we are binding Rectangle.Fill to the progress bar's Background. When your Setters update the background, the rectangle gets updated too.

WPF- trigger target not found

I have own style on listbox, I use in style data template and also control template.
In data template I create listbox item with some textboxes. In control template I want create a trigger which change foreground color of some textbox if listbox item is selected.
Here is some from style:
<Style x:Key="lbStyle" TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Grid Name="MainGrid">
<TextBlock Name="tbName" Text="{Binding Value.nick}"
Grid.Column="0" Grid.Row="0" Margin="2,2,2,2"
FontSize="13" FontWeight="Medium"></TextBlock>
</Grid>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="tbName" Property="Foreground" Value="Black"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Problem is, I get compile error : Cannot find the Trigger target tbName.
<Style TargetType="ListBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding}" Margin="2" FontSize="13" FontWeight="Medium">
<TextBlock.Style>
<Style BasedOn="{StaticResource {x:Type TextBlock}}" TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}, Path=IsSelected}" Value="True">
<Setter Property="Foreground" Value="Black"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
Your code of template is incorrect. You apply ListBoxItem template to ListBox template. Also, you didn't add anything inside ControlTemplate.
I have rewrited it:
<Style x:Key="itemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter x:Name="itemContent"/>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="itemContent" Property="TextBlock.Foreground" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
ListBox with applied style:
<ListBox ItemContainerStyle="{StaticResource itemStyle}" />

Styling TabItem when populated with ItemsSource

I'm using a WPF Tabcontrol populated with a collection using Itemssource.
<TabControl x:Name="_tabControl" ItemsSource="{Binding TabViewModelList}">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding TabCaption}"/>
<Setter Property="Content" Value="{Binding TabContent}"/>
<Setter Property="IsSelected" Value="{Binding IsDefault}"/>
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
Now I want to set my TabItem-style in my App.xaml(or other resourcefile) like this:
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="Border"
Background="LightBlue"
BorderBrush="Black"
BorderThickness="1,1,1,1"
CornerRadius="6,6,0,0" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="12,2,12,2"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
..but the ItemContainerStyle, of course overrides the controltemplate.
How do I combine these two so I can load my tabcontrol dynamically and still be able to style my TabItems the way I want to?
Ok... Solved my own problem. Pretty obvious..
Named my template
<Style TargetType="{x:Type TabItem}" x:Key="TabItemTemplate">
Added a BasedOn property like this:
<Style TargetType="TabItem" BasedOn="{StaticResource TabItemTemplate}">
But if I could combine them into one template please let me know...

WPF Binding & Converters

I've been recently playing with WPF and I've come across a number of problems that I can't solve. I have the following code in my generic.xaml:
<Style TargetType="{x:Type local:ClearButton}">
<Style.Resources>
<con:ValueConverter x:Key="converter" />
</Style.Resources>
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ClearButton}">
<Grid>
<Image Width="{TemplateBinding Width}" Height="{TemplateBinding Height}">
<Image.Style>
<Style TargetType="{x:Type Image}">
<Setter Property="Source" Value="/WPF-Libraries;component/Resources/ClearEnabled.png" />
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BitmapEffect">
<Setter.Value>
<OuterGlowBitmapEffect Opacity="0.5" GlowColor="Red" GlowSize="3" />
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Source"
Value="/WPF-Libraries;component/Resources/ClearDisabled.png" />
</Trigger>
<!--Binding #1-->
<Trigger Property="{TemplateBinding local:ClearButton.IsPressed}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<!--Binding #2-->
<ScaleTransform CenterX="CONVERTER BINDING:PASS WIDTH TO CONVERTER" CenterY="CONVERTER BINDING:PASS HEIGHT TO CONVERTER" ScaleX="0.75" ScaleY="0.75" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I can't get Binding #1 to work. I want to bind the trigger to the IsPressed property of the button, what should the binding be? Also what should the binding be for Binding #2 if I want to pass the button's Width and Height to the converter?
Also I could set the trigger this way instead:
<Style TargetType="{x:Type local:ClearButton}">
<Style.Resources>
<con:ValueConverter x:Key="converter" />
</Style.Resources>
<Setter Property="Width" Value="20" />
<Setter Property="Height" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:ClearButton}">
<!--Abbreviated-->
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!--Binding #1-->
<Trigger Property="{TemplateBinding local:ClearButton.IsPressed}" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<!--Binding #2-->
<ScaleTransform CenterX="CONVERTER BINDING" CenterY="CONVERTER BINDING" ScaleX="0.75" ScaleY="0.75" />
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Which one is better and what would the binding be for Binding #1 and #2?
Both approaches are a little bit off. Your first approach is struggling to reach the IsPressed property using binding, however the Property property of the Trigger object is not a DependencyProperty so it doesn't support binding.
Your second approach is closer to the mark but still wrong, again uses binding on the Property property of the Trigger.
Check this out instead:
<Style TargetType="Button" x:Key="ClearButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<TextBlock
Name="x"
Text="I will change my color when ou press me"
TextAlignment="Center"
VerticalAlignment="Center"
Foreground="Red"
TextWrapping="Wrap"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter
TargetName="x"
Property="Foreground"
Value="Green"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Notice that I put the trigger logic on the control template level (specifying the target element), not on the individual element (the TextBlock in this case).

Resources