I am creating a Fault Log Application, bound to a database
The primary use of what I want is to format the DateTime cell to RED if the DateTime
listed is greater than 3 weeks prior to the current date.
MainWindow.xaml
<DataGrid AutoGenerateColumns="False" Height="379" HorizontalAlignment="Left" Margin="0,36,0,0" Name="dataGridLog" VerticalAlignment="Top" Width="432" SelectionChanged="dataGridLog_SelectionChanged" IsReadOnly="True" MouseDoubleClick="dataGridLog_MouseDoubleClick" ItemsSource="{Binding}" RowDetailsVisibilityMode="VisibleWhenSelected">
<DataGrid.Columns>
<DataGridTemplateColumn x:Name="dateColumn" Header="Date" Width="80" CanUserReorder="True" CanUserSort="False">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="dateColumnTextBlock" Text="{Binding Path=DateSent, StringFormat={}{0:dd/MM/yyyy}}" Width="80" />
<DataTemplate.Triggers>
<!--<DataTrigger Binding="{Binding Path=DateSent, StringFormat={}{0:dd/MM/yyyy}, Converter={x:Reference mIsEqualOrGreaterThanConverter.Instance}, ConverterParameter=3}" Value="True">
<Setter TargetName="dateColumnTextBlock" Property="Background" Value="Red" />
</DataTrigger>-->
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn x:Name="priorityColumn" Header="Priority" Width="80" CanUserReorder="True" CanUserSort="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="priorityColumnTextBlock" Text="{Binding Path=Priority}" Width="80" />
<!--<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=Priority}" Value="Urgent">
<Setter TargetName="priorityColumnTextBlock" Property="Background" Value="Red" />
</DataTrigger>
</DataTemplate.Triggers>-->
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn x:Name="titleColumn" Binding="{Binding Path=Fault}" Header="Title" Width="270" CanUserReorder="True" CanUserSort="True" />
</DataGrid.Columns>
</DataGrid>
MainWindow.xaml.cs
[ValueConversion(typeof(DateTime), typeof(String))]
public class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime date = (DateTime)value;
DateTime curDate = DateTime.Now;
TimeSpan span = curDate.Subtract(date);
return span.Days;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string strValue = value as string;
DateTime resultDateTime;
if (DateTime.TryParse(strValue, out resultDateTime))
{
return resultDateTime;
}
return DependencyProperty.UnsetValue;
}
}
I cannot seem to bind the converter, not able to convert the dates.
If you have declared your Converter in Resources
<Window.Resources>
<local:IsEqualOrGreaterThanConverter x:Key="IsEqualOrGreaterThanConverter" />
</Window.Resources>
you can reference it like this
<DataTrigger Binding="{Binding Path=DateSent, Converter={StaticResource IsEqualOrGreaterThanConverter}, ConverterParameter=3}" Value="True">
<Setter TargetName="dateColumnTextBlock" Property="Background" Value="Red" />
</DataTrigger>
Your DataTrigger compares with True. Therefore your Converter should return a bool.
[ValueConversion(typeof(DateTime), typeof(bool))]
public class IsEqualOrGreaterThanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime date = (DateTime)value;
DateTime curDate = DateTime.Now;
TimeSpan span = curDate.Subtract(date);
return span.TotalDays > (int)parameter * 7;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Related
I have a DataGrid loaded with a list of objects that have a property bool IsAutomaticSell. I need that when changing the value, the tooltip of the button of that row is updated. I have the following code but it does not work. Thx
View.xaml
<DataGridTextColumn Header="Code"
Binding="{Binding Code}" />
<DataGridTemplateColumn Header="Actions"
Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<Button Command="{Binding DataContext.AutomaticSellCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}"
Padding="10"
Margin="0,2,2,2">
<iconPacks:PackIconModern Kind="CurrencyDollar" />
<Button.Style>
<Style TargetType="{x:Type Button}"
BasedOn="{StaticResource AccentedSquareButtonStyle}">
<Setter Property="ToolTip"
Value="DEFAULT_TOOLTIP" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsAutomaticSell, UpdateSourceTrigger=PropertyChanged}"
Value="True">
<Setter Property="ToolTip"
Value="NEW_TOOLTIP" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
ViewModel.cs
public ICommand AutomaticSellCommand => _automaticSellCommand ??
(_automaticSellCommand = new RelayCommand<OrderStatusDataWrapper>(AutomaticSell));
private static void AutomaticSell(OrderStatusDataWrapper orderStatusData)
{
orderStatusData.IsAutomaticSell = !orderStatusData.IsAutomaticSell;
}
Bind ToolTip.
XAML:
<Button ToolTip={Binding ToolTip}" ... />
ViewModel:
public string ToolTip => (IsAutomaticSell) ? "DEFAULT_TOOLTIP" : "NEW_TOOLTIP";
You need to implement a ValueConverter in order to get this to work.
A ValueConverter will allow you to handle what to display based on your boolean value.
MSDN
public class BoolToContentConverter : IValueConverter
{
public BoolToContentConverter()
{
TrueContent = "True Tool Tip";
FalseContent = "False Tool Tip";
NullContent = "No Value";
}
public object TrueContent { get; set; }
public object FalseContent { get; set; }
public object NullContent { get; set; }
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
if (value == null)
return NullContent;
bool boolValue = true;
bool isBool = true;
try
{
boolValue = (bool) value;
}
catch
{
isBool = false;
}
if (!isBool)
return NullContent;
return boolValue ? TrueContent : FalseContent;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
In your XAML you need to implement that converter.
<Window x:Class="Example.MainWindow"
...
xmlns:l="clr-Example"
...>
<Window.Resources>
<l:BoolToContentConverter x:Key="converter" />
</Window.Resources>
...
<DataGridTextColumn Header="Code"
Binding="{Binding Code}" />
<DataGridTemplateColumn Header="Actions"
Width="150">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal"
HorizontalAlignment="Center">
<Button Command="{Binding DataContext.AutomaticSellCommand,
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
CommandParameter="{Binding}"
Padding="10"
Margin="0,2,2,2">
<iconPacks:PackIconModern Kind="CurrencyDollar" />
<Button.Style>
<Style TargetType="{x:Type Button}"
BasedOn="{StaticResource AccentedSquareButtonStyle}">
<Setter Property="ToolTip"
Value="DEFAULT_TOOLTIP" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsAutomaticSell, UpdateSourceTrigger=PropertyChanged}"
Value="True">
<Setter Property="ToolTip"
Value="{Binding IsAutomaticSell, Converter={StaticResource converter}}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
....
</Window>
Hope this answers your question. Cheers!
I am trying to set visibility of my stackpanel to collapsed if value is null, but DataTriggerBehavior is not changing it's visibility value, If I change value to something else than it work's, below is the xaml for that:
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding Name}"
Value="{x:Null}">
<Core:ChangePropertyAction TargetObject="{Binding ElementName=spName}"
PropertyName="Visibility"
Value="Collapsed" />
</Core:DataTriggerBehavior>
</Interactivity:Interaction.Behaviors>
One option is to use a simple converter which presumes Name is a String and returns an empty String if value is null else returns the value as a String
public class NullToEmptyStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (value == null)
return "";
else
return value.ToString();
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
And your xaml will reference NullToEmptyStringConverter NB local is the namespace where I've created the converter class it maybe different in your app
<Page.Resources>
<local:NullToEmptyStringConverter x:Key="NullToEmptyStringConverter"/>
</Page.Resources>
and your DataTrigger
<Interactivity:Interaction.Behaviors>
<Core:DataTriggerBehavior Binding="{Binding Name, Converter={StaticResource NullToEmptyStringConverter}}"
Value="">
<Core:ChangePropertyAction TargetObject="{Binding ElementName=spName}"
PropertyName="Visibility"
Value="Collapsed" />
</Core:DataTriggerBehavior>
I have this problem, i'm using telerik on WPF and a source on my grid and doing the correct bindings. I want to be able to disable the tooltip when the value of the binding is null or empty. How can it be done?
This is one example:
<telerik:GridViewDataColumn x:Name="GRIDVIEWCOLUMN_ENDDATE" Header="Data de Conclusão" DataMemberBinding="{Binding ClosedDate, StringFormat=dd-MM-yyyy}" IsVisible="False" Width="auto" IsFilterable="False">
<telerik:GridViewDataColumn.ToolTipTemplate>
<DataTemplate>
<TextBlock Text="{Binding ClosedDate, StringFormat=dd-MM-yyyy}" FontFamily="Segoe UI Light" FontSize="13.667" />
</DataTemplate>
</telerik:GridViewDataColumn.ToolTipTemplate>
</telerik:GridViewDataColumn>
Just bind the Visibility of your tooltip (in this case, you have provided a TextBlock) to the same property - ClosedDate, and use a converter to get the value based on your logic.
public class TooltipVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is string)
{
return String.IsNullOrEmpty(value as string) ? Visibility.Collapsed :Visibility.Visible;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
In your XAML, you would have something like this. You declare your converter as a static resource somewhere in your view, and later refer to it in your binding.
<converters:TooltipVisibilityConverter x:Key="TooltipVisibilityConverter"/>
<telerik:GridViewDataColumn x:Name="GRIDVIEWCOLUMN_ENDDATE" Header="Data de Conclusão" DataMemberBinding="{Binding ClosedDate, StringFormat=dd-MM-yyyy}" IsVisible="False" Width="auto" IsFilterable="False">
<telerik:GridViewDataColumn.ToolTipTemplate>
<DataTemplate>
<TextBlock Text="{Binding ClosedDate, StringFormat=dd-MM-yyyy}" FontFamily="Segoe UI Light" FontSize="13.667" Visibility="{Binding ClosedDate, Converter={StaticResource x:Key="TooltipVisibilityConverter"}" />
</DataTemplate>
</telerik:GridViewDataColumn.ToolTipTemplate>
I know this is a pretty old question but I was trying to hide empty tooltips and found a much simpler way to do so here: http://wpfthoughts.blogspot.com/2014/02/hiding-empty-tooltips.html.
Basically if you put a resource dictionary in App.xaml you can automatically hide all empty/null tooltips in your application.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Style TargetType="{x:Type ToolTip}">
<Style.Triggers>
<Trigger Property="Content" Value="{x:Static sys:String.Empty}">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="Content" Value="{x:Null}">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</Style.Triggers>
</Style>
</ResourceDictionary>
It is overkill if you only need it in one spot but it's a super simple fix that prevents you from having to add code to every page that has tooltips. Hopefully this helps someone out.
You can consider using a IValueConverter to show/hide the tooltip border
<telerik:GridViewDataColumn x:Name="GRIDVIEWCOLUMN_ENDDATE" Header="Data de Conclusão" DataMemberBinding="{Binding ClosedDate, StringFormat=dd-MM-yyyy}" IsVisible="False" Width="auto" IsFilterable="False">
<telerik:GridViewDataColumn.ToolTipTemplate>
<DataTemplate>
<Border Background="Black" Visibility="{Binding ClosedDate, Converter={StaticResource BorderVisible}}" >
<TextBlock Text="{Binding ClosedDate, StringFormat=dd-MM-yyyy}" FontFamily="Segoe UI Light" FontSize="13.667" />
</Border>
</DataTemplate>
</telerik:GridViewDataColumn.ToolTipTemplate>
</telerik:GridViewDataColumn>
class BorderVisibilitySetter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
//check if the control's content property is null or empty
if(value == null || value.ToString() == string.Empty)
return Visibility.Collapsed;
else
return Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Setting the tooltip parent control IsEnabled to false will effectively prevent the tooltip to pop unless ToolTipService.ShowOnDisabled is set to true.
Check george.zakaryan's answer, but instead of using a converter to bind the visibility of the tooltip textblock to its content, use a similar converter to Bind the IsEnabled property of the tooltip's parent to its Textblock's text.
public class StringToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string)
{
return String.IsNullOrEmpty(value as string) ? false : true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
in your xaml
<UserControl.Resources>
<utils:StringToBoolConverter x:Key="StringToBoolConverter"/>
</UserControl.Resources>
and
<TextBlock Text="{Binding SrcDrive, Mode=OneWay}" IsEnabled="{Binding SrcDrive, Converter={StaticResource StringToBoolConverter}, Mode=OneWay}" Width="400" >
<TextBlock.ToolTip>
<TextBlock Text="{Binding SrcDrive, Mode=OneWay}" />
</TextBlock.ToolTip>
</TextBlock>
Native Telerik tooltip for GridView has a defect, which is even when you set Visibility=Collapsed it will still show an empty box (see below image):
Code:
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding Name}">
<telerik:GridViewColumn.ToolTipTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" Visibility="Collapsed" />
</DataTemplate>
</telerik:GridViewColumn.ToolTipTemplate>
</telerik:GridViewDataColumn>
</telerik:RadGridView.Columns>
Result:
Solution:
Instead of using null check Converter, the approach that worked for me was to skip showing the tooltip when TextBlock.ToolTipOpeningEvent is triggering.
To do so in your xaml.cs do the following:
public partial class MainWindow: Window
{
public MainWindow()
{
InitializeComponent();
EventManager.RegisterClassHandler(typeof(GridViewCell),
TextBlock.ToolTipOpeningEvent,
new RoutedEventHandler(OnToolTipOpening));
}
private void OnToolTipOpening(object sender, RoutedEventArgs e)
{
if (sender is GridViewCell cell) // show tooltip only when text is trimmed
e.Handled = !IsTextTrimmed(cell);
}
static bool IsTextTrimmed(GridViewCell cell) => cell?.Value.ToString().Length > 50;
}
That's it, and no need to write any additional logic to show/hide tooltips.
I am a beginner to WPF .
I have a data grid for showing messages with column definitions as below . Data grid is bound to a datatable
<my:DataGridTextColumn Binding="{Binding Module}" Header="Module"
Width="75" IsReadOnly="True"></my:DataGridTextColumn>
<my:DataGridTextColumn Binding="{Binding Record ID}" Header="RecordID"
Width="75" IsReadOnly="True"></my:DataGridTextColumn>
<my:DataGridTextColumn Binding="{Binding ItemName}"
Header="Item/Platform/Country Name" Width="175" IsReadOnly="True">
</my:DataGridTextColumn>
<my:DataGridTextColumn Binding="{Binding DateReceived}"
Header="DateReceived" Width="150" IsReadOnly="True">
</my:DataGridTextColumn>
<my:DataGridTextColumn Binding="{Binding Comments}" Header="Comments"
Width="300" IsReadOnly="True"></my:DataGridTextColumn>
Now I need to add a coulmn with header as "Status" . and content as image . I am binding
"IsRead" column of the datatable to this column such that if the IsRead value is False i need to show image unread.png and if the IsRead value is True i need to show image read.png
How do i do this?
You could create a StatusImage property in the class that holds your binding properties:
public string StatusImage {
get
{
if (IsRead)
return "read.png";
return "unread.png";
}
}
And then bind it to the image for example:
<Image Source="{Binding StatusImage}"></Image>
Or as in your case that you haven't got a class. You could choose between a datatrigger:
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Image Name="IsReadImage" Source="read.png"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsRead}" Value="False">
<Setter TargetName="IsReadImage" Property="Source" Value="unread.png"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Or you could use a value converter:
Class:
public class IsReadImageConverter : IValueConverter
{
public Image ReadImage { get; set; }
public Image UnreadImage { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is bool))
{
return null;
}
bool b = (bool)value;
if (b)
{
return this.ReadImage
}
else
{
return this.UnreadImage
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Window Resources:
<local:IsReadImageConverter ReadImage="Read.png" UnreadImage="Unread.png" x:Key="BoolImageConverter"/>
Then your binding would be:
ImageSource={Binding Path=IsRead,Converter={StaticResource BoolImageConverter}}"
Should all work.
I try to get a Button to Enable if all textbox have a value but it doesn´t work and i can´t find out why.
NullToBoolConverter.cs
public class NullToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(bool));
bool nullResult = false;
if (parameter != null)
nullResult = (bool)converter.ConvertFrom(parameter);
if (value == null)
return nullResult;
else
return !nullResult;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
XAML-Ressourcedict.
<ex:NullToBoolConverter x:Key="NullToBoolConverter"/>
<Style x:Key="okButtonStyle" TargetType="{x:Type Button}">
<Setter Property="IsEnabled" Value="False" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Hostadress, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
<Condition Binding="{Binding UserBox, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
<Condition Binding="{Binding PasswordTextBox, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
<Condition Binding="{Binding PortBox, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
I changed your converter to this, as it just seemed to be a lot simpler...
public class NullToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value == null)
return false;
string currentValue = value.ToString();
if (string.IsNullOrWhiteSpace(currentValue))
return false;
return true;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return Binding.DoNothing;
}
}
Then your XAML style should look like this...
<ex:NullToBoolConverter
x:Key="NullToBoolConverter" />
<Style
x:Key="okButtonStyle"
TargetType="{x:Type Button}">
<Setter
Property="IsEnabled"
Value="False" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition
Binding="{Binding ElementName=Hostadress, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
<Condition
Binding="{Binding ElementName=UserBox, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
<Condition
Binding="{Binding ElementName=PasswordTextBox, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
<Condition
Binding="{Binding ElementName=PortBox, Path=Text, Converter={StaticResource NullToBoolConverter}, UpdateSourceTrigger=PropertyChanged}"
Value="True" />
</MultiDataTrigger.Conditions>
<Setter
Property="IsEnabled"
Value="True" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
Debugging worked and typing in all of the textboxes would enable the button.
Notice that I changed the Binding statements to use the ElementName and Path.
I simplified a little bit code:
[ValueConversion(typeof(object), typeof(bool))]
public class NullToBoolValueConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var result = value == null;
return parameter != null ? !result : result;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
I tried your code and I your only problem is that you are only comparing the value to null and not to string.Empty. Try this
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(bool));
bool nullResult = false;
if (parameter != null)
nullResult = (bool)converter.ConvertFrom(parameter);
if (value == null || value.ToString() == string.Empty)
return nullResult;
else
return !nullResult;
}