Displaying "NaN" in a cell depending on the datasource value - c#

I have a Style on my data grid cell defined as follows:
<Style TargetType="{x:Type Editors:XamNumericEditor}" x:Key="MyVisibleStyle" BasedOn="{StaticResource InPointStyle}">
<Setter Property="Mask" Value="-nnnnnnnnnnn.nnnn"/>
<Setter Property="Format" Value="#,##0.000;-#,##0.000" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=DataItem.IsPermissioned}" Value="False" >
<Setter Property="Visibility" Value="Hidden" />
</DataTrigger>
</Style.Triggers>
</Style>
So depending on the value of DataItem.IsPermissioned I set the Visibility of the cell.
How can I change this so that if IsPermissioned=false then I display "NaN" in the cell?

Did you try creating a converter, which implements IValueConverter?
In the binding you would use it like
Binding="{Binding Path=Something, Converter={StaticResource yourConverter}}"
and your converter would be something like
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (validation on the value)
{ return "NaN" } }

You need to alternate the content property instead. So use the part below or add your own content depending on the cell pattern.
<Setter Property="Content" Value="NaN" />

Related

WPF RibbonTab - cannot bind to RibbonTab Headerstyle

I try to customize the RibbonTabHeader with different colors.
However I'm unable to bind dynamic values to the object RibbonTabHeader. One can customize its style by assigning a style to HeaderStyle. But the get of the binded method BackgroundColor is never called.
Xaml:
<Style TargetType="{x:Type ribbon:RibbonTab}">
<Setter Property="Header" Value="{Binding Header}" />
<Setter Property="ItemsSource" Value="{Binding GroupDataCollection}" />
<Setter Property="Visibility" Value="{Binding IsVisible}" />
<Setter Property="IsEnabled" Value="{Binding IsEnabled}"/>
<Setter Property="HeaderStyle">
<Setter.Value>
<Style TargetType="{x:Type ribbon:RibbonTabHeader}">
<Setter Property="Background" Value="{Binding BackgroundColor}"/>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Foreground" Value="#333333" />
</Style>
Code behind:
public string BackgroundColor
{
get { return "Black"; }
}
When I create the style dynamically in the code behind and assign it to HeaderStyle it is actually working. But this doesn't seem to me as an option as my style will become much more complicated (I have to remove gradients, paint a horizontal rectangle, adjust borders, ..). So it will get complicated to create all dynamically in the code behind.
The other bindings that are directly called in RibbonTab i.e. IsEnabled are actually working.
What is working is this code:
In Xaml:
<Setter Property="HeaderStyle" Value="{Binding Style}"/>
In the code behind:
public Style Style
{
get
{
Style style = new Style(typeof (RibbonTabHeader));
style.Setters.Add(new Setter(RibbonTabHeader.BackgroundProperty, Brushes.Green));
return style;
}
}
Any ideas how I can bind dynamic values to the object RibbonTabHeader ?
I was thinking of defining a style in the xaml and then load it via LoadResource in the codebehind. But I'm not sure if I can clone it later to assign all different colors to different tabs.
After days of research I still didn't find a propper answer to my question.
I nevertheless found a workaround to make it work.
What I finally did is to us a CustomConverter to exploit the tab name that is dynamically bound.
The Converter that is returning a different color based on each tab name looks like this:
public class TabNameToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value.ToString() = "tabName")
return "Red";
return "Black";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The Xaml looks like this (Content is the name of the Tab, it is replacing the background color)
<UserControl.Resources>
<ResourceDictionary>
<Converters:TabNameToColorConverter x:Key="TabNameToColorConverter" />
</ResourceDictionary>
</UserControl.Resources>
<Style TargetType="{x:Type ribbon:RibbonTabHeader}">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content,Converter={StaticResource TabNameToColorConverter}}"/>
</Style>

WPF DataGridColumn style depending on tag

