Invert the output of the boolean visibility converter? - wpf

In WPF, I have an element whose visibility should be bound to a checkbox. I can use BindingPath=IsChecked and Converter={StaticResource convVisibility} to make it visible. However, I want to make it hidden and there is no BindingPath=IsUnchecked. Can I invert the value of the boolean to visibility converter? Thanks for help.
This is in the window xaml:
<Window.Resources>
<BooleanToVisibilityConverter x:Key="convVisibility"/>
</Window.Resources>

This is my solution of this problem:
public class BoolVisibilityCollapsedConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool param = true;
if (parameter != null)
param = System.Convert.ToBoolean(parameter);
bool state = (bool)value;
Visibility visibility = Visibility.Visible;
if (state != param)
visibility = Visibility.Collapsed;
return visibility;
}
If you use this converter, you will switch visibilty like True = Visible / False = Collapsed. If you want the different behavior (True = Collapsed / False = Visible) just use CommandParameter="False"

Related

How can I switch out one UserControl for another during runtime within a Window in WPF?

I have a portion of a Window that should display one of several UserControls. Each UserControl presents the same data, only in a different format, arrangement, and style. The particular UserControl that will be presented in this section of the Window should be determined by a single setting that is stored in the ViewModel of the Window.
How can I make it so that the program end user can change the UserControl that is displayed in the Window at run-time?
I figured it out. In my ViewModel, I have a UserControl property called SelectedUC, and another property, called Style, that is an enum type, which enumerates the different UserControls that I am using. In the set part of the Style property I have OnPropertyChanged("SelectedUC"); The get part of the SelectedUC property has a switch-case statement that sets the field of the SelectedUC to a new instance of the corresponding type of UserControl and passes the ViewModel (this) as a parameter.
private MyStyleEnum _style = MyStyleEnum.OneStyle;
public MyStyleEnum Style
{
get { return _style; }
set
{
if (value != _style)
{
_style = value;
OnPropertyChanged("Style");
OnPropertyChanged("SelectedUC");
}
}
}
private UserControl _selectedUC;
public UserControl SelectedUC
{
get
{
switch (Style)
{
case MyStyleEnum.OneStyle:
_selectedUC = new ucOneControl(this);
break;
case MyStyleEnum.AnotherStyle:
_selectedUC = new ucAnotherControl(this);
break;
}
return _selectedUC;
}
set { _selectedUC = value; }
}
In my MainView's xaml, I have a ContentPresenter with the Content property bound to the SelectedUC property in the ViewModel.
<ContentPresenter Content="{Binding SelectedUC}" />
In my SettingsView's xaml, I have a group of RadioButtons that are all bound to the Style property and use a Converter and ConverterParameter.
<Window x:Class="MyProject.View.SettingsView"
xmlns:cv="clr-namespace:MyProject.Converters"
xmlns:vm="clr-namespace:MyProject.ViewModel">
<Window.Resources>
<cv:EnumToBoolConverter x:Key="EBConverter"/>
</Window.Resources>
<RadioButton Content="One" IsChecked="{Binding Path=Style, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource ResourceKey=EBConverter}, ConverterParameter={x:Static Member=vm:MyStyleEnum.SingleLine}}"/>
</Window>
EnumToBoolConverter.cs:
public class EnumToBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter.Equals(value))
return true;
else
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return parameter;
}
}
One (quick but not necessarily best) way is to add a ContentControl to your window
<ContentControl Name="cc" />
Then set the content of it however you like. Eg. set it in code-behind
cc.Content = new UserControl1();

What is the appropriate approach for implementing custom DependencyProperty for two-way binding in a UserControl?

