Replacing delete button with restore depending on boolean value in WPF - c#

I have boolean column named "deleted" in mysql.
1)if the row is not deleted it shows the delete button.
2)if the row is deleted it should display retore button in that datagrid cell instead of deleted with the query of restore behind it.
right now i can only disable the button if the row is deleted.
My code is as follows.
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete" Name="btnDelete"
Click="btnDelete_Click">
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding deleted}" Value="False">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>

The main idea is using converter that will convert bool value to visibility.
However, for restore button, you will need to invert the visibility behavior, therefore custom converter comes in mind
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (!(value is bool boolValue))
throw new InvalidOperationException();
if (parameter == null || (parameter is bool invertVisibility && !invertVisibility))
return boolValue ? Visibility.Visible : Visibility.Collapsed;
else
return boolValue ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then your buttons will use the same converter registered as:
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"></local:BoolToVisibilityConverter>
</Window.Resources>
But one of them will pass additional parameter so that converter will invert its logic:
<Button Margin="5" Content="Delete"
Visibility="{Binding deleted, Converter={StaticResource BoolToVisibilityConverter}, ConverterParameter=true}"
Command="{Binding DeleteCommand}"></Button>
<Button Margin="5" Content="Restore"
Visibility="{Binding deleted, Converter={StaticResource BoolToVisibilityConverter}}"
Command="{Binding RestoreCommand}"></Button>

You can use the built-in BoolToVisibilityConverter and set the Visibility Property, you might not need a trigger for this
...
<Window.Resources>
<BooleanToVisibilityConverter x:Key="VisibleIfTrueConverter" />
</Window.Resources>
...
<Button Visibility={Binding deleted, Converter={StaticResource VisibleIfTrueConverter}}/>

Related

Cross-binding checkboxes - isChecked #1 -> isEnabled #2

I have a ListBox that takes boolean elements from list in my model and represent them as checkboxes. Just after building project the second checkbox isEnabled is set to false. If I modify (eg. cut and paste same converter) binding in the second checkbox in debug, the binding start working correctly. Also I have a global checkboxes that modyfi isChecked properties of all checkboxes from listBox. If I set globalCheckbox #2, all listBox_checkBoxes #2 are set to true and all listBox_checkBoxes #1 isEnabled property are set to false
XAML:
<ListBox x:Name="ListBox_assent" SelectedIndex="-1" Grid.Row="2" ItemsSource="{Binding Path=FullDataAssetList.List}" IsSynchronizedWithCurrentItem="True" Height="Auto">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource MaterialDesignListBoxItem}">
<Setter Property="Margin" Value="2"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Focusable" Value="False" />
<EventSetter Event="RequestBringIntoView" Handler="ListBoxItem_RequestBringIntoView"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Grid.Row="0" Opacity="{Binding Path=SkipAssentTemp, Converter={StaticResource BoolToOpacity}}">
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="3">
<CheckBox x:Name="chbx_Assent" HorizontalContentAlignment="Left" FlowDirection="RightToLeft" ToolTip="Skip" IsChecked="{Binding SkipAssent, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding SkipAssentTemp, Converter={StaticResource InverseBoolean}}" LostFocus="chbx_Assent_LostFocus" Background="#FFCB0000"/>
<TextBlock FontSize="16" Text=" / " VerticalAlignment="Center"/>
<CheckBox x:Name="chbx_AssentTemp" HorizontalContentAlignment="Left" FlowDirection="RightToLeft" ToolTip="Skip temp." IsChecked="{Binding SkipAssentTemp, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding SkipAssent, Converter={StaticResource InverseBoolean}}" LostFocus="chbx_AssentTemp_LostFocus" Background="#FFCBA300"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Converter:
public class InverseBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (targetType == typeof(bool) || targetType == typeof(bool?))
{
if ((bool?)value == true)
{
return false;
}
else
if ((bool?)value == false)
{
return true;
}
return null;
}
else
{
throw new InvalidOperationException("The target must be a boolean");
}
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
How can i fix binding to get full functionality just after building?
I have found solution. DataTrigger in xaml was overwritnig isEnabled property

Telerik WPF GridView header text disappears when content is bound to tooltip

I am following Telerik guide for displaying a tooltip on WPF GridView column headers. The task is to create a tooltip which would have same text as column header.
In generic.xml there is this style:
<Style TargetType="telerik:GridViewHeaderCell">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content}" />
</Style>
This does work and shows a tooltip when mouse is hovered over column header, however the actual header is being cleared.
I wonder why this is happening and how to fix it? GridViewHeaderCell inherits from ContentControl.
I ended up adding a converter because "Content" value appeared to be a TextBlock:
public class TooltipObject : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value != null)
{
return ((TextBlock)value).Text;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
}
}
and the style looks like:
<utils:TooltipObject x:Key="tooltip" />
...
<Style TargetType="telerik:GridViewHeaderCell">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content, Mode=TwoWay, Converter={StaticResource tooltip}}" />
</Style>

