my checkbox doesn't bind the initial value correctly on startup:
<CheckBox IsThreeState="True" IsChecked="{Binding StartWithSettings,Mode=TwoWay}"/>
The checkbox is displayed empty on startup, but should be nulled (the box with the black square in it).
Getter is properly raised with null on startup, what am I missing?
EDIT:
Below you can find my viewmodel, model code and a button to switch all three states of the checkbox. the strange thing happens when switching between null state and false state -> it always shows the false checkbox, whether its null or false, but the underlying data is correct.
do i toggle the checkboxstate directly by clicking the checkbox itself, all three states are displayed correctly.
It is a windows 8.1 store app, maybe the wpf checkbox control is another than the "usual" wpf checkbox and has a bug?
viewmodel snippet:
public bool? StartWithSettings
{
get
{
return _configurationModel.MyAppModel.StartWithSettings;
}
set
{
_configurationModel.MyAppModel.StartWithSettings = value;
RaisePropertyChangedEvent("StartWithSettings");
}
}
model snippet
public class MyAppModel
{
public bool? StartWithSettings { get; set; }
public MyAppModel()
{
this.StartWithSettings = null;
}
}
snippet test code
private void ChangeCheckboxState()
{
if (StartWithSettings == null)
{
StartWithSettings = true;
return;
}
else if (StartWithSettings == true)
{
StartWithSettings = false;
return;
}
else
StartWithSettings = null;
}
The backing property that is bound to the property must be of type bool? in order to support 3 state check box. Make sure that the backing field is set to null.
Also, you don't need to set IsThreeState="True"
EDIT: Since you mentioned Windows 8.1 and I assume this would be WinRT.
Nullable types are not supported in WinRT/Win8 Dev.
A solution would be here
Related
I have a combobox of type List. I have the ItemsSource and the ItemSelected bound through the datacontext. If the selected item has been changed then I show a pop up message confirming the users action. On clicking of 'Ok' the selection gets changed. But on clicking of cancel, the selection should be cancelled and previous item should be retained. Below is the property that is bound to SelectedItem of the combobox.
Public SomeClass Sel
{
get
{
return _sel;
}
set
{
if (_sel != value)
{
var sview = _sel;
if (Compare())
{
_sel = value;
if (Sel != null)
IsDefault = Sel.IsDefault;
OnPropertyChanged(() => Sel);
}
else
{
MessageBoxResult result = MessageBox.Show("Message.", "Owb Message", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
_sel = value;
if (Sel != null)
IsDefault = Sel.IsDefault;
OnPropertyChanged(() => Sel);
}
else
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
_sel = sview;
OnPropertyChanged("Sel");
}), DispatcherPriority.Send, null);
return;
}
}
}
}
}
The combo box is in a pop window. So would Dispatcher object work in that case?
I'm guessing the selected value is retained, but the View doesn't update correctly.
Have a look at this article: http://www.codeproject.com/Articles/407550/The-Perils-of-Canceling-WPF-ComboBox-Selection. Basically, the few workarounds that did exist in .Net 3.5 no longer work in .Net 4.0..
As a general rule, if you've got visual controls leaking into your viewmodel, you're going down a path you don't want to go down.
Create a Behavior that intercepts the OnChanged event of the ComboBox and launches a message box. Here's a tutorial on using behaviours
This keeps all the UI logic in the UI and leaves your viewmodel to manage data and validation.
It works like magic now! I missed out setting the value before calling dispatcher.
_sel = sview
I have a checkbox with its IsChecked property bound to a nullable bool. When my control first loads the value is null and the checkbox appears greyed out. This is what I want.
When the user clicks the checkbox, it moves to the false/Unchecked state.
However, 99% of the time the user is going to want to tick the checkbox - which currently means double clicking the checkbox.
How can I make the value move from null to true when the user first clicks the checkbox?
I had the same problem and ran into this question. This is a late response but I think this is the best solution :)
With the help of IsThreeState and TargetNullValue you can accomplish this
<CheckBox IsThreeState="False" IsChecked="{Binding YOUR_NULLABLE_PROPERTY, TargetNullValue=false}" />
The only caveat is that it will toggle between null and true. There will never be a false value.
You can just modify the setter of the bound property to check whether the previous value is null and if it is, set the value to true. Something like this:
public bool? MyBoolProperty
{
get { return _myBoolProperty; }
set
{
_myBoolProperty = (_myBoolProperty != null || value == null) ? value : true;
RaisePropertyChanged("MyBoolProperty");
}
}
The binding system will re-read the property after it sets it, so the new value will be reflected by the CheckBox.
You can handle the Click event and implement a logic like this:
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox cb = sender as CheckBox;
switch (cb.IsChecked)
{
case null:
cb.IsChecked = false;
break;
case true:
cb.IsChecked = true;
break;
case false:
if (cb.IsThreeState) {
cb.IsChecked = null;
} else {
cb.IsChecked = true;
}
break;
}
e.Handled = true;
}
I have met this problem recently. I look all answers of this question, but none seem fit me. The accepted answer is fail when I set IsChecked equals false in ViewModel. I decompile the checkbox in wpf.
As you can see, when you click a null IsChecked checkbox, IsChecked property will switch to false.
protected internal virtual void OnToggle()
{
bool? flag;
if (this.IsChecked == true)
{
flag = (this.IsThreeState ? null : new bool?(false));
}
else
{
flag = new bool?(this.IsChecked.HasValue);
}
base.SetCurrentValueInternal(ToggleButton.IsCheckedProperty, flag);
}
So you can Create a new class inherit CheckBox and override OnToggle method like this:
protected override void OnToggle()
{
bool? flag;
if (this.IsChecked == true)
{
flag = this.IsThreeState ? null : new bool?(false);
}
else
flag = true;
// what a pity this method is internal
// actually you can call this method by reflection
base.SetCurrentValueInternal(ToggleButton.IsCheckedProperty, flag);
}
The other way is:
protected override void OnToggle()
{
if (this.IsChecked == null)
this.IsChecked = false;
base.OnToggle();
}
The easiest way would be to simply handle the click event and set the control to true if its current state is null, optionally setting a flag for your internal code tracking after first click.
I'm using a MVVM approach with WPF to let the user select one item in a combobox. The model contains a set of possible options, the combobox is bound to this set, the current selection is again bound to a property of my model. This part works fine.
Now I'd like to allow the user to enter an arbitrary text into the combobox. If the text doesn't correspond to an existing item the program should ask him if he wants to add a new item. He should also be allowed to cancel the action and select another item.
How would I do that within the MVVM pattern?
You would check the "already existing" status of the text from your ViewModel's bound property setter. At that point, you need a mechanism to raise an event and decide what to do based on what happens.
An example:
enum Outcome { Add, Cancel }
class BlahEventArgs : EventArgs
{
Outcome Outcome { get; set; }
}
class ViewModel
{
private string name;
public EventHandler<BlahEventArgs> NotExistingNameSet;
public Name
{
get { return this.name; }
set
{
if (/* value is existing */) {
this.name = value;
return;
}
var handler = this.NotExistingNameSet;
if (handler == null) {
// you can't just return here, because the UI
// will desync from the data model.
throw new ArgumentOutOfRangeException("value");
}
var e = new BlahEventArgs { Outcome = Outcome.Add };
handler(this, e);
switch (e.Outcome) {
case Outcome.Add:
// Add the new data
this.name = value;
break;
case Outcome.Cancel:
throw new Exception("Cancelled property set");
}
}
}
}
Your View would add an event handler to NotExistingNameSet to present appropriate UI and set the value of e.Outcome accordingly.
I have a checkbox which i need to bind to a bool in the source and also disable or enable a container.
My source is as follows for the binding but it does not work:
private bool isMapEditOn = false;
OnLoadFunction()
{
//Bindings
Binding mapEditBind = new Binding("IsChecked") { Source = isMapEditOn, Mode = BindingMode.TwoWay };
//Bind to check or uncheck the mapEdit Checkbox
ChckEditMap.SetBinding(ToggleButton.IsCheckedProperty, mapEditBind);
//Bind to disable children (point and area buttons).
EditBtnContainer.SetBinding(IsEnabledProperty, mapEditBind);
}
When I test this by checking and unchecking the checkbox, it does not altar isMapEditOn.
The easiest way to do this is to wrap the isMapEditOn in a property. If you want change notification from the source you'll need to implement INotifyPropertyChanged (not shown here. See this page for info on implementing this interface ):
private bool _isMapEditOn = false;
public bool IsMapEditOn
{
get
{
return _isMapEditOn;
}
set
{
_isMapEditOn = value;
}
}
OnLoadFunction()
{
//Bindings
Binding mapEditBind = new Binding("IsMapEditOn") { Source = this, Mode = BindingMode.TwoWay };
//Bind to check or uncheck the mapEdit Checkbox
ChckEditMap.SetBinding(ToggleButton.IsCheckedProperty, mapEditBind);
//Bind to disable children (point and area buttons).
EditBtnContainer.SetBinding(IsEnabledProperty, mapEditBind);
}
Try using the type bool? instead of bool. The IsChecked property is defined as:
public bool? IsChecked { get; set; }
I have a Silverlight DataGrid of which I need to check if it has Focus. I know there is a method to set Focus and an event for GotFocus but can't see anyhting for checking if it has focus.
Any Ideas ?
AFAIK there is no direct method or property to check if it has focus, but you should be able to use the FocusManager.GetFocusedElement().
If you then define a extension method, you should be able to call MyDataGrid.HasFocus():
public static class ControlExtensions
{
public static bool HasFocus(this Control aControl)
{
return System.Windows.Input.FocusManager.GetFocusedElement() == aControl;
}
}
[edited: I did test it now:]
However there is catch: the call GetFocusedElement() can return the current focused cell within the DataGrid. So in that case the HasFocus will return false.
To be able to check if the DataGrid or one of its cells are focused, we can adapt our extension method like this
public static class ControlExtensions
{
public static bool HasFocus(this Control aControl, bool aCheckChildren)
{
var oFocused = System.Windows.Input.FocusManager.GetFocusedElement() as DependencyObject;
if (!aCheckChildren)
return oFocused == aControl;
while (oFocused != null)
{
if (oFocused == aControl)
return true;
oFocused = System.Windows.Media.VisualTreeHelper.GetParent(oFocused);
}
return false;
}
}
Hope this helps a bit?