Bind IsEnabled value from string - wpf

How can I bind a value of string Y or N to a isEnabled Value?
<TextBox IsEnabled="{Binding Path=StringValueFromSomeEntity, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
StringValueFromSomeEntity can be a Y or N value.

Use a converter to convert the string to a bool-value:
public class StringToBoolConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value.ToString().ToLower() == "y")
return true;
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if ((bool)value)
return "Y";
return "N";
}
}
Refer to it in the resources:
<Window.Resources>
<conv:StringToBoolConverter x:Key="StringToBool"/>
</Window.Resources>
Apply it to your binding (if you just want to change the IsEnabled property according to your string, use Mode=OneWay, but if you really want to bind TwoWay you need the ConvertBack-method):
<TextBox IsEnabled="{Binding Path=StringValueFromSomeEntity, Mode=OneWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ResourceKey=StringToBool}"/>

You can create an IValueConverter subclass like this:
public class YNBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value as string) == 'Y';
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value ? 'Y' : 'N';
}
}
You need ConvertBack if you are expecting to bind TwoWay.
Then add it to the resources of your page.
And add it to the binding
{Binding Path=StringValueFromSomeEntity, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged, Converter={StaticResource YNBoolConverter}}

By default string cann't be converted into Boolen type so you have to tell WPF how to convert and take the value in place where you want to have.
here are two ways to implement this.
Using ValueConverter (prefered way)
Add a Converter into your project like below.
public class StringToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
string val = System.Convert.ToString(value).ToUpper();
if (string.IsNullOrWhiteSpace(val))
return false;
return val == "Y" ? true : false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add the namespace into you window and add resource
<Window.Resources>
<convrter:StringToBoolConverter x:Key="stringtoboolConverter"/>
</Window.Resources>
Now refrance this convert into IsEnabled Propery of Checkbox.
<GroupBox Header="With Converter" >
<StackPanel>
<TextBox x:Name="txt1" Text="Y" />
<CheckBox IsEnabled="{Binding ElementName=txt1,Path=Text,Converter={StaticResource stringtoboolConverter}}" />
</StackPanel>
</GroupBox>
Using Style / Triggers (alternative way)
<TextBox x:Name="txt" Text="Y" />
<CheckBox Content="IsEnabled" Tag="{Binding ElementName=txt,Path=Text}" >
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="Tag" Value="Y" >
<Setter Property="IsEnabled" Value="true"/>
</Trigger>
<Trigger Property="Tag" Value="N" >
<Setter Property="IsEnabled" Value="false"/>
</Trigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>

Use a ValueConverter.
Create a class which implements IValueConverter
for example
public class StringToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
string value = (string)value;
return value.Trim().ToLower() == "y";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
After that you can it applay to your binding

Related

Wpf- binding tooltip to a column having comma separated values to be show as a list

How can I display tool tip as a list of values binded to one of the column of a grid having comma separated string value in WPF.
I can bind it to a column which is showing comma separated values.
<ctl:FieldHelp.Columns>
<data:DataGridTextColumn Binding="{Binding ID, Mode=TwoWay}" IsReadOnly="True">
<data:DataGridTextColumn.CellStyle>
<Style TargetType="data:DataGridCell" >
<Setter Property="ToolTipService.ToolTip" Value="{Binding Details}"></Setter>
</Style>
</data:DataGridTextColumn.CellStyle>
</data:DataGridTextColumn>
<data:DataGridTextColumn Binding="{Binding Name, Mode=TwoWay}" IsReadOnly="True"/>
<data:DataGridTextColumn Binding="{Binding Description, Mode=TwoWay}" IsReadOnly="True"/>
Use a value converter. You hav to create a class which implements the IValueConverter interface.
public class TooltipStringListConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// Process your comma seperated string here
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
// You can leave this empty
}
}
In your XAML change
<Setter Property="ToolTipService.ToolTip" Value="{Binding Details}"></Setter>
To this:
<Setter Property="ToolTipService.ToolTip" Value="{Binding Details, Converter={StaticResource TooltipStringListConverter}}"></Setter>
Be sure that you use the correct namespace of the converter.
I have not tested it, but i'm sure this is the way to go.
Edit:
I forgot the include the converter in the xaml like Celso Livero did by adding
<Window ...
xmlns:converters="clr-namespace:NamespaceOfYourConverter"
>
<Window.Resources>
<converters:TooltipStringListConverter x:Key="TooltipStringListConverter"/>
</Window.Resources>
Here, how to use a converter:
change:
Value="{Binding Details}" => Value="{Binding Details, Converter={StaticResource CommaStringConverter}}"
Create your converter
public class CommaStringConverter : BaseConverter, IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return string.Join("\n", value.Split(','));
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Add it to your app.xaml file
<Application
.....
xmlns:converters="clr-namespace:YourAppNameSpace.YourConvertersFolder"
...... >
<Application.Resources>
<converters:CommaStringConverter x:Key="CommaStringConverter " />
...........
</Application.Resources>
</Application>

