Uncheck checkbox when another is checked - wpf

I have two checkboxes. When I check one, I want the other to uncheck if it's currently checked. Both can be unchecked. Currently, I can check one, but when I check the other, both of them uncheck. I'm having trouble figuring out why.
Note: I want to do this all in the .xaml if possible. I've been messing with data triggers to get the proper effect with no luck so far.
<CheckBox Name="SYOChkBox">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=UTMChkBox}"
Value="True">
<Setter Property="IsChecked"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<CheckBox Name="UTMChkBox">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked, ElementName=SYOChkBox}"
Value="True">
<Setter Property="IsChecked"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>

You should really be using a ViewModel to do this (I'll leave a snippet on how you could do it using a VM at the end of the post).
Anyway, here's what I was able to do with XAML only
Using CheckBox
The problem with using this approach is that when both are checked, both of the triggers will be triggered (??), and both will be unchecked. So, I guess what you can do is this:
CheckBox X will normally uncheck when you check CheckBox Y, but CheckBox X just won't check while CheckBox Y is checked.
<CheckBox Name="SYOChkBox">
<CheckBox.Style>
<Style TargetType="CheckBox">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsChecked, ElementName=UTMChkBox}" Value="True" />
<Condition Binding="{Binding IsChecked, ElementName=SYOChkBox}" Value="True" />
</MultiDataTrigger.Conditions>
<Setter Property="IsChecked" Value="False" />
</MultiDataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<CheckBox Name="UTMChkBox" />
Using RadioButton
I know it isn't what you asked, but as a sugestion, you could use a RadioButton, the code would be a lot cleaner:
<RadioButton>Option A</RadioButton>
<RadioButton>Option B</RadioButton>
<RadioButton>None</RadioButton>
Using ViewModel
XAML
<CheckBox IsChecked="{Binding IsChecked_CheckBoxA}" />
<CheckBox IsChecked="{Binding IsChecked_CheckBoxB}" />
Code-behind:
private bool _IsChecked_CheckBoxA;
private bool _IsChecked_CheckBoxB;
public bool IsChecked_CheckBoxA
{
get
{
return _IsChecked_CheckBoxA;
}
set
{
if (value)
IsChecked_CheckBoxB = false;
_IsChecked_CheckBoxA = value;
NotifyPropertyChanged();
}
}
public bool IsChecked_CheckBoxB
{
get
{
return _IsChecked_CheckBoxB;
}
set
{
if (value)
IsChecked_CheckBoxA = false;
_IsChecked_CheckBoxB = value;
NotifyPropertyChanged();
}
}

As others have said, it might not be doable in just xaml, and using a viewmodel is suggested. So here's what I have that works:
Xaml:
<CheckBox Name="SYOChkBox"
IsChecked="{Binding IsCheckedSYO}" />
<CheckBox Name="UTMChkBox"
IsChecked="{Binding IsCheckedUTM}" />
Viewmodel:
private bool _isCheckedSYO;
public bool IsCheckedSYO
{
get { return _isCheckedSYO; }
set
{
if (true == value) //if checked
{
IsCheckedUTM = false; //uncheck the UTM check box
_isCheckedSYO = value;
}
else
{
_isCheckedSYO = value;
}
OnPropertyChanged("IsCheckedSYO");
}
}
private bool _isCheckedUTM;
public bool IsCheckedUTM
{
get { return _isCheckedUTM; }
set
{
if (true == value) //if checked
{
IsCheckedSYO = false; //uncheck the SYO checkbox
_isCheckedUTM = value;
}
else
{
_isCheckedUTM = value;
}
OnPropertyChanged("IsCheckedUTM");
}
}

Related

Use DataTrigger in DataGridTemplateColumn.CellStyle

I have a datagrid as follows,
<DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" ItemsSource="{Binding SelectedSet.Rows}" IsSynchronizedWithCurrentItem="True" AutoGenerateColumns="False" CanUserAddRows="False" Style="{StaticResource DataGridStyle2}" HeadersVisibility="Column" SelectedItem="{Binding SelectedItem}" EnableRowVirtualization="False">
<DataGrid.Columns>
<DataGridTemplateColumn Width="30*" Header="{StaticResource RangeColumnHeader}" HeaderStyle="{StaticResource HeaderStyle2}" SortMemberPath="StartValue">
<DataGridTemplateColumn.CellStyle>
<DataTrigger Binding="{Binding SelectedSet.IsDefault}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedSet.IsDefault}" Value="False">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DatGrid>
I Want use " SelectedSet's " IsDefault property to set cell's IsEnabled property.
I tried above code, which is not working.
Classes are defined as follows,
public class UCSetModel : ViewModelBase
{
private Set _SelectedSet;
public Set SelectedSet
{
get
{
return _SelectedSet;
}
set
{
_SelectedSet = value;
RaisePropertyChanged("SelectedSet");
}
}
}
public class Set
{
private ObservableCollection<Markers> _rows;
public ObservableCollection<Markers> Rows
{
get
{
return _rows;
}
set
{
_rows = value;
RaisePropertyChanged("Rows");
}
}
private bool _isDefault;
public bool IsDefault
{
get
{
return _isDefault;
}
set
{
_isDefault = value;
RaisePropertyChanged("IsDefault");
}
}
}
I want to bind to a property of the same 'SelectedSet' that the rows come from.
The markup you have posted won't even compile. This does:
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding IsDefault}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
IsDefault is supposed to be a property of a Row object, i.e. you should remove "Set." from the binding path assuming that a row doesn't have a Set property.
If you want to bind to a property of the same SelectedSet that the rows come from, the binding should be defined like this:
<DataTrigger Binding="{Binding DataContext.SelectedSet.IsDefault, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
This worked for me,
<DataTrigger Binding="{Binding Path=DataContext.SelectedSet.IsDefault,ElementName=SetWindow}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>

