Change predefined style inside a control in xaml - c#

I have the following style in App.xaml:
<Style TargetType="{x:Type Button}">
<Style.Resources>
<DataTemplate x:Key="Unpressed">
<Image Stretch="Uniform" Source="Img/button1.png"/>
</DataTemplate>
<DataTemplate x:Key="Pressed">
<Image Stretch="Uniform" Source="Img/button1_press.png"/>
</DataTemplate>
</Style.Resources>
<Setter Property="ContentTemplate" Value="{StaticResource Unpressed}"/>
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource Pressed}"/>
</Trigger>
</Style.Triggers>
</Style>
I want to change the data template from my button, something like this:
<Button x:Name="Button2">
<Style>
<Style.Resources>
<DataTemplate x:Key="Unpressed">
<Image Stretch="Uniform" Source="../Img/button2.png"/>
</DataTemplate>
<DataTemplate x:Key="Pressed">
<Image Stretch="Uniform" Source="../Img/button2_press.png"/>
</DataTemplate>
</Style.Resources>
</Style>
</Button>
So basically, all my buttons have the same style but each button have an unique image, I need to change the DataTemplate of the style individually for each button

This is my proposed solution:
For the style:
<Application.Resources>
<local:ImgToDisplayConverter x:Key="ImgToDisplayConverter"/>
<local:ImgPressedToDisplayConverter x:Key="ImgPressedToDisplayConverter"/>
<Style TargetType="Image" x:Key="PressedButtonImageStyle">
<Setter Property="Source">
<Setter.Value>
<MultiBinding Converter="{StaticResource ImgToDisplayConverter}">
<Binding Path="Tag" RelativeSource="{RelativeSource AncestorType=Button}"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsPressed, RelativeSource={RelativeSource AncestorType=Button}}" Value="true">
<Setter Property="Source">
<Setter.Value>
<MultiBinding Converter="{StaticResource ImgPressedToDisplayConverter}">
<Binding Path="Tag" RelativeSource="{RelativeSource AncestorType=Button}"/>
</MultiBinding>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</Application.Resources>
For the Control:
<Button Tag="button1" Width="100" Height="100" HorizontalAlignment="Left">
<ContentControl>
<Image Stretch="Uniform" Style="{StaticResource PressedButtonImageStyle}" IsHitTestVisible="False"/>
</ContentControl>
</Button>
The Converters:
class ImgToDisplayConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string image = values[0].ToString();
string resourceName = String.Format("pack://application:,,,/{0}.png", image);
return new BitmapImage(new Uri(resourceName));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
class ImgPressedToDisplayConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
string image = values[0].ToString();
string resourceName = String.Format("pack://application:,,,/{0}_pressed.png", image);
return new BitmapImage(new Uri(resourceName));
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
You can change the code depending on your needs.

