I have a table with different columns I am showing two in this code :
<DataGridTextColumn Header="Allocated" Binding="{Binding Allocated}" >
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource converter}">
<Binding Path="Current_Phase" />
<Binding Path="Status" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Op10}" Header="WIP OP10" >
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource converter}">
<Binding Path="Current_Phase" />
<Binding Path="Status" />
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
The problem I have My IConverterClass is returning a background colour and is putting green for both, but my current phase is "op30"(my parameters value) but still is changing the colour of column op10. I am totally lost, pls helppppp.
My converter Class
object IMultiValueConverter.Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string type = values[0].ToString();
string status = values[1].ToString();
if (type == "op10" && status == "10")
{
return Brushes.Green;
}
else if ( type == "op30" && status == "30")
{
return Brushes.Green;
}
else
{
return DependencyProperty.UnsetValue;
}
}
Please Helppp, I dont know what to do.
I don't understand your problem:
Your converter returns green for "op10" and "op30" and you bind that converter to both columns and therefore it changes both columns to green. If you don't want to change the column op10, remove the binding to the converter.
Related
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}"/>
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>
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.
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.
I have control, that is used by others. It has a TexBox that is binding to a decimal value. And since the Precision can vary, I am using a DependencyProperty and MultiBinding to specify it.
When the TextBox is not focused the number should be displayed with the specified Precision, but when it is focused the full number should be displayed.
Example:
Precision: 2
User Input: 29.333
TextBox not focused should show: 29.33
TextBox focused should show: 29.333
I have accomplished this by using a IMultibindingConverter, and the IsFocused property. But I don't know if this is the best approach.
My TexBox is defined like this
<UserControl.Resources>
<conv:ValuePrecisionConverter x:Key="ValuePrecisionConverter" />
</UserControl.Resources>
<TextBox x:Name="myTextBox">
<TextBox.Text>
<MultiBinding Converter="{StaticResource ValuePrecisionConverter}" Mode="TwoWay"
NotifyOnValidationError="true">
<Binding ElementName="parent" UpdateSourceTrigger="PropertyChanged" Path="Value" Mode="TwoWay" />
<Binding ElementName="parent" Path="Precision"/>
<Binding ElementName="parent" Path="AdditionalFormatting"/>
<Binding ElementName="myTextBox" Path="IsFocused" Mode="OneWay"/>
</MultiBinding>
</TextBox.Text>
</TextBox>
My ValuePrecisionConver is defined like this:
public class ValuePrecisionConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
double? value = null;
converter = null;
value = System.Convert.ToDouble(values[0]);
precision = System.Convert.ToInt32(values[1]);
//Other code with 3rd parameter
if (values.Count() > 3)
{
bool isFocused = System.Convert.ToBoolean(values[3]);
if (isFocused)
return value.ToString();
}
/*Here I do the formating with the given precision*/
return formattedValue;
}
}
Is this the best way to accomplish what I need? Is it ok to use the IsFocused property like this?
Try with thisss.
<TextBox x:Name="myTextBox">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="IsFocused" Value="False">
<Setter Property="Text" Value="{Binding Value, StringFormat=n2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Setter Property="Text" Value="{Binding Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</Trigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
I would prefer you to go for Event Trigger with PreviewGotKeyboardFocus and PreviewLostKeyboardFocus... Set the value with a converter.. No need of MuiltBinding here...