I have two radiobuttons.
One (rb1) is binded to a property of my ViewModel. If the property is true rb1 is checked when the application is loaded. If the property is false rb1 is unchecked (that's right).
But in the last case, both radiobuttons are unchecked, and I need the second radiobutton (rb2) is checked when property is false. How could I do this??
The issue you are encountering is that the DataBinding is "lost". Let me quote Matt Thalman:
The click would change the UI state of
the buttons correctly (for example,
clicking Bar would uncheck Foo and
check Bar). But I noticed that if the
underlying value of IsFoo and IsBar
ever changed after that point, the
buttons would not have their IsChecked
state updated. Using the Snoop tool,
I discovered that the IsChecked state
had had its state set manually after
clicking on one of the buttons. Once
a dependency property has been set
manually, it loses its Binding. This
is why the IsChecked state was not
being changed when the properties
being bound to were updated.
A simple solution is to subclass the RadioButton class:
public class DataBoundRadioButton : RadioButton
{
protected override void OnChecked(RoutedEventArgs e)
{
// Do nothing. This will prevent IsChecked from being manually set and overwriting the binding.
}
protected override void OnToggle()
{
// Do nothing. This will prevent IsChecked from being manually set and overwriting the binding.
}
}
See this blog entry for more details.
Related
I am using checkbox in an itemtemplate column in a Silverlight 5 DataGrid.
I am facing a strange problem with it. When I select more than one checkbox and then scroll the grid up and down, the selection shifts to some other checkbox.
I fixed this problem in my code. I did handling within the LoadingRow and UnloadingRow events of the grid.
As soon as a row is loaded, we need to look for the condition on the basis of which we want to keep the check-box checked or unchecked. But as soon as you set the IsChecked property, Checked or UnChecked event of the check-box will get fired.
In this scenario we can unregister the Checked and UnChecked events of the check-box if we have any, set the IsChecked property. After setting this, again register the events.
Below is the code for your help.
Add LoadingRow and UnloadingRow events to your grid.
... LoadingRow="DGUserList_RowLoadUnload" UnloadingRow="DGUserList_RowLoadUnload">
In your code behind file:
private void DGUserList_RowLoadUnload(object sender, DataGridRowEventArgs e)
{
DataGridRow row = e.Row;
CheckBox cbox = (CheckBox)this.dgUserList.Columns[0].GetCellContent(row);
this.UpdateHookedEventsForCheckBox(cbox, false);
cbox.IsChecked = true; // Here put your condition for check/uncheck
this.UpdateHookedEventsForCheckBox(cbox, true);
}
private void UpdateHookedEventsForCheckBox(CheckBox chkBox, bool register)
{
if (register)
{
chkBox.Checked += this.CheckBox_Checked;
chkBox.Unchecked += this.CheckBox_Unchecked;
}
else
{
chkBox.Checked -= this.CheckBox_Checked;
chkBox.Unchecked -= this.CheckBox_Unchecked;
}
}
This way I need not bother about putting some hake code in my Checked and UnChecked events.
This is a known behaviour since Silverlight is re-using its graphical resources in the DataGrid. There's a discussion about it in this Silverlight thread.
It seems one way to fix it is to databind the IsSelected property:
My solution at that time was to add a new property in my data source:
IsSelected, and to bind the checkbox to that value.
You have more additional info in this thread, where Microsoft answers:
This is not a bug. What happens when you scroll around in the
DataGrid is the same checkboxes are being used for new data because
the DataGrid recycles the visuals. When your new data has different
values, the check will change through the Binding and you'll receive
the event. What you can do to get this scenario to work is to listen
to LoadingRow which is raised when a row comes into view. In there,
you can call column.GetCellContents to get the contents of the cell.
This will give you the CheckBox, and you can attach to CheckChanged at
this time. If you do this, you need to do something similar and
listen to UnloadingRow so you can detach the eventhandler when the
checkbox is scrolled out of view.
This is a bit of a wierd problem. (.NET 3.5sp1)
I have a UserControl containing three ToggleButtons, each with IsChecked bound to different dependency properties on the UserControl itself. Two of these default to true, one defaults to false.
On startup of the application, the UserControl itself (and thus its contents) is disabled. When it gets enabled later on, all three buttons appear un-pressed; however the code properties are still in the correct state.
If the buttons are clicked then the properties will toggle properly and the UI (for that button only) will update to reflect the correct state (ie. clicking on a button which appears un-pressed but has a true bound value will show no visible change the first time, but updates the bound value to false). Pressing a "glitched" button for the second time will behave normally (if it toggles on, the button will press in as expected).
If the UserControl is not disabled on startup, then the buttons will appear correctly (according to the state of the properties).
Unfortunately the UserControl is supposed to be disabled on startup, so I can't really start up with it enabled; I'm hoping for an alternate solution. Any ideas?
(I've tried making the properties default to false and then setting them to true in the user control's Load event. Doesn't make any difference.)
The same weird problem happens in .NET 4.0 as well. I noticed that the problem only occurs if you set IsEnabled through code and not if you bind it, so if you can change your code to that instead I believe your problem will be solved.
Otherwise, I believe a workaround is necessary and here is one way to do it. Reset the DataContext for the UserControl the first time IsEnabled is set to True.
public UserControl1()
{
InitializeComponent();
DependencyPropertyDescriptor descriptor =
DependencyPropertyDescriptor.FromProperty(UserControl1.IsEnabledProperty,
typeof(UserControl1));
EventHandler isEnabledChanged = null;
isEnabledChanged = new EventHandler(delegate
{
if (IsEnabled == true)
{
descriptor.RemoveValueChanged(this, isEnabledChanged);
var dataContext = this.DataContext;
this.DataContext = null;
this.DataContext = dataContext;
}
});
descriptor.AddValueChanged(this, isEnabledChanged);
}
I came across a 'somewhat' similar situation and the following SO reply proved to be more appropriate in my case. It save me a lot of troubles and so, just in case anyone looking at this solution hasn't noticed it, I think a reference to it should be useful here.
WPF ToggleButton incorrect render behavior
Cheers
Mansoor
I have a DataTemplate. It has two visual states - Expanded, Collapsed.
I added 2 GoToStateAction-s. The first one goes to the Expanded state when a data context property becomes True, and the second one goes to the Collapsed state when that same property becomes False.
A Checkbox is part of the template and bound to that property. So when the Checkbox gets checked/unchecked the necessary transition happens.
But none of the actions are applied on startup. The Checkbox is Checked but the Expanded visual state is not applied.
Is it possible using the Visual State Manager to have all items loaded with states applied according to the property values?
It sounds like you need to override OnApplyTemplate and call VisualStateManager.GoToState(). What happened was your control was loaded, data binding occurred, and then the template was applied. Thus the template is in the base state because nothing told it to perform a state transition. You might be able to do it all from XAML by hooking into the loaded event, but you might find it to be flaky.
You just need to add another GoToStateAction that sets the desired states upon the OnLoad event firing.
update
I haven't tested this, but I think you could use a custom TargetedTriggerAction that derives from GoToStateAction:
public class GoToStateIfCheckedAction : GoToStateAction
{
protected override void Invoke(object parameter)
{
var toggleButton = Target as ToggleButton;
if (toggleButton != null && (!toggleButton.IsChecked.HasValue || !toggleButton.IsChecked.Value))
{
// if the Target is a ToggleButton, and it is in an indeterminate or unchecked state, don't invoke
return;
}
// if the Target is not a ToggleButton, or if the ToggleButton is checked, go ahead and invoke the action
base.Invoke(parameter);
}
}
When attached to a ToggleButton, such as CheckBox, this action will only be executed when IsChecked == true.
You could trigger this from the OnLoad event and it will go to the state if the box is checked, or do nothing if unchecked.
I have a similar problem that a binded visual state is not applied on view load:
<core:PropertyChangedTrigger Binding="{Binding State}">
<core:GoToStateAction StateName="{Binding State}" />
</core:PropertyChangedTrigger>
As I am using MVVM architecture I cannot override the view's OnApplyTemplate as the view cannot 'see' the ViewModel.
Finally, I found that EventTrigger helps and I want to share it with you:
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger>
<core:GoToStateAction StateName="{Binding State}" />
</interactivity:EventTrigger>
<core:PropertyChangedTrigger Binding="{Binding State}">
<core:GoToStateAction StateName="{Binding State}" />
</core:PropertyChangedTrigger>
</interactivity:Interaction.Triggers>
where xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
In my WPF application I have a CheckBox whose IsChecked value is bound to a property in my viewmodel. Notice that I have commented out the actual line which sets the value in my viewmodel. It's the standard pattern:
View.xaml
<CheckBox IsChecked="{Binding Path=SomeProperty}" />
ViewModel.cs
public bool SomeProperty
{
get { return this.mSomeProperty; }
set
{
if (value != this.mSomeProperty)
{
//this.mSomeProperty = value;
NotifyPropertyChanged(new PropertyChangedEventArgs("SomeProperty"));
}
}
}
When I click the CheckBox I expect nothing to happen, since the value of this.mSomeProperty does not get set. However the observed behavior is that the CheckBox is being checked and unchecked regardless of the value of this.mSomeProperty.
What is going on? Why isn't my binding forcing the CheckBox to show what the underlying data model is set to?
Because WPF does not automatically reload from the binding source after updating the source. This is probably partly for performance reasons, but mostly to handle binding failures. For example, consider a TextBox bound to an integer property. Suppose the user types 123A. WPF wants to continue showing what the user typed so that they can correct it, rather than suddenly resetting the TextBox contents to the old value of the property.
So when you click the CheckBox, WPF assumes that it should continue to display the control state, not to re-check the bound property.
The only way I've found around this, which is not very elegant, is to raise PropertyChanged after WPF has returned from calling the property setter. This can be done using Dispatcher.BeginInvoke:
set
{
// ...actual real setter logic...
Action notify = () => NotifyPropertyChanged(...);
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, notify);
}
This could be made a bit less horrible by consolidating it into the NotifyPropertyChanged implementation so that you wouldn't have to pollute individual properties with this implementation concern. You might also be able to use NotifyOnSourceUpdated and the SourceUpdated attached event, but I haven't explored this possibility.
I have a form
on that form I have a radiobutton
When the radiobutton changes I want to do some stuff.
However I only want to do this if the FormLoad event has fired
and dor some wierd reason the radiobutton changed event is getting hit prior to the FormLoad
Call stack is not much use, but its coming from the settings.designer.cs file
Anyway short of setting a flag on the onLoadEvent is there some intrinsic property of the form like IsLoaded which i can use to make sure that my radio button code only executes once the form is loaded
You can check the IsHandleCreated property of your form to determine if the OnLoad has been called. This is the closest thing to a IsLoaded property.
Here is a different way...
RadioButton has an AutoCheck property which by default is set to true, you want to set this to false in the designer.
And then override it manually in the Form Load event to true like so:
radioButton1.AutoCheck = true;
You can set the CheckedChanged property setup in the designer still and it should work (won't trigger change event).
In the event handler, check to see if the radio button and/or form is visible. If the radio button's state is being changed before the form has been loaded, then RadioButton.Visible should be false.
You may also like to subscribe to the FormShown event. E.g:
private void Form1_Shown(object sender, EventArgs e)
{
radioButton1.Checked = true;
}
You can check that the control has focus or not. If not, then ignore. Eg:
if(radioButton1.ContainsFocus)
{
//Event handling code here...
}