I use this simple code and it works well(if you want to release the button from being pressed ,set timer).I hope this will help you..
xaml code
<Button Name="male" Height="318" Width="352" Click="male_Click" Margin="236,120,1332,642">
<Button.Background>
<ImageBrush ImageSource="pack://application:,,,/Imagesrc/logotype/USER_MALE.png" ></ImageBrush>
</Button.Background>
</Button>
pressed code
public void male_Click(object sender, RoutedEventArgs e)
{
System.Windows.Controls.Image img = new System.Windows.Controls.Image();
img.Source = new BitmapImage(new Uri(#"pack://application:,,,/maindocket;component/Imagesrc/logotype/USER_MALE_SELECTED.png"));
male.Content = img;
}

Related

Change style of a button at runtime in wpf with multibinding

I am trying to change the style of a button at runtime depending on a bool property. In addition to that, I am using the mahapps.metro framework.
My Code:
The view:
<UserControl.Resources>
<Style TargetType="{x:Type Button}" x:Key="firstStyle">
<Setter Property= "Style" Value="{StaticResource SquareButtonStyle}"/>
</Style>
<Style TargetType="{x:Type Button}" x:Key="secondStyle">
<Setter Property="Style" Value="{StaticResource AccentedSquareButtonStyle}"/>
</Style>
<conv:ButtonMultiConverter x:Key="styleConvert"/>
</UserControl.Resources>
The button:
<Button>
<Button.Style>
<MultiBinding Converter="{StaticResource styleConvert}">
<Binding Path="ValueFilter" />
<Binding Source="{StaticResource firstStyle}" />
<Binding Source="{StaticResource secondStyle}" />
</MultiBinding>
</Button.Style>
<iconPacks:PackIconModern Width="30" Height="15" Kind="edit"/>
</Button>
The converter:
public class ButtonMultiConverter: IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var firstStyle = values[1] as Style;
var secondStyle = values[2] as Style;
if (values[0] is bool)
return (bool)values[0] ? secondStyle : firstStyle;
return firstStyle;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
With this code I get always the following exception:
"style object is not allowed to affect the style property of the object to which it applies"
What should I change on the xaml code to prevent this exception.
The firstStyle and secondStyle resources are invalid. As the error message says, a Style applied to an element can not have a Setter that sets the Style property of that element.
They are however also redundant. Use SquareButtonStyle and AccentedSquareButtonStyle directly:
<Button.Style>
<MultiBinding Converter="{StaticResource styleConvert}">
<Binding Path="ValueFilter"/>
<Binding Source="{StaticResource SquareButtonStyle}"/>
<Binding Source="{StaticResource AccentedSquareButtonStyle}"/>
</MultiBinding>
</Button.Style>
If for any reason you really need firstStyle and secondStyle, declare them like this:
<Style x:Key="firstStyle" TargetType="Button"
BasedOn="{StaticResource SquareButtonStyle}"/>
<Style x:Key="secondStyle" TargetType="Button"
BasedOn="{StaticResource AccentedSquareButtonStyle}"/>

Changing Background Color of DataGridCell via IValueConverter

I am using a WPF DataGrid with dynamic columns. The colums and binding are generated in code behind which is working fine.
Now I want to change the background color of the DataGrid cell depending on data
Therefore I created a IValueConverter
public class ValueToBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is DataGridCell dgc)
{
var content = dgc.Content;
var header = dgc.Column.Header;
var index = dgc.Column.DisplayIndex;
}
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
Using it that way:
<UserControl.Resources>
<converters:ValueToBrushConverter x:Key="ValueToBrushConverter"/>
<Style x:Key="CellStyle" TargetType="DataGridCell">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource ValueToBrushConverter}}" />
</Style>
</UserControl.Resources>
<DataGrid Grid.Row="2" x:Name="PartsGrid" AutoGenerateColumns="False" IsReadOnly="True" CanUserSortColumns="True"
BorderBrush="Black" Margin="20 10 0 10"
CellStyle="{StaticResource CellStyle}"
VirtualizingPanel.IsContainerVirtualizable="True"
VirtualizingPanel.VirtualizationMode="Recycling"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.CacheLengthUnit="Item"
EnableColumnVirtualization = "True"
EnableRowVirtualization = "True"
>
</DataGrid>
Unfortunately I cannot get the showen Value of the gridcell inside the converter. Header and DisplayIndex are the, but content is null.
So whats the proper way to get the value of the gridcell inside the IValueConverter?
Using a Multibinding Converter solved it:
<Style x:Key="CellStyle" TargetType="DataGridCell">
<Setter Property="Background" >
<Setter.Value>
<MultiBinding Converter="{StaticResource ValueToBrushConverterMulti}" >
<Binding Path="." RelativeSource="{RelativeSource Self}"/>
<Binding Path="." RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=DataGridColumn}" />
</MultiBinding>
</Setter.Value>
</Setter>

Cant set Style in Trigger wpf

