WPF binding button - wpf

I have two buttons in my application
Now I want to bind the btnOff to !isOn. Meaning is btnOn is Enabled, btnOff should be Disabled and vice-versa
EDIT: Below is my implementation:
<Button x:Name="btnOn" Content="On" Width="45" Height="24" IsEnabled="{Binding isOn, Converter={StaticResource BoolInverter}}" />
<Button x:Name="btnOff" Content="Off" Width="45" Height="24" IsEnabled="{Binding isOn} />
public class BoolInverterConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
}

Wouldn't it be simpler to have another computed/derived property IsOff (no backing field) that negates the IsOn property ?
public bool IsOn{
get{...}
set
{ _isOn = value;
NotifyPropertyChanged("IsOn");
NotifyPropertyChanged("IsOff");
}
}
public bool IsOff
{
get{ return !IsOn;}
}
Converters are normally used to convert data types e.g. to bind a Visibility enum property to a boolean backing property in the viewmodel.

Element data binding,
http://www.codeproject.com/Articles/29054/WPF-Data-Binding-Part-1 -> another example for element data binding

Related

How to use specific properties of a Value converter in wpf xaml

I have a enum to string converter
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
MailSettingsStateEnum enumValue = (MailSettingsStateEnum)value;
// extension method on the enum, to return a string based on enum.
return enumValue.Description();
}
// ConvertBack not relevant here.
}
I am using this in wpf xaml easily as follows to set the Content property of a label.
<Label Content="{Binding MailSettingState, Converter={StaticResource
EnumConverterString}}"
BorderBrush="{Binding MailSettingState, Converter={StaticResource
EnumConverterBorderBrush}}" />
Now as you can see, I have another property BorderBrush. I also have to set this based on the same enum. And so I had to write another converter EnumConverterBorderBrush
So is there a way by which I have only one converter, and it return an object which has two properties and i can use these properties in the xaml? I can create the converter, its easy, but I dont know how to use it in xaml. Say the converter returned an object and has tow property called MessageString(of type string), and another BorderBrush of the type Brush, how do I use it the xaml?
You can switch the output based on the targetType you receive in your converter.
So you could do something like this:
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
var enumValue = (MailSettingsStateEnum)value;
switch(targetType)
{
case typeof(string)
return enumValue.Description();
case typeof(Brush)
return enumValue.GetBrush();
default:
throw new NotSupportedException("Type not supported")
}
}
// ConvertBack not relevant here.
}
Now you'll have one converter to rule them all!
converter should return object which match requested targetType. converter can return different values for input enum value depending on parameter. I think it is more flexible than relying on targetType only.
public class SpecEnumConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Enum)
{
if ((string) parameter == "brush")
return "Red"; // return brush here!
// if not pre-defined parameter (null or any other), return description
return (int) value; // return enum description here!
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
usage:
<Label Content="{Binding MailSettingState, Converter={StaticResource
EnumConverterSpec}}"
BorderBrush="{Binding MailSettingState, Converter={StaticResource
EnumConverterSpec}, ConverterParameter='brush'}" />
I already commented above, but here's the solution.
<Label DataContext="{Binding MailSettingState, Converter={converters:EnumConverter}}" Content="{Binding Label}" BorderBrush="{Binding BorderBrush}"/>
public class EnumConverter: MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var enumValue = (MailSettingsStateEnum) value;
return new ConvertedEnum { Label = enumValue.Description(),
BorderBrush = new BorderBrush()};
}
// ConvertBack not relevant here.
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
public class ConvertedEnum
{
public string Label {get; set;}
public BorderBrush {get; set;}
}
Separate converters still look prettier to me.

binding to a radio button