How to trim text displayed in a ComboBox?

I have my own combobox (autocompleteCombobox) where I would like to see only 35 characters of the selectedItem, but with a tooltip that show the full name.
The user control code:
<UserControl.Resources>
<Style x:Key="ComboboxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ShownName}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<ComboBox x:Name="Combobox" IsSynchronizedWithCurrentItem="True"
IsEditable="True" TextSearch.Text="ShownName"
IsTextSearchEnabled="True" DisplayMemberPath="ShownName"
ToolTip="{Binding SelectedItem.ShownName,ElementName=autoComplete}"
ItemsSource="{Binding ItemsSource,ElementName=autoComplete}"
SelectedItem="{Binding SelectedItem, ElementName=autoComplete}"
Style="{StaticResource ComboboxStyle}">
<ComboBox.InputBindings>
<KeyBinding Key="Enter"
Command="{Binding Path=SelectItemCommand, ElementName=autoComplete}"
CommandParameter="ShownName"/>
</ComboBox.InputBindings>
</ComboBox>
</Grid>
And inside the cs file of the autocompletecombobox:
public static readonly DependencyProperty MaxTextLengthProperty =
DependencyProperty.Register(
"MaxTextLength",
typeof(int),
typeof(ComboBoxAutoComplete),
new UIPropertyMetadata(35));
public int MaxTextLength
{
get { return (int)GetValue(MaxTextLengthProperty); }
set
{
SetValue(MaxTextLengthProperty, value);
LimitTextInCombobox();
}
}
private void LimitTextInCombobox()
{
Combobox.Text = Combobox.Text.Substring(0, MaxTextLength);
}
But it doesn't work...
Rather than trimming the text to a certain number of characters you could let WPF trim it for you with respect to the visual width of the text, which probably would look better. If that is an option for you, you could look into the TextBlock.TextTrimming-property.
you can use converter
[ValueConversion(typeof(object), typeof(string))]
public class StringFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
string str = value.ToString();
if (string.IsNullOrEmpty(str))
{
return "";
}
else
{
if (str.Length >= 35)
{
return str.Substring(0, 35);
}
else
{
return str;
}
}
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
and in Xaml
<Windows.Resources>
<dict:StringFormatConverter x:Key="StringFormatConverter"/>
</Windows.Resources>
<UserControl.Resources>
<Style x:Key="ComboboxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ShowName, Converter={StaticResource StringFormatConverter}}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
The setter of a CLR wrapper for a dependency property should always only call the SetValue method to set the value of the dependency property. Nothing else:
public int MaxTextLength
{
get { return (int)GetValue(MaxTextLengthProperty); }
set
{
SetValue(MaxTextLengthProperty, value);
}
}
Also, you want to keep the original value to be able to display it in the tooltip anyway.
Using a converter as suggested by #Alematt seems like a good option. Just modify the ItemTemplate slightly:
<UserControl.Resources>
<local:Converter x:Key="converter" />
<Style x:Key="ComboboxStyle" TargetType="{x:Type ComboBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding ShownName, Converter={StaticResource converter}}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
And create a converter class:
public class Converter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string shownName = value as string;
if (!string.IsNullOrEmpty(shownName) && shownName.Length > 35)
return shownName.Substring(0, 35) + "...";
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
And keep the Tooltip as it is:
ToolTip="{Binding SelectedItem.ShownName, ElementName=autoComplete}"
Instead of that just pass the SelectedItem to your converter like so:
<ComboBox x:Name="cmb">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource multi}">
<Binding Path="."/>
<Binding Path="SelectedItem" ElementName="cmb"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.Style>
<ComboBox.Items>
<sys:String>Very long string 1</sys:String>
<sys:String>Very long string 2</sys:String>
</ComboBox.Items>
</ComboBox>
Then use your converter like so:
class MultiValConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values[0] != null && values[1] != null)
{
if (values[0].ToString() == values[1].ToString())
{
return "...";//put your logic here i.e. substring(0,30);
}
}
return values[0];
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
and you would reference the converter like this:
<locals:MultiValConverter x:Key="multi"/>

DataTriggerBehavior is not working for null values

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>

WPF - Disable tooltip when value is null or empty

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.

Categories

Resources