i want to change style when toggle button checked
<ToggleButton.Style>
<Style TargetType="ToggleButton" BasedOn="{StaticResource ToggleButtonPrimary}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=ButtonNude, Path=IsChecked}" Value="True">
<Setter Property="Style" Value="{StaticResource ToggleButtonDanger}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
but my code not work and app crash
As suggested by #clemens , the right way would be to have template and apply in controlTemplate with TargetName
There is one more (may be ugly) way:
On view:
<StackPanel>
<StackPanel.Resources>
<local:Myconverter x:Key="MyConverter" />
<Style TargetType="ToggleButton" x:Key="ToggleButtonPrimary">
<Setter Property="Background" Value="blue" />
</Style>
<Style TargetType="ToggleButton" x:Key="ToggleButtonDanger">
<Setter Property="Background" Value="Red" />
</Style>
</StackPanel.Resources>
<CheckBox Margin="20" x:Name="chk" />
<ToggleButton Width="100" Height="100" >
<ToggleButton.Style>
<MultiBinding Converter="{StaticResource MyConverter}">
<MultiBinding.Bindings>
<Binding ElementName="chk" Path="IsChecked"/>
<Binding RelativeSource="{RelativeSource AncestorType=StackPanel}"/>
</MultiBinding.Bindings>
</MultiBinding>
</ToggleButton.Style>
</ToggleButton>
</StackPanel>
Converter:
public class Myconverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)values[0])
{
return (values[1] as FrameworkElement).Resources["ToggleButtonDanger"];
}
else
return (values[1] as FrameworkElement).Resources["ToggleButtonPrimary"];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Hope that helps.

How to color certain header columns and certain cells of a datagrid wpf

I was trying a example to color certain datagrids cell depending on a condition but do not know how to manage color of certain cells with code
In the following code, the third column will be red if date is even
I am using
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LoadSummaryMesh();
}
private void LoadSummaryMesh()
{
DataTable dt = new DataTable();
dt.Columns.Add("c1");
dt.Columns.Add("c2");
dt.Columns.Add("xxx", typeof(DateTime));
dt.Rows.Add("aa", "" , DateTime.Now.AddDays(0));
dt.Rows.Add("bb", "" ,DateTime.Now.AddDays(1));
dt.Rows.Add("cc", "" , DateTime.Now.AddDays(2));
this.dataGrid1.DataContext = dt;
}
}
public class MyBkColorConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DataRowView drv = value as DataRowView;
if (drv != null)
{
DateTime dt = DateTime.Parse(drv[2].ToString());
if (dt.Day % 2 == 0) //If it's a even number day.
return Brushes.Red;
}
return Brushes.White;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
and xaml
<Window x:Class="SummaryMesh.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SummaryMesh"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:MyBkColorConverter x:Key="bkColorCvrt"/>
<Style x:Key="LeftAlignmentColumnHeaderStyle" TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource WrappedColumnHeaderStyle}">
<Setter Property="HorizontalContentAlignment" Value="Left"/>
</Style>
<Style x:Key="soDataGrid_ColumnHeaderRotateStyle" TargetType="DataGridColumnHeader" >
<Setter Property="ContentTemplate" >
<Setter.Value>
<DataTemplate>
<TextBlock TextWrapping="Wrap" Text="{Binding}"
FontWeight="Bold" Width="90"
VerticalAlignment="Center" TextAlignment="Center"
HorizontalAlignment="Center">
<TextBlock.LayoutTransform>
<RotateTransform Angle="270" />
</TextBlock.LayoutTransform>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="HorizontalContentAlignment" Value="Center" />
</Style>
</Window.Resources>
<Grid>
<DataGrid ItemsSource="{Binding}"
AutoGenerateColumns="False"
ColumnHeaderStyle ="{StaticResource soDataGrid_ColumnHeaderRotateStyle}"
Margin="22,12,18,19" Name="dataGrid1"
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding c1}" Width="80" Header="c1" />
<DataGridTextColumn Binding="{Binding c2}" Width="80" Header="c2"/>
<DataGridTextColumn Binding="{Binding xxx}" Width="80" Header="xxx">
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background">
<Setter.Value>
<Binding Converter="{StaticResource bkColorCvrt}"/>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
To get:
Now the question is how can I color only the second column header blue
and how to color [second column,second row] yellow (using the datatable I am using) ?
something similar to
For 'yellow' cell, you can do as third column.
Add a new converter:
public class MyBkColorConverter2 : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DataRowView drv = value as DataRowView;
if (drv != null)
{
int rownum = drv.Row.Table.Rows.IndexOf(drv.Row);
if (rownum == 1)
{
return Brushes.Yellow;
}
}
return Brushes.White;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add it in xaml:
...
<local:MyBkColorConverter2 x:Key="bkColorCvrt2"/>
...
<DataGridTextColumn Binding="{Binding c2}" Width="80" Header="c2">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource soDataGrid_ColumnHeaderRotateStyle}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Yellow"/>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.HeaderStyle>
<DataGridTextColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Background">
<Setter.Value>
<Binding Converter="{StaticResource bkColorCvrt2}"/>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.CellStyle>
</DataGridTextColumn>
For column header:
<DataGridTextColumn Binding="{Binding c2}" Width="80" Header="c2">
<DataGridTextColumn.HeaderStyle>
<Style TargetType="{x:Type DataGridColumnHeader}" BasedOn="{StaticResource soDataGrid_ColumnHeaderRotateStyle}">
<Setter Property="Background">
<Setter.Value>
<SolidColorBrush Color="Yellow"/>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.HeaderStyle>
</DataGridTextColumn>
First about 'yellow' cell you already have an answer, just change CellStyle for a second column as you did it for third column.
Second about header: Add style for your TextBlock at DataGridColumnHeader template, and set required triggers so they will change background, or wrap you TextBlock with grid and set it's background based on trigger.