Clear combobox in WPF

I have a Combobox that I would like to clear whenever a checkbox is checked.
How would I go about doing that?
My combobox:
<ComboBox
DisplayMemberPath="KommuneNavn"
SelectedValuePath="KommuneNr"
ItemsSource="{Binding KommuneNavne}"
SelectedValue="{Binding kommuneNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="3"
IsEnabled="{Binding IsUdenlandskAdresse, Converter={StaticResource BooleanNotConverter}}"/>
My Checkbox that binds to a boolean property IsUdenlandskAdresse in my viewmodel:
<CheckBox Margin="3" IsChecked="{Binding IsUdenlandskAdresse, Mode=TwoWay}"/>
So when IsUdenlandskadresse is set to true, I would like the combobox to become blank.
If I understood what you are trying to do correctly, you want the ComoBox to be blank (or at least look blank) when it is disabled. The simplest way to do this is to change the Foreground (The color used for Text) to Transparent when the ComboBox is disabled with a style. That way you won't need any code-behind, can reuse that behavior on other ComboBoxes and you don't lose the selection if it gets re-enabled.
<Style TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
Minimalistic Demo:
<ComboBox Height="Auto" IsEnabled="{Binding ElementName=cckEnabled, Path=IsChecked}">
<ComboBox.Style>
<Style TargetType="ComboBox">
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="Transparent"/>
</Trigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
<ComboBoxItem>Entry 1</ComboBoxItem>
<ComboBoxItem>Entry 2</ComboBoxItem>
<ComboBoxItem>Entry 3</ComboBoxItem>
<ComboBoxItem>Entry 4</ComboBoxItem>
<ComboBoxItem>Entry 5</ComboBoxItem>
</ComboBox>
<CheckBox Name="cckEnabled" Content="Enabled"/>
To clear your ComboBox (remove all selectable items from ItemsSource):
public bool IsUdenlandskAdresse
{
get { return _isUdenLandskAdresse; }
set
{
SetProperty(ref _isUdenLandskAdresse, value);
// this will clear your collection if value=true
if(value)
KommuneNave.Clear();
}
}
If you want to unselect the SelectedItem:
public bool IsUdenlandskAdresse
{
get { return _isUdenLandskAdresse; }
set
{
SetProperty(ref _isUdenLandskAdresse, value);
// just set the SelectedItem BindingTarget to null
if(value)
kommunenr = null;
}
}

WPF. Check and disable a checkbox if another checkbox is checked

I have 2 checkboxes.
when one is checked, the other one must be checked and disabled.
The code I have so far is like so
Xaml
<CheckBox x:Name="chkSABranches" Content="Apply to all branches" IsChecked="{Binding IsSABranches,ElementName=pgPageTemplate}" Grid.Row="0" Grid.Column="2"/>
In xaml.cs:
public static DependencyProperty IsSABranchesProperty = DependencyProperty.Register("IsSABranches", typeof(bool), typeof(pgAccounts), new PropertyMetadata(false));
public static DependencyProperty IsSAWarehousesProperty = DependencyProperty.Register("IsSAWarehouses", typeof(bool), typeof(pgAccounts), new PropertyMetadata(false));
public Boolean IsSABranches
{
get
{
return (bool)GetValue(IsSABranchesProperty);
}
set
{
SetValue(IsSABranchesProperty, value);
NotifyPropertyChanged("IsSABranches");
NotifyPropertyChanged("IsSAWarehouses");
}
}
public Boolean IsSAWarehouses
{
get
{
return (bool)GetValue(IsSAWarehousesProperty) || (bool)GetValue(IsSABranchesProperty);
}
set
{
SetValue(IsSAWarehousesProperty, value);
NotifyPropertyChanged("IsSAWarehouses");
}
}
This doesn't seem to work.. Could anyone please provide some guidance. thanks
Here how to do it entirely in Xaml using DataTrigers
<StackPanel>
<CheckBox x:Name="CheckBox1"></CheckBox>
<CheckBox >
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="IsEnabled" Value="True"></Setter>
<Setter Property="IsChecked" Value="False"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsChecked,ElementName=CheckBox1}" Value="True">
<Setter Property="IsChecked" Value="True"/>
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
</StackPanel>