I have the following radio button bound to the variable IsAllowed
<RadioButton Name="YesRadioButton" Margin="5,5,0,0" IsChecked="{Binding Path=IsAllowed, Mode=TwoWay}">Yes</RadioButton>
How can I make the No button to take the opposite value only using XAML ?
You do not need to. It will happen by default.
Just make sure that IsAllowed starts off as true, and the rest will take care of its self.
This is because when you click on the No button, it will automatically set the Yes button's checked value (that's how radio buttons work), so the change will happen automatically and you backing class will be updated.
EVEN BETTER: Just use a check box. Yes/no situations are what they are designed for.
There is no Xaml-only solution. You could bind No using a reverse bool Converter though.
<local:NotConverter x:Key="notConverter"/>
{Binding IsAllowed, Mode=TwoWay, Converter=notConverter}
public class NotConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Boolean result = false;
if (value is Boolean)
result = !((Boolean)value);
return result;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Boolean result = false;
if (value is Boolean)
result = !((Boolean)value);
return result;
}
}
You will have to write converter using IValueConverter. Here is an example how to do it WPF - Bind to Opposite Boolean Value Using a Converter
The above answer works but I wanted a converter that would apply to both Yes and No radio buttons and reflect the value of nullable booleans. So I made the alternative that takes advantage of converter parameters:
public class YesNoRadioButtonToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return CompareValueWithRequiredValueToBeChecked(value, parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return CompareValueWithRequiredValueToBeChecked(value, parameter);
}
private bool CompareValueWithRequiredValueToBeChecked(object value, object parameterValue)
{
bool? convertedValue = ConvertObjectToBool(value);
bool? convertedParameter = ConvertObjectToBool(parameterValue);
bool result = convertedValue == convertedParameter;
return result;
}
private bool? ConvertObjectToBool(object parameter)
{
string stringResult = parameter == null ? null : parameter.ToString();
bool? convertedResult;
bool convertResultTest = false;
if (stringResult != null && !bool.TryParse(stringResult, out convertResultTest))
{
throw new InvalidCastException(string.Format("Cannot convert {0} to a bool.", parameter));
}
convertedResult = stringResult == null ? (bool?)null : (bool?)convertResultTest;
return convertedResult;
}
}
Here is what the XAML looks like:
<converters:YesNoRadioButtonToBooleanConverter x:Key="yesNoToBool" />
<RadioButton Content="Yes" Name="radYes" GroupName="Group1" IsChecked="{Binding Path=boolProperty1, Mode=TwoWay, Converter={StaticResource yesNoToBool}, ConverterParameter=true}" />
<RadioButton Content="No" Name="radNo" GroupName="Group1" IsChecked="{Binding Path=boolProperty1, Mode=TwoWay, Converter={StaticResource yesNoToBool}, ConverterParameter=false}" />

Silverlight 4: how to switch control visibility

I am using MVVM in my Silverlight app. When control visibility is need to be managed by data, I am connecting its 'Visibility' property to object's corresponding property:
XAML:
<TextBlock Text="Price" Visibility="{Binding PriceVisibility, Mode=OneWay}"/>
<TextBox Text="{Binding TicketPrice, Mode=TwoWay}" Visibility="{Binding PriceVisibility, Mode=OneWay}"/>
CodeBehind (C#):
public string PriceVisibility { get { return PriceVisible ? "Visible" : "Collapsed"; } }
But from my perspective, returning string representation of the Visibility property is not a best approach.
Could you please advise if there are any better way?
Thanks!
I just used Reflector to inspect the type converters in the PresentationFramework.dll
There is already an implementation that can convert between boolean and visibility. You should be able to make use of this in your silverlight application.
public sealed class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool flag = false;
if (value is bool)
{
flag = (bool) value;
}
else if (value is bool?)
{
bool? nullable = (bool?) value;
flag = nullable.HasValue ? nullable.Value : false;
}
return (flag ? Visibility.Visible : Visibility.Collapsed);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((value is Visibility) && (((Visibility) value) == Visibility.Visible));
}
}
I've faced the problem of binding a Boolean value to the visibility property, so I've implemented my own Boolean to Visibility Converter, I'm using it with most of my applications.
Add the Following Class to your application:
public class BoolVisibilityConverter : IValueConverter{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture){
bool isVisible = (bool)value;
return isVisible ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){
System.Windows.Visibility currVisibility = (System.Windows.Visibility)value;
return (currVisibility == System.Windows.Visibility.Visible);
}
}
Now To Use it you'll need to add it as a resource in your XAML Code.
<UserControl.Resources>
<Helpers:BoolVisibilityConverter x:Key="boolVisibilityConverter" />
</UserControl.Resources>
In your example use the following:
<TextBlock Text="Price" Visibility="{Binding PriceVisibility, Mode=OneWay, Converter={StaticResource boolVisibilityConverter}}"/>
<TextBox Text="{Binding TicketPrice, Mode=TwoWay}" Visibility="{Binding PriceVisibility, Mode=OneWay, Converter={StaticResource boolVisibilityConverter}}"/>