Disable scrolling if the cursor is over element

I wanted to disable the scrolling when the cursor is over an element in WPF.
If the mouse is over the red rectangle, the scroll should be disabled.
The red rectangle is on a scrollviewer.
Any idea?
I got it to work with this code:
<Window.Resources>
<converter:MouseOverToScrollBarVisibility x:Key="scrollVisibility" />
</Window.Resources>
<ScrollViewer VerticalScrollBarVisibility="{Binding IsMouseOver,
ElementName=rec,
Converter={StaticResource scrollVisibility}}">
<Rectangle Height="50" Width="50" Fill="Red" x:Name="rec"/>
</ScrollViewer>
Then just define this converter:
[ValueConversion(typeof(bool), typeof(ScrollBarVisibility))]
sealed class MouseOverToScrollBarVisibility : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((bool)value) ? ScrollBarVisibility.Hidden : ScrollBarVisibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}

binding radiobuttons group to a property in WPF

Let's imagine that I have:
<RadioButton GroupName="Group1" IsChecked="{Binding Path=RadioButton1IsChecked}" />
<RadioButton GroupName="Group1" IsChecked="{Binding Path=RadioButton2IsChecked}" />
And then in my data source class I have:
public bool RadioButton1IsChecked { get; set; }
public bool RadioButton2IsChecked { get; set; }
public enum RadioButtons { RadioButton1, RadioButton2, None }
public RadioButtons SelectedRadioButton
{
get
{
if (this.RadioButtonIsChecked)
return RadioButtons.RadioButton1;
else if (this.RadioButtonIsChecked)
return RadioButtons.RadioButton2;
else
return RadioButtons.None;
}
}
Can I somehow bind my radio buttons directly to SelectedRadioButton property? I really need RadioButton1IsChecked and RadioButton2IsChecked properties only to calculate the selected radiobutton.
Declare an enumeration similar to:
enum RadioOptions {Option1, Option2}
XAML:
<RadioButton IsChecked="{Binding SelectedOption, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static local:RadioOptions.Option1}}"/>
<RadioButton IsChecked="{Binding SelectedOption, Converter={StaticResource EnumBooleanConverter}, ConverterParameter={x:Static local:RadioOptions.Option2}}"/>
Converter class:
public class EnumBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value.Equals(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((bool)value) ? parameter : Binding.DoNothing;
}
}
<RadioButton GroupName="Group1" IsChecked="{Binding Path=SelectedRadioButton, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=RadioButton1}" />
<RadioButton GroupName="Group1" IsChecked="{Binding Path=SelectedRadioButton, Converter={StaticResource EnumBooleanConverter}, ConverterParameter=RadioButton2}" />
public enum RadioButtons { RadioButton1, RadioButton2, None }
public RadioButtons SelectedRadioButton {get;set;}
public class EnumBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var ParameterString = parameter as string;
if (ParameterString == null)
return DependencyProperty.UnsetValue;
if (Enum.IsDefined(value.GetType(), value) == false)
return DependencyProperty.UnsetValue;
object paramvalue = Enum.Parse(value.GetType(), ParameterString);
return paramvalue.Equals(value);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var ParameterString = parameter as string;
var valueAsBool = (bool) value;
if (ParameterString == null || !valueAsBool)
{
try
{
return Enum.Parse(targetType, "0");
}
catch (Exception)
{
return DependencyProperty.UnsetValue;
}
}
return Enum.Parse(targetType, ParameterString);
}
}
We can create the radio buttons dynamically, ListBox can help us do that, without converters, quite simple.
The advantage is below:
if someday your enum class changes, you do not need to update the GUI (XAML file).
The steps are below:
create a ListBox and set the ItemsSource for the listbox as the enum and binding the SelectedItem of the ListBox to the Selected property.
Then the Radio Buttons for each ListBoxItem will be created.
public enum RadioButtons
{
RadioButton1,
RadioButton2,
None
}
Step 1: add the enum to static resources for your Window, UserControl or Grid etc.
<Window.Resources>
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type system:Enum}"
x:Key="RadioButtons">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="local:RadioButtons" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
Step 2: Use the List Box and Control Template to populate each item inside as Radio button
<ListBox ItemsSource="{Binding Source={StaticResource RadioButtons}}" SelectedItem="{Binding SelectedRadioButton, Mode=TwoWay}" >
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<RadioButton
Content="{TemplateBinding ContentPresenter.Content}"
IsChecked="{Binding Path=IsSelected,
RelativeSource={RelativeSource TemplatedParent},
Mode=TwoWay}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
</ListBox>
Now, enjoy~
References:
https://brianlagunas.com/a-better-way-to-data-bind-enums-in-wpf/
XAML:
<RadioButton IsChecked="{Binding Path=SelectedOption, UpdateSourceTrigger=PropertyChanged}">Option1</RadioButton>
<RadioButton IsChecked="{Binding Path=SelectedOption, UpdateSourceTrigger=PropertyChanged, Converter={v:NotBoolenConverter}}">Option2</RadioButton>
Converter:
public class NotBoolenConverter : IValueConverter
{
public NotBoolenConverter()
{
}
public override object Convert(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
bool output = (bool)value;
return !output;
}
public override object ConvertBack(
object value,
Type targetType,
object parameter,
CultureInfo culture)
{
bool output = (bool)value;
return !output;
}
}
Works with 2 radio buttons, by binding one to the opposite of the other.

