I saw many posts on how to bind a boolean value to a radio button. But my scenario is that I need to bind it to a radio button and read the selection from the user.
That is no option should be selected intially.
If I bind it to a boolean, since boolean cant be null it shows the default value selected in radio button.
If I use nullable boolean, I still defaults to false when trying to use the converter.
I cant use oneway mode in xaml as I need to check if the radio button selection was made which I do using the bounded variable.
Ant pointers on how to achieve this?
You can bind a nullable boolean to your radio buttons, but you need to do it through a converter.
First declare your variable:
private bool? answer;
public bool? Answer
{
get { return answer; }
set
{
answer = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Answer"));
}
}
and initialise it to null.
Then in the XAML:
<Window.Resources>
<local:BooleanConverter x:Key="BooleanConverter"/>
</Window.Resources>
<StackPanel Grid.Row="1">
<RadioButton Content="I Agree"
IsChecked="{Binding Answer,
Converter={StaticResource BooleanConverter},
ConverterParameter='true', Mode=TwoWay}" />
<RadioButton Content="I Disagree"
IsChecked="{Binding Answer,
Converter={StaticResource BooleanConverter},
ConverterParameter='false', Mode=TwoWay}" />
</StackPanel>
And finally your converter:
class BooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var test = (bool?)value;
var result = bool.Parse((string)parameter);
if (test == result)
{
return true;
}
return false;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var result = bool.Parse((string)parameter);
return result;
}
}
This binds the radio button to Answer and states that the first one will only be checked when the value is true and the second one will be checked when the answer is false. You can then check that Answer is not null before letting the user proceed.
This may not be the best way of doing it, but you could use something similar to this:
checkbox like radiobutton wpf c#
and just have two controls.
I appreciate it's not the best, but reading your answer it gives you what you want (generally).
Related
I have two object: UserDto and RoleDto. User has a property which is the RoleDto.
In my viewmodel I have the following:
public UserDto User
{
get { return _user; }
set
{
if (_user == value) return;
_user = value;
User.PropertyChanged += UserPropertyChanged;
OnPropertyChanged("User");
}
}
private UserDto _user;
public IEnumerable<RoleDto> Roles { get; set; } //I load all available roles in here
In the view, I want to select the role that the user belongs. This is how I define the combobox in the view:
<ComboBox Grid.Row="3" Grid.Column="1" Margin="5" ItemsSource="{Binding Roles}" SelectedItem="{Binding User.Role, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Description" />
If I try to create a new user and select a role from the combobox, it is correctly binded to the user. The problem is that when I load a user that already exists, the role is not displayed in the combobox (even the user has a role defined).
Any help please?
Thanks in advance
This is because the reference of RoleDTO that your UserDTO has, does not match any of the RoleDTOs in Roles collection which you set as ItemsSource of ComboBox.
Better define a property on your ViewModel like
public RoleDTO SelectedRole
{
get { return Roles.FirstOrDefault(role => role.Role == User.RoleDto.Role); }
set { User.RoleDto = value; OnPropertyChanged("SelectedRole"); }
}
and set it as SelectedItem of you combobox
ItemsSource="{Binding Roles}" SelectedItem="{Binding SelectedRole, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Description" />
In my opinion the second option on this page is the easiest way.
https://rachel53461.wordpress.com/2011/08/20/comboboxs-selecteditem-not-displaying/
You can override the equals property on your object so that it returns true if the items have the same data. Then when the combo box box goes to check to make sure your item is in the selection it will find a match.
The other way to solve this problem is using Converter on Binding. when you use binding to bind SelectedItem, WPF will check the reference of SelectedItem against all objects inside ItemsSource property and of course if there was no match, SelectedItem will be empty. using Converter you can tell WPF that how it should match SelectedItem.
In this case you just need find SelectedItem among ItemsSource and return it to Binding. so follow these steps:
1- Create a class and implement IValueConverter. It has two methods: Convert and ConvertBack
2- for Convert method do something like this:
public class MySelecteItemBindingConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var mySelectedItem = value as MySelectedItemType;
var myItemsSource = parameter as List<MySelectedItemType>;
var matchedItem = myItemsSource.FirstOrDefault(i=>i.Id == mySelectedItem.Id);
return matchedItem;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// Do just like Convert method
}
}
3- Use this Converter on your Binding like this:
var myBinding = new Binding("YourBindingPath");
myBinding.Converter = new MySelectedItemBindingConverter();
myBinding.ConverterParameter = myItemsSource; //this is List<MySelectedItemType> in this example
myCombo.SetBinding(ComboBox.SelectedItemProperty, myBinding);
Note: if you want to do binding from XAML you can not pass ConverterParameter like this, instead you should create a static list and use that as ItemsSource or use MultiBinding to pass your ConverterParameter using a trick. here there is a good and simple explanation about it: Binding ConverterParameter
I have a bound WPF comboBox that has an ItemsSource set to a CompositeCollection. I'm trying this to try and accomodate adding <Select> and <Add New...> selections to precede an ObservableCollection of 'regular' objects. What I can't figure out is how to, in code-behind, select one of these added choices.
This is how I'm building the CompositeCollection:
private CompositeCollection CreateItemsSource(ObservableCollection<T> source)
{
CompositeCollection cmpc = new CompositeCollection();
cmpc.Add(new ComboBoxItem { Content = "<Select>" });
cmpc.Add(new ComboBoxItem { Content = "<Add New...>" });
var cc1 = new CollectionContainer { Collection = source };
cmpc.Add(cc1);
return cmpc;
}
This is what the ComboBox looks like:
<DataTemplate x:Key="LookupComboTemplate">
<TextBlock Text="{Binding}"/>
</DataTemplate>
<ComboBox ItemsSource="{Binding SubCategories.ItemsSource}"
ItemTemplate="{StaticResource LookupComboTemplate}">
<ComboBox.SelectedItem>
<Binding Path="SourceData.SubCategoryObj" Mode="TwoWay"></Binding>
</ComboBox.SelectedItem>
</ComboBox>
I've got a situation where SelectedItem SourceData.SubCategoryObj is null (it's an optional property). In this case, I want to manually select and display the <Select> choice. But no matter what I do (setting SelectedIndex is ignored, setting SelectedValue to the ComboBoxItem in the CompositeCollection is ignored) I get a blank ComboBox when it renders.
I'd appreciate any advice on how I can do this.
Thanks!
Corey.
You should be able to fix this with a custom valueconverter for your SelectedItem binding. http://wpftutorial.net/ValueConverters.html should give you some pointers.
I'm not sure if combox wants a simple string or some composite object but you can check that. Something like
public class ComboConverter: IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return "<Select>";
return value;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (value.toString().Equals("<Select>")
return null;
return value;
}
should give you the "<Select>" entry if the selected item is null.
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.
I have ItemsControls with items binded from CollectionViewSource.
<ItemsControl ItemsSource="{Binding Source={StaticResource VisibleFlagsImageSourcePathView}}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<r:RibbonRadioButton SmallImageSource="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And another control outsite:
<TextBox Text="{Binding Path=SelectedCountryCode" />
What I am trying to accomplish is whenever I change the value of the TextBox I want the corresponding RibbonRadioButton property IsChecked set to true or false.
What you need to do is create a ViewModel with two properties.
class MyViewModel
{
// Bind this to TextBox
public String SelectedCountryCode { get; set; }
// Bind this to ItemsControl
public ObservableCollection<Object> VisibleFlagsImageSourcePath { get; set; }
}
// Note I have omitted implementation of `INotifyPropertyChanged`. But, you will need to implement it.
And monitor the SelectedCountryCode, and whenever it changes, change appropriate value in VisibleFlagsImageSourcePath collection.
Radio buttons represent enumerated values. A text box in this case would represent an open value. What you seem to want is a set of open values as well as a pre-set selection of enumerated values. The control that best represents this is a combo box.
If you decide to continue with the radio button/text box approach, you can adapt the method people use to bind radio buttons to an enumerated value, except use a string field/string field type converter instead of an enum field/enum field type converter.
See this answer for how to bind to enums: How to bind RadioButtons to an enum?
To adapt this to strings, simply make a class called KnownStringToBooleanConverter (note that this is an identical implementation to EnumToBooleanConverter):
public class KnownStringToBooleanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(parameter);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value.Equals(true) ? parameter : Binding.DoNothing;
}
}
Also create a type with your known strings (similar to how you would create an enum):
public static class KnownCountryCodes
{
// Note: I'm guessing at these codes...
public const string England = "EN";
public const string Japan = "JP";
}
Then bind to this in a similar way:
<RadioButton IsChecked="{Binding Path=SelectedCountryCode, Converter={StaticResource KnownStringToBooleanConverter}, ConverterParameter={x:Static local:KnownCountryCodes.England}}" />
<RadioButton IsChecked="{Binding Path=SelectedCountryCode, Converter={StaticResource KnownStringToBooleanConverter}, ConverterParameter={x:Static local:KnownCountryCodes.Japan}}" />
If you want all your controls to cross-populate, then you'll need to implement INotifyPropertyChanged in your view model:
public class MyViewModel : INotifyPropertyChanged
{
// Bind this to TextBox and radio buttons. Populate the radio buttons manually
public string SelectedCountryCode
{
get
{
return selectedCountryCode;
}
set
{
selectedCountryCode = value;
RaiseNotifyPropertyChanged("SelectedCountryCode");
}
}
/* Todo: Implement NotifyPropertyChanged and RaiseNotifyPropertyChanged here */
private string selectedCountryCode;
}
When a custom value (that isn't in the list) is entered, the radio buttons will all dim. When you type in a value that is from the list, the corresponding radio button will light up. When you select a correct radio button, the value will be changed in the text box.
This View/ViewModel stuff is called MVVM.
See: http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
I have a checkbox in a UserControl:
<CheckBox Content="Existing" IsChecked="{Binding Path=IsExistingTemplate, Mode=TwoWay}"/>
It is bound to a DataContext with Property IsExistingTemplate which always returns False. (In my real application, it doesn't always return False!). DataContext implements INotifyPropertyChanged.
public bool? IsExistingTemplate
{
get
{
return false;
}
set
{
OnPropertyChanged("IsExistingTemplate")
}
}
When the user clicks the CheckBox, the CheckBox always shows a tick.
How can I force the CheckBox not to show a tick when the user Clicks it?
I remember having a very similar problem, but I can't find where and how I solved it. I thought that the problem was caused by how WPF updates bindings, and I thought that I read somewhere that it could be solved by using an IValueConverter that simply passes the values through, but I've tested that it and it doesn't seem to work. It was supposed to work because using a converter was supposed to make the bindings re-evaluate.
You could always handle the Clicked event on the CheckBox and update the values via code, but it just feels so dirty. Sorry I couldn't be of more help
<StackPanel.Resources>
<local:PassThroughConverter x:Key="PassThroughConverter" />
</StackPanel.Resources>
<CheckBox IsChecked="{Binding IsExistingTemplate, Converter={StaticResource PassThroughConverter}}" Content="Stuff"/>
public class PassThroughConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}