WPF Radiobutton (two) (binding to boolean value)

I have a property of type boolean presented with checkbox.
I want to change that to two radiobuttons that bind on the same property presenting the value true/false.
How can that be done?
<RadioButton GroupName="Group1"
IsChecked="{Binding PropertyValue}" Content="Yes" />
<RadioButton GroupName="Group1" Content="No"
IsChecked="{Binding PropertyValue,
Converter={StaticResource BoolInverterConverter}}" />
public class BoolInverterConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
if (value is bool)
{
return !(bool)value;
}
return value;
}
#endregion
}
The standard binding approach has the unfortunate side effect of firing the binding setter as "unselected" whenever the UI is loaded. So if you've got code to handle the user's clicks in the setter for your bool, it will do some weird stuff like fire the setter to "false" even though you've bound it to a "true" bool.
I got around this with a converter used specifically for radio buttons:
public class BoolRadioConverter : IValueConverter
{
public bool Inverse { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool) value;
return this.Inverse ? !boolValue : boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool)value;
if (!boolValue)
{
// We only care when the user clicks a radio button to select it.
return null;
}
return !this.Inverse;
}
}
In your resources:
<converters:BoolRadioConverter x:Key="BoolRadioConverter" />
<converters:BoolRadioConverter x:Key="InverseBoolRadioConverter" Inverse="True" />
In your xaml:
<RadioButton
Content="True option"
GroupName="radioGroup1"
IsChecked="{Binding MyProperty,
Converter={StaticResource BoolRadioConverter}}" />
<RadioButton
Content="False option"
GroupName="radioGroup2"
IsChecked="{Binding MyProperty,
Converter={StaticResource InverseBoolRadioConverter}}" />
You can use a value-converter that reverts the boolean value:
With that converter, bind one Checkbox.IsChecked-property to the boolean value without the converter and one CheckBox.IsChecked-property with the converter. This should do the trick.
Here the code for such a converter. I have copied it from here and added some lines of code. There you will find more information about.
public class BoolToOppositeBoolConverter : IValueConverter {
public object Convert(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture) {
if (targetType != typeof(bool)) {
throw new InvalidOperationException("The target must be a boolean");
}
if (null == value) {
return null;
}
return !(bool)value;
}
public object ConvertBack(object value, Type targetType, object parameter,System.Globalization.CultureInfo culture) {
if (targetType != typeof(bool)) {
throw new InvalidOperationException("The target must be a boolean");
}
if (null == value) {
return null;
}
return !(bool)value;
}
}
To use it, declare it in the resource-section.
<local:BoolToOppositeBoolConverter x:Key="BoolToOppositeBoolConverter_ValueConverter"/>
And the use it in the binding as a static resource:
<CheckBox IsChecked="{Binding YourProperty}" />
<CheckBox IsChecked="{Binding YourProperty,Converter={StaticResource BoolToOppositeBoolConverter_ValueConverter}}" />
Please note, the converter is only a simple example. Implement it neatly if you want to use it in productive code. I have not tested it. Make a comment if its not working.
You can achieve this without a converter if you set the GroupName property of two radio button to the same value (so only one can be checked at the time). Then, set IsChecked of one radio button to "True", and bind IsChecked of another to your Boolean. Switching radio buttons will change the Boolean value, however, changing the Boolean value to False will not check the other radio button.
Thanks,
Vlad
Here is the solution on how to bind radio buttons to any type (enumeration, Boolean, string, integer, etc.) with the sample code:
http://www.codeproject.com/Tips/720497/Binding-Radio-Buttons-to-a-Single-Property
When using MVVMLight and DataContext is set in XAML as:
DataContext="{Binding <Your ViewModel property name>, Source={StaticResource Locator}}"
BoolInverterConverter causes Stack Overflow second time the window gets opened.
The work around is to remove DataContext from XAML and do it in code in window constructor after InitializeComponent():
DataContext = ServiceLocator.Current.GetInstance<Your View Model class>();
After some testing it was not enough - Stack Overflow error could pop up randomly when clicking on radio button. The solution which worked for me - instead of the converter use another property for other radio button in a group:
public bool Is9to1 { get; set; }
public bool Is1to9 { get { return !Is9to1; } set { Is9to1 = !value; } }
in XAML:
<RadioButton GroupName="Is9to1" IsChecked="{Binding Is1to9}"/>
<RadioButton GroupName="Is9to1" IsChecked="{Binding Is9to1}"/>
Simplified version of ragunathan's answer.
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) =>
Convert(value);
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) =>
Convert(value);
private object Convert(object value) =>
value is bool ? !(bool)value : value;
Little upgrade of RandomEngy's answer if you want your bool nullable (for no default value/Checked Radiobutton)
public class BoolRadioConverter : IValueConverter
{
public bool Inverse { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? boolValue = (bool?)value;
return this.Inverse ? !boolValue : boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool? boolValue = (bool?)value;
if (boolValue != null && (bool)!boolValue)
{
// We only care when the user clicks a radio button to select it.
return null;
}
return !this.Inverse;
}
}
and the rest is the same as his answer.
From The answer of Mr-RandomQC everything works fine. But when I click another radio in the same group. Then the opposite radio will show a Red box around the radio button.
I changed the code a little bit from his answer to return Binding.DoNothing instead of return null like this.
public class BoolRadioConverter : IValueConverter
{
public bool Inverse { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool)value;
return this.Inverse ? !boolValue : boolValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
bool boolValue = (bool)value;
if (!boolValue)
{
// Return Binding.DoNothing instead of Return null
return Binding.DoNothing;
}
return !this.Inverse;
}
}

