I am using "BooleanToVisibilityConverter" to show one image when radio button is checked. Is their any way I can use same sort of style show another image when this radio button is unchecked?
<BooleanToVisibilityConverter x:Key="VisibilityConverter" />
<RadioButton Name="rbttest" IsChecked="True" GroupName="rbtMenuGroup"
Style="{StaticResource RadioButtonMenuStyle}" >
<WrapPanel>
<Image Source="/wpf1;component/Images/test1.png"
Visibility="{Binding IsChecked=false ???}" Style="{StaticResource MenuIconStyle}" />
<Image Source="/wpf;component/Images/test2.png"
Visibility="{Binding IsChecked, Converter={StaticResource
VisibilityConverter},ElementName = rbttest}"
Style="{StaticResource MenuIconStyle}" ></Image>
<TextBlock Text="This is testing" />
</WrapPanel>
</RadioButton>
I found a solution for the time being before I study the MVVM, DataBinding, DependencyProperty, ControlTemplates.
I have added the BooleanToVisibilityConverter class which allows reverse, I mean hide/collapse control when true and visible when false !
using System;
using System.Windows.Data;
using System.Windows;
namespace TestBooleanToVisibilityConverter
{
class BoolToVisibleOrHidden : IValueConverter
{
#region Constructors
/// <summary>
/// The default constructor
/// </summary>
public BoolToVisibleOrHidden() { }
#endregion
#region Properties
public bool Collapse { get; set; }
public bool Reverse { get; set; }
#endregion
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
bool bValue = (bool)value;
if (bValue != Reverse)
{
return Visibility.Visible;
}
else
{
if (Collapse)
return Visibility.Collapsed;
else
return Visibility.Hidden;
}
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
Visibility visibility = (Visibility)value;
if (visibility == Visibility.Visible)
return !Reverse;
else
return Reverse;
}
#endregion
}
}
Now you can reverse this very easily in the XAML.
<local:BoolToVisibleOrHidden x:Key="BoolToVisConverter" Collapse="True" Reverse="True"
/>
<local:BoolToVisibleOrHidden x:Key="BoolToVisConverter2" Collapse="True"
Reverse="false" />
---------------------------------------------------------------------------------
<RadioButton Name="rbttest" IsChecked="True" GroupName="rbtMenuGroup"
Style="{StaticResource RadioButtonMenuStyle}" >
<WrapPanel>
<--Show the image when radio button unchecked-->
<Image Source="/wpf1;component/Images/test1.png"
Visibility="{Binding IsChecked, Converter={StaticResource
BoolToVisConverter},ElementName = rbttest}" Style="{StaticResource MenuIconStyle}"
/>
<--Show the image when radio button checked-->
<Image Source="/wpf1;component/Images/test2.png"
Visibility="{Binding IsChecked, Converter={StaticResource
BoolToVisConverter2},ElementName = rbttest}"
Style="{StaticResource MenuIconStyle}" ></Image>
<TextBlock Text="This is testing" />
</WrapPanel>
Reference : http://www.rhyous.com/2011/02/22/binding-visibility-to-a-bool-value-in-wpf/
Related
Consider in my wpf application, I have a checkbox and 2 textedits, as below:
<CheckBox x:Uid="Checkbox_1" FlowDirection="RightToLeft" IsChecked="{Binding TickCheckBox, Mode=TwoWay}" Style="{StaticResource StandardCheckBoxStyle}">My Checkbox</CheckBox>
<dxe:TextEdit x:Uid="dxe:TextEdit_1" Grid.Row="1" Grid.Column="1" Width="100" Style="{StaticResource FleetScheduledHoursStyle}" EditValue="{Binding RealValue, Mode=OneWay}" EditMode="InplaceInactive" ToolTipService.ShowDuration="20000" />
<dxe:TextEdit x:Uid="dxe:TextEdit_2" Grid.Row="1" Grid.Column="1" Width="100" Style="{StaticResource FleetScheduledHoursStyle}" EditValue="{Binding RealValue, Mode=OneWay}" EditMode="InplaceInactive" ToolTipService.ShowDuration="20000" />
The TickCheckBox is bound to a property in my viewmodel as below:
private bool tickCheckBox;
public bool TickCheckBox
{
get
{
return this.tickCheckBox;
}
set
{
if (this.TickCheckBox.Equals(value))
{
return;
}
this.tiketCheckBox = value;
this.NotifyPropertyChange(() => this.TickCheckBox);
}
}
How do I change the property "EditMode" of one of the textedit (say Text_Edit1) to "InplaceActive" when I ticked the checkbox?
Thanks for your help!
You can use an IValueConverter:
BoolToEditModeConverte.cs
public class BoolToEditModeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is bool isChecked))
{
throw new ArgumentException("Converter value must be of type 'bool'");
}
return isChecked
? EditMode.InplaceInactive
: EditMode.None;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
Usage
<Window>
<Window.Resources>
<BoolToEditModeConverte x:Key="BoolToEditModeConverte" />
</Window.Resources>
<CheckBox x:Name="MyCheckbox" />
<TextEdit EditMode="{Binding ElementName=MyCheckBox,
Path=IsChecked,
Converter={StaticResource BoolToEditModeConverte}}" />
</Window>
Since you're using POCOViewModel, you just define a property for the TextEdit.EditMode and binding in the xaml, and define a method for the TickCheckBox changed event in the poco view model, like this:
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
this.DataContext = Vm.Create();
}
}
[POCOViewModel]
public class Vm {
public virtual bool TickCheckBox { get; set; } = false;
public virtual EditMode EditMode { get; set; } = EditMode.InplaceInactive;
public static Vm Create() => ViewModelSource.Create(() => new Vm());
protected void OnTickCheckBoxChanged() {
if (this.TickCheckBox) {
// or this.EditMode = EditMode.InplaceActive;
this.EditMode = EditMode.Standalone;
} else {
this.EditMode = EditMode.InplaceInactive;
}
}
}
and the xaml:
<StackPanel>
<CheckBox x:Uid="Checkbox_1" FlowDirection="RightToLeft" IsChecked="{Binding TickCheckBox, Mode=TwoWay}">
My Checkbox
</CheckBox>
<dxe:TextEdit
x:Uid="dxe:TextEdit_1"
EditMode="{Binding EditMode}"
EditValue="{Binding RealValue, Mode=OneWay}"
ToolTipService.ShowDuration="20000" />
<dxe:TextEdit
x:Uid="dxe:TextEdit_2"
EditMode="Standalone"
EditValue="{Binding RealValue, Mode=OneWay}"
ToolTipService.ShowDuration="20000" />
</StackPanel>
I want to change the properties of the dynamically populated UI components.
Here is my sample UI. The label and three textboxes created dynamically.
I want to change the visibility of the third textbox if the label content is R11.
and add a combo box with the static resource if the label is R12
Here is my sample code
my main screen XAML
<StackPanel>
<control:MethodControl></control:MethodControl>
<ContentControl Content="{Binding ChildViewModel}" />
</StackPanel>
MainViewModel
class MethodViewModel : ViewModelBase
{
#region Properties
private Method _method;
private PropertyViewModel _childViewModel;
#endregion
#region Getter & Setters
public PropertyViewModel ChildViewModel
{
get { return this._childViewModel; }
set
{
if (this._childViewModel != value)
{
this._childViewModel = value;
RaisePropertyChanged(() => ChildViewModel);
}
}
}
public Method Method
{
get { return _method; }
}
public ICommand UpdateCommand
{
get; private set;
}
#endregion
#region Constructor
/// <summary>
/// Initialize a new interface of the MEthodViewModel class
/// </summary>
public MethodViewModel()
{
//test
_method = new Method();
PropertyViewModel pwm = new PropertyViewModel();
pwm.CollectProperties(_method.Name, _method.Helper);
ChildViewModel = pwm;
UpdateCommand = new UpdateCommand(SaveChanges, () => string.IsNullOrEmpty(_method.Error));
}
#endregion
#region Functions
public void SaveChanges()
{
PropertyViewModel pwm = new PropertyViewModel();
pwm.CollectProperties(_method.Name, _method.Helper);
ChildViewModel = pwm;
}
Child View Model
class PropertyViewModel : ViewModelBase
{
private ObservableCollection<Property> _properties;
public ObservableCollection<Property> Properties
{
get { return _properties; }
}
public PropertyViewModel(string method, string reflection)
{
_properties = new ObservableCollection<Property>();
CollectProperties(method, reflection);
}
public void CollectProperties(string method, string reflection)
{
_properties.Clear();
int methodindex = Array.IndexOf((String[])Application.Current.Resources["MethodNames"], method);
switch (methodindex)
{
case 0:
foreach (String prop in (String[])Application.Current.Resources["Result1"])
{
PopulateProperty(prop, true);
}
break;
default:
foreach (String prop in (String[])Application.Current.Resources["Result2"])
{
PopulateProperty(prop, true);
}
break;
}
}
public PropertyViewModel()
{
_properties = new ObservableCollection<Property>();
}
private void PopulateProperty(string prop, bool p1)
{
Property temp = new Property(prop, "", 0, "");
_properties.Add(temp);
}
}
ChildViewModel XAML
<StackPanel >
<ItemsControl ItemsSource = "{Binding Properties}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<Label Content="{Binding Name}"></Label>
<TextBox Text = "{Binding Path, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding StdDev, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
<TextBox Text = "{Binding Unit, Mode=TwoWay}"
Width = "100" Margin = "3 5 3 5"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
and my resources
<x:Array x:Key="MethodNames" Type="sys:String"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>MM1</sys:String>
<sys:String>MM2</sys:String>
<sys:String>MM3</sys:String>
</x:Array>
<x:Array x:Key="HelperMethods" Type="sys:String"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>HM1</sys:String>
<sys:String>HM2</sys:String>
<sys:String>HM3</sys:String>
</x:Array>
<x:Array x:Key="Result1" Type="sys:String"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>R11</sys:String>
<sys:String>R12</sys:String>
<sys:String>R13</sys:String>
</x:Array>
<x:Array x:Key="Result2" Type="sys:String"
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<sys:String>R21</sys:String>
<sys:String>R22</sys:String>
<sys:String>R23</sys:String>
</x:Array>
<DataTemplate DataType="{x:Type modelViews:PropertyViewModel}">
<control:PropertyControl />
</DataTemplate>
part of the UI is changing with the selections of the combo boxes.
I need whole 3 text boxes for some options, only 1 for some and 1 textbox and 1 combo box for some options depends on the label name.
How can I add this property to dynamically populated user control?
You could add one or several triggers to the DataTemplate, e.g.:
<DataTemplate>
<StackPanel Orientation = "Horizontal">
<Label Content="{Binding Name}"></Label>
<TextBox Text = "{Binding Path, Mode=TwoWay}" Width = "100" Margin="3 5 3 5"/>
<TextBox Text="{Binding StdDev, Mode=TwoWay}" Width="100" Margin="3 5 3 5"/>
<TextBox x:Name="third" Text="{Binding Unit, Mode=TwoWay}" Width="100" Margin="3 5 3 5"/>
<ComboBox x:Name="combo" Visibility="Collapsed" />
</StackPanel>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Name}" Value="R11">
<Setter TargetName="third" Property="Visibility" Value="Collapsed" />
<Setter TargetName="combo" Property="Visibility" Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
I find an easy solution to my question, so let me add it.
I add visibility in the properties and bind the textbox visibility to it.
here is the bool the visibility converter
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
return (bool) value ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// Do the conversion from visibility to bool
}
}
Resource
<converter:BoolToVisibilityConverter x:Key="converter"></converter:BoolToVisibilityConverter>
text box
<TextBox Visibility="{Binding HasUnit,
Converter={StaticResource converter}}" />
I have problem with binding visibility in listbox-item template with property in parent object. Here is a little snippet from custom xaml style template:
<!-- DATA BINDING ITEM TEMPLATE -->
<StackPanel Orientation="Vertical">
<TextBlock Height="19"
....
Text="{Binding InfoTop}"/>
<Rectangle Height="1"
....
Visibility="{Binding _linesVisibility[0], RelativeSource={RelativeSource AncestorType=my:PatientsList}}"/>
<TextBlock Height="19"
....
Text="{Binding InfoMiddle}"
Visibility="{Binding _linesVisibility[0], ElementName=patientsControl}"/>
<Rectangle Height="1"
....
Visibility="{Binding _linesVisibility[1]}"/>
<TextBlock Height="19"
....
Text="{Binding InfoBottom}"
Visibility="{Binding _linesVisibility[1]}"/>
</StackPanel>
I managed to bind Text value by assigning ItemsSource in code file but i can't bind Visibility. As you can see i tried some different ideas but none of them work.
I have public variable public Visibility[] _linesVisibility = new Visibility[2]; in my custom control. This control contains listbox with custom style as above. How to bind properly my _linesVisibility to listbox-item style ?
You can't bind directly to an array:
Visibility="{Binding _linesVisibility[1]}"
This will not work.
You need to bind to a property and your class needs to implement INotifyPropertyChanged:
private Visibility backingVariable;
public Visbilility PublicProperty
{
get { return backingVariable; }
set
{
backingVariable = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("PublicVariable"));
}
}
}
It doesn't have to be a property of type Visibility. It can be any type as long as you bind through a converter that returns Visibility:
public class BoolToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool visibility = (bool)value;
return visibility ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Visibility visibility = (Visibility)value;
return (visibility == Visibility.Visible);
}
}
Usage:
Visibility="{Binding SomeBoolean, Converter={StaticResource boolToVisibilityConverter}}"
where the converter is declared in XAML like this:
<UserControl.Resources>
<globalConverters:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
</UserControl.Resources>
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.
WPF:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"
True="Visible"
False="Collapsed" />
</Window.Resources>
<Canvas>
<StackPanel Canvas.Left="100" Canvas.Top="100" Width="200" Height="100">
<ListBox>
<ListBoxItem>one</ListBoxItem>
<ListBoxItem>two</ListBoxItem>
<ListBoxItem>three</ListBoxItem>
</ListBox>
<StackPanel Orientation="Horizontal"
Visibility="{Binding
RelativeSource={RelativeSource AncestorType={x:Type StackPanel}},
Path=IsMouseOver,
Converter={StaticResource BooleanToVisibilityConverter}}">
<Button>one</Button>
<Button>two</Button>
<Button>three</Button>
</StackPanel>
</StackPanel>
</Canvas>
</Window>
Code:
public abstract class BooleanConverter<T> : IValueConverter
{
public BooleanConverter(T trueValue, T falseValue)
{
True = trueValue;
False = falseValue;
}
public T True { get; set; }
public T False { get; set; }
public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is bool && ((bool)value) ? True : False;
}
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value is T && EqualityComparer<T>.Default.Equals((T)value, True);
}
}
public class BooleanToVisibilityConverter : BooleanConverter<Visibility>
{
public BooleanToVisibilityConverter()
: base(Visibility.Visible, Visibility.Collapsed)
{ }
}
My the mouse hovers over the ListBox, the buttons are displayed as expected. If the mouse moves below the ListBox on the right side, the buttons vanish. Why is IsMouseOver false over there? Shouldn't the height of the outer StackPanel increase when the inner StackPanel's Visibility property changes from Collapsed to Visible?
Here's the project if you want to play with it: http://dl.dropbox.com/u/4220513/WpfApplication1.zip
You need to set the background of the StackPanel (the outer one) to Transparent to detect mouse over. If background is null as in your sample, hit testing will fail.
Use a background for your StackPanel like <StackPanel Background="Transparent">...