WPF Change ViewModel Property in View

I have a WPF DataGrid with several Templated Columns containing Checkboxes.
If I press a specific Checkbox the source of another checkbox has to be set.
I have a Viewmodel with a Property called Property (yes i know :)), and this Property has the Property "Visible".
If I check the "Mandatory" checkbox I want the "Visible" Value to be set and so the visible Checkbox to be set too, but somehow this is not working.
Heres my code:
<toolkit:DataGridTemplateColumn Header="Mandatory" IsReadOnly="False">
<toolkit:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<CheckBox IsChecked="{Binding Path=Mandatory,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<CheckBox.Style>
<Style TargetType="{x:Type CheckBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=MandatoryDB}" Value="True">
<Setter Property="IsEnabled" Value="False" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=MandatoryDB}" Value="False">
<Setter Property="IsEnabled" Value="True" />
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<ei:ChangePropertyAction TargetObject="{Binding UpdateSourceTrigger=PropertyChanged}" PropertyName="ReadOnly" Value="False" />
<ei:ChangePropertyAction TargetObject="{Binding NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}" PropertyName="Visible" Value="True" />
</i:EventTrigger>
</i:Interaction.Triggers>
</CheckBox>
</StackPanel>
</DataTemplate>
</toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>
Thanks,
Jonny
I think what you're trying to do is to drive your business logic by your View which is a horrible anti-pattern. What you need to is when the value of the "Mandatory" checkbox is changed then your viewmodel needs to set other properties accordingly and alert your view that there was a change (INotifyPropertyChanged).
Your view should not set any viewmodel properties, it should only read them and pass user input, the only other things which your view needs to controll are converters and other view-only items.
Hope this helps
see if this can help you.
lets assume that you want to show yes, no and ans in your Datagrid. for this find the sample code below.
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Coll}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Yes">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Width="50"
Height="50"
IsChecked="{Binding Yes,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="No">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Width="50"
Height="50"
IsChecked="{Binding No,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Ans">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Rectangle Width="100"
Height="50"
RadiusX="25"
RadiusY="25">
<Rectangle.Style>
<Style TargetType="{x:Type Rectangle}">
<Style.Triggers>
<DataTrigger Binding="{Binding Ans}" Value="true">
<Setter Property="Fill" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding Ans}" Value="false">
<Setter Property="Fill" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
code behind
public partial class YesNoTest : Window
{
public YesNoTest()
{
InitializeComponent();
if (Coll == null)
{
Coll = new ObservableCollection<Anss>();
for (int index = 0; index < 10; index++)
{
Coll.Add(new Anss() { Yes = false, No = false, Ans = true });
}
}
this.DataContext = this;
}
private ObservableCollection<Anss> _coll;
public ObservableCollection<Anss> Coll
{
get { return _coll; }
set { _coll = value; }
}
}
public class Anss : INotifyPropertyChanged
{
private bool _Yes;
public bool Yes
{
get
{
return _Yes;
}
set { _Yes = value; OnChanged("Yes"); OnChanged("Ans"); }
}
private bool _No;
public bool No
{
get
{
if (_No == true)
Yes = false;
return _No;
}
set { _No = value; OnChanged("No"); OnChanged("Ans"); }
}
private bool _Ans;
public bool Ans
{
get
{
if (Yes == true)
_Ans = true;
else
_Ans = false;
return _Ans;
}
set { _Ans = value; OnChanged("Ans"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}

Seting control value on the same stackPanel WPF

I have a situation:
DataGrid with TemplateColumn. Template contains Stack panel with CheckBox and TextBox. What I want is when I press CheckBox then TextBox which is on the same StakcPanel set value to 1.
So in simple
CheckBox -> IsChecked==true -> Set TextBox value to 1 (TextBox on the same StackPanel as CheckBox)
I try with RelativeSource but not work.
Thanks For help.
Well you can bind the Content of the TextBox TextForTextBox, and bind the Checked state to Checked. in your viewModel you would : do
private string _text;
private bool _checked;
public string TextForTextBox
{
get { return _text; }
private set { _text = value;}
}
public bool Checked
{
get { return _checked; }
set
{
if (_checked != value)
{
_checked = value;
Text = _checked ? 1 : = 0;
PropertyChanged("Checked");
PropertyChanged("TextForTextBox");
}
}
}
This is assuming that you have a ViewModel that implements the INotfiyPropertyChanged.
EDIT
Code to change this in pure XAML :
<Grid>
<StackPanel>
<CheckBox x:Name="check" />
<TextBox>
<TextBox.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=check, Path=IsChecked}" Value="True">
<Setter Property="TextBox.Text" Value="1" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=check, Path=IsChecked}" Value="False">
<Setter Property="TextBox.Text" Value="0" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
</Grid>

Resources