Binding a Distinction basedon Actual Width to Visibility

Is it possible to bind an ActualWidth or Width property of a Control to the Visibility of another Control with a distinction about value (like <200)? In my Opinion it is only possible with a converter because a DataTrigger can not work with > or <.
So I tried it with a Converter but it didn't work. I'm not sure which BindingMode is necessary and which kind of converter I need for such a solution.
The xaml code:
<StackPanel>
<Slider x:Name="slider" Height="36" Width="220" Maximum="500"/>
<Rectangle x:Name="mover" Height="12" Stroke="Black" Width="{Binding Value, ElementName=slider}"/>
<Rectangle x:Name="rectangle" Fill="#FFFF9E0E" Height="34" Width="112" Visibility="{Binding ActualWidth, Converter={StaticResource umkehr}, ElementName=rectangle, Mode=OneWay}"/>
</StackPanel>
and the idea for the converter:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value != null) {
var val = System.Convert.ToDouble(value);
if (val > 100)
return Visibility.Visible;
return Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
It is likely not working because you are binding your Rectangle's Visibility to the same rectangle's ActualWidth, and an invisible rectangle will always have a width of 0, so will never be visible.
Here's some examples. One binds to the other rectangle's ActualWidth, and the other binds to your Slider's Value
<Rectangle x:Name="rectangle"
Visibility="{Binding ActualWidth, ElementName=mover,
Converter={StaticResource umkehr}}"/>
or
<Rectangle x:Name="rectangle"
Visibility="{Binding Value, ElementName=slider,
Converter={StaticResource umkehr}}"/>
And as far as I know, there's no easy way of basing a value off of if something is greater than or less than a value. Coverters are your best option.
ActualWidth is a readonly property exposed by FrameworkElement class -
public double ActualWidth { get; }
It is get only property hence you can't set it to other value from code. You can bind to Width of your control instead to make it work.
EDIT
This works for me, may be this is what you want -
Converter
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double)
{
return ((double)value > 100) ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
XAML
<StackPanel>
<Slider x:Name="slider" Height="36" Width="220" Maximum="500"/>
<Rectangle x:Name="mover" Height="12" Stroke="Black" Width="{Binding Value, ElementName=slider}"/>
<Rectangle x:Name="rectangle" Fill="#FFFF9E0E" Height="34" Width="112" Visibility="{Binding ActualWidth, Converter={StaticResource MyConverter}, ElementName=mover, Mode=OneWay}"/>
</StackPanel>
If you're attempting to change the Visibility of a control based on the ActualWidth of another control, you'll either need to use a IValueConverter or you're own type of MarkupExtension (inherit from Binding or BindingBase).
Converter Option:
[ValueConversion(typeof(Double), typeof(Visibility))]
[ValueConversion(typeof(Double?), typeof(Visibility))]
public class MinimumLengthToVisibilityConverter : IValueConverter
{
public Double MinLength { get; set; }
public override Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
{
if ((value == null) || !(value is Double))
{
return DependencyProperty.UnsetValue;
}
return (((Double)value) > MinLength) ? Visibility.Visible : Visibility.Collapsed;
}
public override Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture)
{
return DependencyProperty.UnsetValue;
}
}
MarkupExtension Option:
Read this blog post to get a better feel for how to implement this...
You can actually have the value in a parameter, so you can re-use the converter if you need to:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double cutoff = 0.0;
if(parameter is double)
{
cutoff = (double)parameter;
}
if (parameter is string)
{
Double.TryParse(parameter.ToString(), out cutoff);
}
if (value is double)
{
return ((double)value > cutoff) ? Visibility.Visible : Visibility.Collapsed;
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
And the XAML:
<StackPanel>
<Slider x:Name="slider" Height="36" Width="220" Maximum="500"/>
<Rectangle x:Name="mover" Height="12" Stroke="Black" Width="{Binding Value, ElementName=slider}"/>
<Rectangle x:Name="rectangle" Fill="#FFFF9E0E" Height="34" Width="112"
Visibility="{Binding ActualWidth, Converter={StaticResource ActualWidthToVisibilityConverter},
ElementName=mover, Mode=OneWay, ConverterParameter=100}"/>
</StackPanel>