I was trying to implement a UserControl called ParityTypeSelect that contains two RadioButton - Odd & Even, and the UserControl is to have a DependencyProperty called ParityType which is going to be used in a Two-Way binding. The idea is simple - if Odd is selected ParityType should return 1, and if Even is selected ParityType should return 0.
Here's the code -
XAML (UserControl):
<StackPanel Orientation="Horizontal">
<RadioButton Name="rdoOdd" Content="Odd" Margin="5" Checked="rdoOdd_CheckedChnaged" Unchecked="rdoOdd_CheckedChnaged" />
<RadioButton Name="rdoEven" Content="Even" Margin="5"/>
</StackPanel>
Code-Behind (UserControl):
public partial class ParityTypeSelect : UserControl
{
//Some Code
static ParityTypeSelect()
{
FrameworkPropertyMetadata parityTypeMetaData =
new FrameworkPropertyMetadata(new PropertyChangedCallback(OnParityTypeChanged),
new CoerceValueCallback(CoerceParityTypeValue));
ParityTypeProperty = DependencyProperty.Register("ParityType", typeof(int?), typeof(ParityTypeSelect),
parityTypeMetaData,
new ValidateValueCallback(ValidateParityTypeValue));
}
public static readonly DependencyProperty ParityTypeProperty;
public int? ParityType
{
get { return (int?)GetValue(ParityTypeProperty); }
set { SetValue(ParityTypeProperty, value); }
}
private static void OnParityTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ParityTypeSelect select = (ParityTypeSelect)d;
int? newValue = (int?)e.NewValue;
if (newValue != null && newValue <= 1)
{
if (newValue == 1)
select.rdoOdd.IsChecked = true;
else
select.rdoEven.IsChecked = true;
}
else
return;
}
private void rdoOdd_CheckedChnaged(object sender, RoutedEventArgs e)
{
RadioButton radioButton = (RadioButton)sender;
if (radioButton.IsChecked != null)
{
if (radioButton.IsChecked.Value)
SetValue(ParityTypeProperty, 1);
else
SetValue(ParityTypeProperty, 0);
}
}
//Some more Code
}
XAML (Consumer):
<StackPanel>
<aucl:ParityTypeSelect ParityType="{Binding Path=Format.FisrtBitType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
...And it's working. BUT the thing is, this was my first implementation of DependencyProperty. So I'm a bit concerned if I'm doing it right. Am I using the OnParityTypeChanged method in a right way? Is the use of rdoOdd_CheckedChnaged event handler to set the proerty value OK? Is there any better or more appropriate way to doing any of this whole implementation? I always look forward for quality coding. So any suggestion, improvement-recommendations, comments from WPF guys will be thankfully appreciated.
I was trying to write this in comments but I will do it as a seprate answer. I would bind the property instead of doing it in code behind. You will need a converter because int? will need to be converted to bool. To make the converter as generic as possible I would use an EqualityConverter which you could bind like this:
<RadioButton Content="Odd" Margin="5" IsChecked="{Binding ParityTypeSelect,Mode=TwoWay,Converter={StaticResource equalityConverter}, ConverterParameter=1}" />
Code for the converter is here:
public class EqualityConverter : IValueConverter
{
public object TrueValue { get; set; }
public object FalseValue { get; set; }
public EqualityConverter()
{
//default the TrueValue and FalseValue to true and false.
//this way we can easily use the same converter for simple comparison or as an IIF statement
TrueValue = true;
FalseValue = false;
}
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null && parameter == null) return TrueValue;
if (value == null && parameter != null) return FalseValue;
//in some cases we might need to compare an enum value to an integer.
//this will fail unless we specifically convert them
if (value is int && parameter is Enum)
parameter = System.Convert.ToInt32(parameter);
else if (value is Enum && parameter is int)
value = System.Convert.ToInt32(value);
return value.Equals(parameter) ? TrueValue : FalseValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null && TrueValue == null) return true;
if (value == null && FalseValue == null) return false;
if (value.Equals(TrueValue)) return true;
return false;
}
}
A few other things I would say:
- instead of using a usercontrol you are better off inheriting from Control (just as a standard class, no xaml). You then put the xaml into a file called Generic.xaml. There is little bit of stuff involved so you would need to search the details
- you have unecessary calls to CoerceParityTypeValue and ValidateParityTypeValue, you can leave these out.
- when defining dependency props just type "propdp" (without quotes) and push tab
- usually controls on controls are named starting with PART_, eg PART_OddButton
EDIT: Here is an article which appears to show the main points but isn't quite complete:
http://wpftutorial.net/HowToCreateACustomControl.html
But one thing could be better and that is rather than setting the value of radio button in changed events code you can bind them in xaml like
<RadioButton Name="rdoOdd" Content="Odd" Margin="5" IsChecked="{Binding ParityTypeSelect,Mode=TwoWay,Converter=StaticResource booltoNullIntConverter }" />
booltoNullIntConverter is a converter that changes bool to null int according to your requirement. I hope this will help.

Silverlight Change Content Based on Control CheckState (Toggle multiple ContentPresenters)

