Custom WPF binding not being updated on listbox selection - c#

I'm puzzled by this probably trivial matter. I have my custom property on a descendant of DevExpresses class LayoutGroup (shouldn't make any difference IMO):
public class ExpandableLayoutGroup : LayoutGroup
{
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register("IsExpanded", typeof(Boolean), typeof(ExpandableLayoutGroup));
public Boolean IsExpanded
{
get { return (Boolean) GetValue(IsExpandedProperty); }
set
{
expandCheckBox.IsChecked = value;
SetValue(IsExpandedProperty, value);
}
}
}
Then I have XAML binding to a listbox (containing 2 items at this time) called listStates.
<ExpandableLayoutGroup x:Name="groupTool" IsExpanded="{Binding SelectedValue.IsTool, ElementName=listStates}" DataContext="{Binding Tool}" Header="Tool" View="GroupBox" />
The object list binding to listStates contains both properties (simplified):
public class State
{
public Boolean IsItemTool { get; private set; }
public Tool Tool { get; private set; }
}
Am I missing something obvious? Because I would expect that when I change listbox selection (single) it would also update IsExpanded property on a group. I have more subproperties of Tool binded (as apparent by DataContext="{Binding Tool}") and those update well. So the DataContext is changing correctly on listbox selection. Except this one property IsExpanded (that should expand/collapse layoutgroup).
What am I doing wrong, and how to make it so, that when listbox changes, IsExpanded binding is polled to get value from IsTool, and will set it (depending on selection).

Getters and setters of dependency properties must contain only GetValue and SetValue calls, because there're two ways to get and set their values: using getters and setters and using DependencyProperty or DependencyPropertyKey. This is why code in your setter is not executed (bindings don't use them for dependency properties). If you want some code to be executed when the value is changed, specify it as a PropertyChangedCallback callback in PropertyMetadata.
See PropertyChangedCallback Delegate on MSDN.

The setter for a dependency property must only set the value for it's underlying type. The .NET internals reserve the right to call SetValue() directly (and in my experience WPF usually does, while Silverlight uses the setter that you've defined).
Refer to the "Implications for Custom Dependency Properties" section of XAML Loading and Dependency Properties for details

Related

Is every Property in WPF Dependency Property?

I read this post and this one about depency properties and I am confused, are all properties in XAML dependency properties ? and what about normal properties we define in C# ? I mean like this : Public int num {get; set;} .
Because the normal properties in C# have some features that they mentioned as a option for dependency property for example I can bind their values to a textbox value.
And if you can make a simple example I will be grateful.
I feel that the other posts answer what a Dependency Property is fairly well so I will address your question showing how to make a Dependency Property, hopefully that will help.
Are all properties in XAML dependency properties?
No, Dependency properties must be specified as such. See below...
public class MyDataGridControl : DataGrid
{
public string SomeName
{
get { return (string)GetValue(SomeNameProperty); }
set { SetValue(SomeNameProperty, value); }
}
public static readonly DependencyProperty SomeNameProperty =
DependencyProperty.Register(
nameof(SomeName), typeof(string), typeof(MyDataGridControl),
new PropertyMetadata(null));
}
In the example above, I have created a class that inherits from DataGrid to make my own DataGrid control. I have created the "normal property" SomeName. I then register SomeName as a Dependency Property. Notice that while SomeName is a "normal property", the getter and setter are referencing the SomeNameProperty Dependency Property.

ObservableCollection is Null when I try to add TextBlocks through XAML to a custom control