Call other element inside WPF Tree in Style

My point is this. For test i need when user check chk1 the chk2 element changed the property IsEnabled to False, but i can't do reference to chk2 element.
This is Style XAML.
<Style x:Key="styleCheckBox" TargetType="{x:Type CheckBox}">
<Style.Triggers>
<Trigger Property="IsChecked" Value="True">
</Style.Triggers>
</Style
Call to Style..
<StackPanel>
<CheckBox x:Name="chk1" Content="CheckBox1" Style="{StaticResource styleCheckBox}"/>
<CheckBox x:Name="chk2" Content="CheckBox2"/>
</StackPanel>
You cannot set TargetProperty in Style Trigger. This basically means that you should create a custom control derived from StackPanel which contains two checkboxes and these checkboxes are exposed as properties. Then you'll be able to define a style for that control (not the CheckBox) and set the properties you want.
Much easier way (if only needed for testing) would be this:
<StackPanel>
<StackPanel.Resources>
<local:InverseBoolConverter x:Key="InverseBoolConverter"/>
</StackPanel.Resources>
<CheckBox x:Name="chk1" Content="CheckBox1"/>
<CheckBox x:Name="chk2" Content="CheckBox2" IsEnabled="{Binding ElementName=chk1, Path=IsChecked, Converter={StaticResource InverseBoolConverter}}"/>
</StackPanel>
Where InverseBoolConverter is defined as follows:
[ValueConversion(typeof(bool), typeof(bool))]
public class InverseBoolConverter: IValueConverter {
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if(value is bool)
return !(bool)value;
else
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) {
if(value is bool)
return !(bool)value;
else
return null;
}
}

Resources