I would like to change the content of a control based on its current CheckState (checked, unchecked, indeterminate). If possible I would like the solution to use only XAML and require no code behind.
I am wondering which control to use and how to define the multiple sets of content.
Example: A "ToggleContent" control that displays UserControl1 when the checked state is Unchecked and UserControl2 when the checked state is Checked.
The XAML might look something like this:
<ToggleContent>
<ToggleContent.ContentUnchecked>
<local:UserControl1></local:UserControl1>
</ToggleContent.ContentUnchecked>
<ToggleContent.ContentChecked>
<local:UserControl2></local:UserControl2>
</ToggleContent.ContentChecked>
</ToggleContent>
I'm not sure what "no code behind" means, but this sounds like a perfect example for using a ValueConverter and changing visibility based on the check state.
It would look something like this:
<StackPanel>
<CheckBox x:Name="MyCheckBox"/>
<local:UserControl1 Visibility="{Binding IsChecked, ElementName=MyCheckBox, Converter={StaticResource BoolToVis}, ConverterParameter=False">
<local:UserControl2 Visibility="{Binding IsChecked, ElementName=MyCheckBox, Converter={StaticResource BoolToVis}, ConverterParameter=True">
The Converter:
public class BooleanToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null) return Visibility.Collapsed;
bool comparer = true;
if(parameter != null)
{
comparer = System.Convert.ToBoolean(parameter);
}
return System.Convert.ToBoolean(value) == comparer ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Here's a nice post from Jeff Wilcox on value converters
You can create a style to CheckBox or ToggleButton, replace the ContentPresenter inside the style by your UserControls and change them visibility in the CheckStates.
id create a user control based on the checkbox and use the visualstatemanager to load your controls.

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}" />

Setting Visibility using MVVM pattern in silverlight

I take one grid in silverlight. Initially textbox2 is invisible. When I click on textbox1 we have to visible textbox2. I try it as belows:
<TextBox x:Name="textbox1" SelectionChanged="txt1_SelectionChanged"/>
<TextBox x:Name="textbox2 " Visibility="Collapsed"/>
private void txt1_SelectionChanged(object sender, RoutedEventArgs e)
{
textbox2 .Visibility = Visibility.Visible;
}
It works fine.
But I want to use MVVM pattern. So there I don't want to use eventHandler.
So how to do that using MVVM pattern?
edit: sorry, i thought you meant the textbox to be visible when the other one has focus, I changed my inital answer.
I can not try it at the moment, but you bind the Visibility property of your textbox to the SelectionLength property of the other, using a valueconverter:
<UserControl.Resources>
<local:IntToVisibilityConverter x:Key="IntToVisibilityConverter" />
</UserControl.Resources>
<Textbox
x:name="textbox2"
Visibility={Binding SelectionLength,
ElementName="textbox1"
Converter={StaticResource IntToVisibilityConverter}}
/>
implement the value converter like this:
public class IntToVisibilityConverter : IValueConverter
{
public Object Convert(Object value, Type targetType, Object parameter, CultureInfo culture)
{
return (int)value > 0 ? Visibility.Visible : Visibility.Hidden;
}
public Object ConvertBack(Object value, Type targetType, Object parameter, CultureInfo culture)
{
throw new InvalidOperationException("Converter cannot convert back.");
}
}
Create a property in viewmodel
public bool IsVisible
{
get
{
return _isVisible;
}
set
{
if (_isVisible == value)
{
return;
}
_isVisible = value;
RaisePropertyChanged("IsVisible");
}
}
This returns a boolean value so u need a converter BoolToVisibility Converter make BoolToVisibilityConverter class
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (parameter == null)
{
return ((bool)value == true) ? Visibility.Visible : Visibility.Collapsed;
}
else if (parameter.ToString() == "Inverse")
{
return ((bool)value == true) ? Visibility.Collapsed : Visibility.Visible;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
Now Bind the TextBox and use the converter
<UserControl.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</UserControl.Resources>
<Textbox x:name="textbox2" Visibility={Binding IsVisible,
Converter={StaticResource BoolToVisibilityConverter}}/>
This is it.
The biggest problem you will have is getting the SelectionChanged event sent to the ViewModel. Commands in SL4 only work on button clicks, so TextBox SelectionChanged events can't fire commands by default.
There are a few solutions out there for you:
Binding Commands to ANY event
EventToCommand Behavior
Once you have done that, you can have a command in your ViewModel that sets a Visibility property in your ViewModel and fires the PropertyChanged event.
Using my ViewModelSupport library, the VM would look like this:
public class MyViewModel : ViewModelBase
{
public Visibility ShowTextbox2
{
get { return Get(() => ShowTextbox2, Visibility.Collapsed); }
set { Set(() => ShowTextbox2, value); }
}
public void Execute_SelectionChanged()
{
ShowTextbox2 = Visibility.Visible;
}
}
}
You would then bind the SelectionChanged event to the SelectionChanged command in the VM and the Textbox2 visibility attribute to the ShowTextbox2 property in the VM.
Good luck.
If you are using MVVM Light, you can also do it like this:
using System.Windows; //place it at the top of your view model class.
private Visibility _isVisible = Visibility.Collapsed;
public Visibility IsVisible
{
get
{ return _isVisible; }
set
{
if (_isVisible == value) { return; }
RaisePropertyChanging(() => IsVisible);
_passwordMissing = value;
RaisePropertyChanged(() => IsVisible);
}
}

Resources