How to write trigger to textbox IskeyboardFocused property

I am trying to change other UI element visibility when textbox is focused. I think that isKeyboardFocused event may solve my problem. So i write my xaml as following.
<TextBox x:Name="SearchBox" Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Stretch">
<i:Interaction.Triggers>
<e:PropertyChangedTrigger>
<i:Interaction.Behaviors>
<e:ConditionBehavior>
<e:ConditionalExpression>
<e:ComparisonCondition LeftOperand="{Binding SearchBox.IsKeyboardFocused}" Operator="Equal" RightOperand="rue" />
</e:ConditionalExpression>
</e:ConditionBehavior>
</i:Interaction.Behaviors>
<e:ChangePropertyAction TargetName="SearchLabel" PropertyName="Visibility" Value="Hidden" />
</e:PropertyChangedTrigger>
</i:Interaction.Triggers>
</TextBox>
<TextBlock x:Name="SearchLabel" Text="Search" FontStyle="Italic" Foreground="Gray" IsHitTestVisible="False" Visibility="Visible" />
This trigger is not working and i could'nt find the problem. What can i do to fix this problem or any other idea about it?
I would bind the Visibility to the IsKeyboardFocused property as follows:
<UserControl.Resources>
<YourNamespace:BoolToVisConverter x:Key="BoolToVis" />
</UserControl.Resources>
...
<TextBox x:Name="SearchBox" />
<Label Visibility="{Binding ElementName=SearchBox, Path=IsKeyboardFocused, Converter={StaticResource BoolToVis}, ConverterParameter='invert'}">hello</Label>
using a customized BoolToVisibilityConverter:
public class BoolToVisConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool)) throw new ArgumentException("bool value expected");
Visibility invisibleMode = (parameter == null || !(parameter is string) ||
!((string) parameter).ToLower().Contains("hidden"))
? Visibility.Collapsed
: Visibility.Hidden;
if ((parameter as string)?.ToLower().Contains("invert") ?? false) return (!(bool) value) ? Visibility.Visible : invisibleMode;
return ((bool) value) ? Visibility.Visible : invisibleMode;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
The Converter parses given CommandParameter string for:
- "invert": true --> invisible, false --> visible
- "hidden": invisble case leads to Visibilitys.Hidden, otherwise it's Visibility.Collapsed
Well, I also find another answer which solves my problem easily. It may be also useful who has the same problem like me.
<TextBox>
<TextBox.Style>
<Style TargetType="TextBox" xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Style.Resources>
<VisualBrush x:Key="CueBannerBrush" AlignmentX="Left" AlignmentY="Center" Stretch="None">
<VisualBrush.Visual>
<Label Content="Search" Foreground="LightGray" />
</VisualBrush.Visual>
</VisualBrush>
</Style.Resources>
<Style.Triggers>
<Trigger Property="Text" Value="{x:Static sys:String.Empty}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="Text" Value="{x:Null}">
<Setter Property="Background" Value="{StaticResource CueBannerBrush}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter Property="Background" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>

Categories