following the post in here, I've managed to create Tag property to the columns of my datagrid. Now, I would like to have different colors of columns depending on the value in tag. The goal is to have a table with days in columns, and today's current day would be highlighted (the date corresponding to column is stored in it's tag). Is it achievable? I found the solution based on coloring cells programmatically, but it doesn't suit my needs (multithreading issue - sometimes cell is painted before it stops to fill with data and then painting doesn't work).
Thanks in advance.
Edit:
Ok, I've followed the answer given by Nayeem Mansoori and came to this:
Style:
<Style x:Key="CellStyle" TargetType="{x:Type DataGridCell}">
<Setter Property="Foreground" Value="Black" />
<Setter Property="Background" Value="{TemplateBinding local:DataGridCellThemeProps.Brush}" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="#B2DCDCDC" />
<Setter Property="BorderBrush" Value="#B2DCDCDC" />
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter Property="Background" Value="#7FFFFFFF" />
<Setter Property="BorderBrush" Value="#7FFFFFFF" />
</Trigger>
</Style.Triggers>
</Style>
DataGrid column:
<DataGridTextColumn local:DataGridCellThemeProps.Brush="Thistle"
Header="{x:Static props:Resources.Monday}"
Binding="{Binding Monday, Converter={StaticResource ZeroConverter}, Mode=TwoWay}"
CellStyle="{StaticResource CellStyle}" Width="75"/>
Class:
public static class DataGridCellThemeProps {
public static SolidColorBrush GetBrush(DependencyObject obj) {
return (SolidColorBrush)obj.GetValue(BrushProperty);
}
public static void SetBrush(DependencyObject obj, SolidColorBrush value) {
obj.SetValue(BrushProperty, value);
}
public static readonly DependencyProperty BrushProperty =
DependencyProperty.RegisterAttached(
"Brush",
typeof(SolidColorBrush),
typeof(DataGridCellThemeProps),
new FrameworkPropertyMetadata(Brushes.Black));
}
When I run my app, I get exception:
Exception: {"'Set property 'System.Windows.Setter.Value' threw an exception.' Line number '25' and line position '14'."}
Inner Exception: {"Expression type is not a valid Style value."}
I've double checked namespace of the class, it's correct. Any ideas?

Get Valdiation error in Tooltip if there is an error, else show explanatory Tooltip (using TextBox Style)

Update: Found a Solution, see below!
I'm try to implement the following behavior:
There are several TextBoxes in a UserControl. Each TextBox-ToolTip should show a specific string, which is located in a Resource.resx-file.
If the Valdiation of this TextBox returns an error, the returned error string will be shown in the ToolTip.
This should be done using a Style. My current status is, that I can show the specific Validation.Errors AND a default ToolTip, which is the same for every TextBox which uses the Style.
So my Style is :
<Style TargetType="{x:Type TextBox}">
<Setter Property="ToolTip" Value="ExampleToolTip"/>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self},
Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
With this Style, i get the behavior described above.
Now I want the Style part
<Style TargetType="{x:Type TextBox}">
<Setter Property="ToolTip" Value="ExampleToolTip"/>
...
</Style>
to be TextBox-Specific.
I tried to write an Attatched Property for my TextBoxes, so that I can define a second string, which should be used as the standard ToolTip.
The Attached Property Code ist shown below:
public class TextBox2 : DependencyObject
{
public static void SetToolTipStandard(TextBox target, string value)
{
target.SetValue(ToolTipStandardProperty, value);
}
public static string GetToolTipStandard(TextBox target)
{
return (string)target.GetValue(ToolTipStandardProperty);
}
public static DependencyProperty ToolTipStandardProperty = DependencyProperty.RegisterAttached(
"ToolTipStandard",
typeof(string),
typeof(TextBox),
new PropertyMetadata());
}
Now I want to set a TextBox2.ToolTipStandard property on my TextBoxes in XAML, and the TextBox-Style should take this Property to set the default ToolTip-Text. I tried several combinations of Bindings but with no success. Is there a way to achieve this behavior?
An idea, you can put a hidden border in the ControlTemplate with a BorderThickness of 0 around the input control which provides the error tooltip. If there is an error you set the visibility to visible and the error tooltip is shown.
It's just an idea, but it may work.
I managed to get the desired behaviour by naming all my TextBoxes and adding multiple Triggers to my TextBox-Style. Code follows:
<UserControl.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<!--Here are the static resource strings for the normal-state ToolTip-->
<Trigger Property="Name" Value="TextBox1">
<Setter Property="ToolTip" Value="{x:Static properties:UIStrings.TextBox1_ToolTip_String}"/>
</Trigger>
<Trigger Property="Name" Value="TextBox2">
<Setter Property="ToolTip" Value="{x:Static properties:UIStrings.TextBox2_ToolTip_String}"/>
</Trigger> ...
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors).CurrentItem.ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>

Is it possible to pass a parameter (a Binding) to a WPF Style