In my WPF Project, i am trying to create an ObservalbeCollection dependency property inside a custom control. I am not sure if i am doing it the right way but i am using the below code :
public static readonly DependencyProperty MenuOptionsDependency = DependencyProperty.Register("MenuOptions", typeof(ObservableCollection<TextBlock>), typeof(DropDownButton));
public ObservableCollection<TextBlock> MenuOptions
{
get
{
return (ObservableCollection<TextBlock>)GetValue(MenuOptionsDependency);
}
set
{
SetValue(MenuOptionsDependency, value);
}
}
The problem arises when i try to add TextBlocks through XAML to this control as follows :
<local:CustomControl1 x:Name="cmm">
<local:CustomControl1.MenuOptions>
<TextBlock/>
</local:CustomControl1.MenuOptions>
</local:CustomControl1>
This throws a design time error saying :
Collection 'CustomControl1'.'MenuOptions' is null
After going through the accepted answer on this SO post, i understand ObservableCollection, being a reference type, will be null as it will be default value. I read through the answer but i am still unclear/unsure on how to implement the solution in my situation.
I need to be able to add objects to the collection through XAML(and also through C#). I would really appreciate if someone points out where i am missing/what i am doing wrong.
You must never set the default value of a collection type dependency property to something else than null. When you assign a non-null default value by (static) property metadata, all instances of your control will use the same collection object.
Instead, set a default value in the control's constructor by SetCurrentValue:
public DropDownButton()
{
SetCurrentValue(MenuOptionsDependency, new ObservableCollection<TextBlock>());
}
Besides that, there is a strict naming convention, according to which the dependency property identifier field must be named as the property with a Property suffix. So your MenuOptionsDependency should actually be named MenuOptionsProperty.
It's also unclear whether the property type really needs to be ObservableCollection. You don't seem to register a CollectionChanged event handler anywhere, which indicates that your control is not supposed to react on such changes.
Consider a property declaration like this:
public DropDownButton()
{
SetCurrentValue(MenuOptionsProperty, new List<TextBlock>());
}
public static readonly DependencyProperty MenuOptionsProperty =
DependencyProperty.Register(
nameof(MenuOptions), typeof(IEnumerable<TextBlock>), typeof(DropDownButton));
public IEnumerable<TextBlock> MenuOptions
{
get { return (IEnumerable<TextBlock>)GetValue(MenuOptionsProperty); }
set { SetValue(MenuOptionsProperty, value); }
}

"Binding" wpf Combox selectedValue to an integer?

I just started a new wpf project in hopes that I could learn a new technique as opposed to using winForms all the time.
I seem to be having way too much difficulty binding the selected value of a comboBox to an integer variable in my "MainWindow" class.
I have been looking at a host of "simple" examples from sites like codeproject, but they all seem way too complicated to just return the selected value of a comboBox. I am used to setting the "SelectedValueChanged" property and just setting a variable, which takes just a few clicks, like so:
public int value;
public void comboBox_SelectedValueChanged()
{
value = comboBox.SelectedValue();
}
Is there a similarly sweet, simple, and short way to properly "bind" the selected comboBox item to an integer?
I am trying to understand how to use INotifyPropertyChanged but I keep getting errors when I try to use it. This is what I have so far, but to be honest, I'm not sure where I am going with it:
// Combo Box Value
public class ComboValue
{
#region Members
int valueToReturn;
#endregion
# region Properties
public int numWeeks
{
get { return valueToReturn; }
}
#endregion
}
// Veiw Model Class
public class ComboValueViewModel:INotifyPropertyChanged
{
#region Construction
public ComboValueViewModel()
{
}
#endregion
}
and I've never used "#region" before, I have no clue what that is.
Could someone fill me in if I'm headed down the right path here?
You don't mention how much you know of MVVM but here goes. Your view will have an associated ViewModel class. In here you'll expose a property containing the items to bind to the combobox, e.g.:
public List<ComboValue> ComboItems { get; set; }
If you populate this property in the VM's constructor, then a List<> is probably sufficient; however you'll often see an ObservableCollection<> used for this kind of thing - this comes into its own if you need to add or remove items within your VM code - your view will react to such changes and update the list accordingly. This won't happen with a List<>.
As for INotifyPropertyChanged, I haven't implemented this pattern in the above code snippet. Again, it's not strictly necessary if you populate the collection in the VM constructor and won't be re-assigning that property again. However it's good practice to use the INPC pattern on your VM properties. Without it, if you were to reassign that property elsewhere in your code, e.g.:-
ComboItems = aNewListOfItems;
then the view wouldn't be made aware of the property change, and the ComboBox wouldn't update. If you need this to happen then implement the INPC pattern on the property, e.g.:-
public List<ComboValue> ComboItems // or ObservableCollection<ComboValue>
{
get
{
return _comboItems;
}
set
{
if (_comboItems != value)
{
_comboItems = value;
OnPropertyChanged("ComboItems");
}
}
}
As you are working with a ComboBox, your VM should also expose a property that you bind to the control's SelectedItem property. This property should implement INPC, e.g.:-
public ComboValue SelectedItem
{
get
{
return _selectedItem;
}
set
{
if (_selectedItem != value)
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
}
As you select items in the combo, the VM's SelectedItem property will change to reflect the current selection.
Finally, your XAML should end up looking something like this:-
<ComboBox ItemsSource="{Binding ComboItems}" SelectedItem="{Binding SelectedItem}" />
Hope this gives you a little "primer" into WPF binding! (Code snippets taken from memory so may not be 100% correct!).
Edit
Your ComboValue class exposes a numWeeks property. As it stands, you'll probably find that your ComboBox displays a list of ComboValue type names. To get the number to appear, the easiest thing is just to override .ToString() in your class and return the value of numWeeks. For more advanced formatting of items in controls such as this, you'll typically specify an ItemTemplate (again, plenty of examples can be found via Google!).

Updating a Custom Control's binded Property on its property change

App.cs
class customRadioButton:RadioButton
{
private Brush enableColor;
private Brush disableColor;
public EnableColor()
{
get{ /*get value */}
set{ /* set value */}
}
}
Main.xaml
<local:customRadioButton EnableColor={Binding ElementName=disableButton, Path=EnableColor} />
<local:customRadioButton x:Name="disableButton" EnableColor="Red", Path=EnableColor} />
Now I am changing the value of EnableColor dynamically. Problem I am having is that the value assigned but is not getting reflected in main.window
I don't want to use dependency property
Is there any other method to Tell the Binded Elements that its property has changed.
Note:I have tried UpdateTrigger its also not working
In order to get Binding work, you will need to create a DependencyProperty.
public Brush EnableColor
{
get { return (Brush)this.GetValue(EnableColorProperty); }
set { this.SetValue(EnableColorProperty, value); }
}
public static readonly DependencyProperty EnableColorProperty = DependencyProperty.Register(
"EnableColor", typeof(Brush), typeof(customRadioButton), new PropertyMetadata(default(Brush));
Read MSDN for details.
Curious what your aversion is to using a dependencyproperty? I answering this on my phone so cant mock one up for you but it would be extremely simple to do.
Just do a Google for "WPF custom control dependency property example" and do exactly what they do just customized for your needs.
The dependency peppery will give you the change notification that you're looking for.
The UpdateTrigger would only apply if you were binding to something that's part of your XAML data context. I mean I guess toy could fudge around to get that to work but DependencyProperty is absolutely the way too go

When do I need to use automatic poperties and when properties with propertychanged event?

I am using wpf and its C sharp!
I have this in my Animal.cs clas
private string _animalName;
public string AnimalName
{
get { return _animalName; }
set
{
if(_animalName!= value)
{
_animalName= value;
this.NotifyPropertyChanged("AnimalName");
}
}
}
I could also write:
public string AnimalName {get;set;}
There is no difference in binding and validation. Everythings works as before when I exchange the code.
Is this due to the fact that I only create new animals but I do not allow to update the animals name in my application ?
So I need to call the propertyChanged("AnimalName"); only when I want to change its property value?
I am a c# beginner ;)
If your object has an updateable property (setter) that will be bound to a control then you need to ensure to let the bound control know of any changes to that property via INotifyPropertyChanged. However, if you have a readonly property and/or a property that's not going to be used in a data-binding scenario then you don't care about implementing or calling NotifyPropertyChanged method from within that property's setter in which case you can use automatic properties.

Categories

Resources