WPF/XAML - hide image if another control's text property is empty/not set

i'm new to wpf and this is my first attempt of creating a custom user control. its purpose is to display two values (myText1 and myText2) with their corresponding images (myimage1, myimage2). sometimes, one of these values is not set and therefore oneimage should be hidden as well. here's my code so far:
Window1.xaml
<local:myControl myText2="Hello World!" />
myControl.xaml
<TextBlock Text="{Binding ElementName=myControl,Path=myText1}" />
<Image Source="myimage1.jpg" />
<TextBlock Text="{Binding ElementName=myControl,Path=myText2}" />
<Image Source="myimage2.jpg" />
myText1 was not set in window1.xaml and therefore the textblock remains empty. but the image is still displayed. which lines of code am i missing to hide the image if myText1 (or myText2) was not set in window1.xaml?
You have write converter for text to visibility
public class TextToVisibilityConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is string && targetType == typeof(bool))
{
if (value.ToString().Equals(string.Empty))
return Visibility.Hidden;
else
return Visibility.Hidden;
}
else
{
return null;
}
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is Visibility && targetType == typeof(string))
{
if ((Visibility)value == Visibility.Visible)
{
return "Text";
}
else
{
return string.Empty;
}
}
else
{
return null;
}
}
}
And in XAML < TextToVisibilityConverter x:Key="myCnverter"/>
Couple of small mistakes there:
if (value is string && targetType == typeof(bool))
{
if (value.ToString().Equals(string.Empty))
return Visibility.Hidden;
else
return Visibility.Hidden;
}
Should be
if (value is string && targetType == typeof(Visibility))
{
if (value.ToString().Equals(string.Empty))
return Visibility.Hidden;
else
return Visibility.Visible;
}
You need the following usings:
using System.Windows;
using System.Windows.Data;
You may also consider returning Visibility.Collapsed rather than Visibility.Hidden
Once you create the right converter then is easy.
And not much answers also got that Text.IsEmpty is available for TextBlock Text property
I created a BooleanVisibilityConverter that depends on a parameter the boolean against True or False.
Gives you the !True flexibility that is missing on xaml.
public class BooleanVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility v = Visibility.Collapsed;
bool checkValue = true;
if(parameter != null)
{
checkValue = Boolean.Parse(parameter.ToString());
}
if(value.Equals(checkValue))
{
v = Visibility.Visible;
}
return v;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Then in your xaml import that namespace into:
xmlns:conv="clr-namespace:ConvertersNamespace"
Create the converter into the Resources:
<UserControl.Resources>
<conv:BooleanVisibilityConverter x:Key="bool2vis" />
</UserControl.Resources>
Then just use into your design:
<TextBlock Text="{Binding ElementName=myControl,Path=myText1}" x:Name="txtBlock"/>
<Image Source="myimage1.jpg"
Visibility="{Binding ElementName=txtBlock,Path=Text.IsEmpty,
Converter={StaticResource bool2vis},ConverterParameter=False}"/>

Resources