I have a WPF style that I am applying to list box items. Currently, each item is bound to a KeyValuePair. I display the Key in a TextBlock inside the ListBoxItem:
<TextBlock Name="Label" Text="{Binding Key}" />
What I want to do is make the Style generic so that if the data is not a KeyValuePair, (maybe just a string), I can bind the data correctly to the TextBlock.
Is there a way to pass a parameter to a Style or DataTemplate or make the data binding generic?
My style:
<Style x:Key="ListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Border" Padding="2" SnapsToDevicePixels="true" CornerRadius="4" BorderThickness="1">
<TextBlock Name="Label" Text="{Binding Key}" />
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="Border" Property="Background" Value="{StaticResource SelectionGradient}" />
</MultiTrigger>
<ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Let me give you a quick example. Let's say your TextBox contains a number, and you want it to be with a red Background if the number is negative, or with a green background if >= 0
Here is the style you'd write:
<TextBlock Text="{Binding Key}" >
<TextBlock.Style>
<Style TargetType="TextBox">
<Setter Property="Background" Value="{Binding Key, Converter={StaticResource MyConverterResource}" />
</Style>
</TextBlock.Style>
</TextBlock>
Here is the converter you'd write:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double source = (double)value;
return source < 0 ? Brushes.Red : Brushes.Green;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// We don't care about this one here
throw new NotImplementedException();
}
}
And, to access the converter in your xaml, you just have to do the following, assuming your converter is in the namespace MyNamespace:
<Window xmlns:my="clr-namespace:MyNamespace">
<Window.Resources>
<my:MyConverter x:Key="MyConverterResource">
</Window.Resources?
<!-- Your XAML here -->
</Window>
(of course you can put this in any Resources, may it be a UserControl or whatever )
This will allow you to call your converter by writing {StaticResource MyConverterResource}
And here, you'd have a conditional style, the converter deciding which color to set as a background according to one parameter, in my case, the value itself (but it can be whatever you want)

How to dynamically set the Row's text to bold, using MVVM, C# and no Code-Behind?

I'm developing a WPF Page using .NET, MVVM, no code-behind, using PropertyChanged. In this Page, I have a DataGrid with a lot of columns.
Into the DB, one of the Columns, let's call it HIGHLIGHT, will have values S or N. If value = S, the entire line will be Bold, or ExtraBold. Case N = Normal.
I made this work using this code in XAML:
<Style x:Key="TextRowStyle" TargetType="{x:Type TextBlock}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Slab.Highlight}" Value="S">
<Setter Property="FontWeight" Value="ExtraBold"/>
</DataTrigger>
</Style.Triggers>
</Style>
But doing in this way, I'll have to put in EVERY COLUMN, this code to make it work (Notice the ElementStyle):
<DataGridTextColumn Header="Test" Binding="{Binding SlabSeq}" ElementStyle="{StaticResource TextRowStyle}"/>
What do I need:
Each table of my DB has several Columns, over 60, 70, and i'm searching for a way to make this more easy, like the StaticResource TextRowStyle i've made...
Another thing i've made, it was a Converter:
public class HighlightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (System.Convert.ToChar(value).Equals("S"))
return FontWeights.ExtraBold;
else
return FontWeights.Normal;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return FontWeights.ExtraBold;
}
}
I'd tried to make a converter inside those fields, using:
<Page.Resources>
<vm:HighlightConverter x:Key="HighlightConverter"/>
</Page.Resources>
and into the Grid:
<TextBlock FontWeight={Binding Slab.Highlight, Converter={StaticResource HighlightConverter}}"/>
Does anyone have any idea of how I can make this work?
Best regards,
Gustavo.
why you dont create a "local" style in your DataGrid.Resources. did i get it right that the entire row has to be bold (S) or normal (N)?
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridCell}" >
<Setter Property="FontWeight" Value="Normal"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Slab.Highlight}" Value="S">
<Setter Property="FontWeight" Value="ExtraBold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
with the code above all cells would be normal, but if a datarow has Slab.Highlight=S all cells would be bold. the code is not tested. maybe you have to add TextBlock.Fontweight or something like that.
What about applying the style implicitly by dropping the x:Key? That should make it apply everywhere in the grid when placed in the DataGrid.Resources.
This might work. Sorry, it's untested as I'm nowhere near an IDE.
<DataGrid>
<DataGrid.Resources>
<Style TargetType="DataGridTextColumn">
<Style.Resources>
<Style TargetType="TextBlock">
<Setter Property="FontWeight" Value="{Binding Slab.Highlight, Converter={StaticResource HighlightConverter}}"/>
</Style>
</Style.Resources>
</Style>
</DataGrid.Resources>
</DataGrid>

Categories