Dependency Property does not get or set Value - c#

I have created a user control in WPF, and in the code behind I have created some dependency properties.
I added several WPF controls to my user control, one of the is a progress bar, so What I tried to do is to expose the Value progressBar property as below:
public static readonly DependencyProperty valueProperty = DependencyProperty.Register(
"Value",
typeof(Double),
typeof(MyUserControl),
new FrameworkPropertyMetadata(
ValuePropertyCallback));
private static void ValuePropertyCallback(DependencyObject controlInstance, DependencyPropertyChangedEventArgs args)
{
MyUserControl myUserControlInstance = (ProgressControl)controlInstance;
myUserControlInstance.progressBar.Value = (Double)args.NewValue;
}
public Double Value
{
get { return (Double)GetValue(valueProperty); }
set { SetValue(valueProperty, value); }
}
And in XAML I have written this:
<MyUserControl Name="myControl" Value="{Binding ProgressBarValue}" >
But It seems not to be working, neither setting nor getting the value.
I have a couple hours reviewing this but I cant realize what I am doing wrong.
Hope you can help me, Thank you in advance.
(Note: DataContext are defined previously and it is correct since this is the only binding that does not work)

valueProperty <----> "Value" does not match... (v/V) :=)

Have you tried Mode=TwoWay:
<MyUserControl Name="myControl" Value="{Binding ProgressBarValue, Mode=TwoWay}" >
I have also used PropertyMetadata instead of FrameworkPropertyMetadata

Try changing the name of your dependency property to be PascalCased:
ValueProperty
You might also want to look at BindsTwoWayByDefault to make sure changes to your DP are written to the source object.

Turns out that my problem was that I didnt implement the INotifyPropertyChanged interface, so, the changes I did were not showed. But since I am new at WPF using MVVM I didnt know that.
But you just need to create an ObservableObject, then your viewModel class has to inherit from it.
Here is an example to create the ObservableObject class and how to inherit from it.

Related

Custom control binding setter not firing

I have a custom control with following code:
public partial class TableSelectorControl : UserControl
{
private Brush _cellHoverBrush = new SolidColorBrush(Colors.CadetBlue) { Opacity = 0.3 };
public static readonly DependencyProperty ActiveSelectionProperty =
DependencyProperty.Register("ActiveSelection", typeof(TableSelectorSelection),
typeof(TableSelectorControl));
public TableSelectorSelection ActiveSelection
{
get => (TableSelectorSelection)GetValue(ActiveSelectionProperty);
set
{
SetValue(ActiveSelectionProperty, value);
_cellHoverBrush = value.HoverBrush;
}
}
}
As you can see, I'm trying to set _cellHoverBrush on each ActiveSelectionProperty update, which is done from ViewModel. Binding works well and the ActiveSelectionProperty seemes to change, but the setter is not firing. I surely can use a FrameworkProperyMetadata, but I don't want _cellHoverBrush to become static, the idea is to change it with respect to selected ActiveSelection. How can I achieve this?
I can provide more info, if needed.
There are two types of properties in WPF: .NET Framework properties and dependency properties (which are specific for WPF). Each dependency property has associated a .Net Framework property, but this property is only a wrapper over WPF dependencies properties. This is done to standardize the way we work with properties in WPF. When a dependency property is used in bindings from .xaml files, the WPF framework will not use the .Net wrapper property to get or set the value. This is why, it's not indicated to use other code than GetValue and SetValue in your .NET wrapper property.
For what you need, you should use PropertyChangedCallback, like in the example below:
public partial class TableSelectorControl : UserControl
{
private Brush _cellHoverBrush = new SolidColorBrush(Colors.CadetBlue) { Opacity = 0.3 };
public static readonly DependencyProperty ActiveSelectionProperty =
DependencyProperty.Register("ActiveSelection", typeof(TableSelectorSelection),
typeof(TableSelectorControl), new PropertyMetadata(new PropertyChangedCallback(OnActiveSelectionChanged)));
public TableSelectorSelection ActiveSelection
{
get => (TableSelectorSelection)GetValue(ActiveSelectionProperty);
set => SetValue(ActiveSelectionProperty, value);
}
private static void OnActiveSelectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var tableSelCtrl = d as TableSelectorControl;
if (tableSelCtrl != null)
{
tableSelCtrl._cellHoverBrush = (e.NewValue as TableSelectorSelection)?.HoverBrush;
}
}
}
Using the PropertyChangedCallback of FrameworkPropertyMetadata doesn't necessarily mean you need to make your field static. Your handler method will get a reference to the instance that is invoking it which you can then modify - you will need to cast it to your type first though.
The PropertyChanged walkthrough on this page shows one way you might do it.
https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-callbacks-and-validation

Binding ProgressBar in CustomControl seems not to work

I got a customcontrol that contains a ProgressBar among other elements.
<ProgressBar Value="{TemplateBinding CurrentProgress}"
MinValue="{TemplateBinding MinValue}"
MaxValue="{TemplateBinding MaxValue}"/>
<Label Content="{TemplateBinding CurrentProgress}"/>
In my .cs File, i defined all of these properties like this:
#region MaxProgress
public int MaxProgress
{
get { return (int)GetValue(MaxProgressProperty); }
set { SetValue(MaxProgressProperty, value); }
}
public static readonly DependencyProperty MaxProgressProperty =
DependencyProperty.Register("MaxProgress", typeof(int), typeof(GameFlowControl), new FrameworkPropertyMetadata(1000, FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
#region CurrentProgress
public int CurrentProgress
{
get { return (int)GetValue(CurrentProgressProperty); }
set { SetValue(CurrentProgressProperty, value); }
}
public static readonly DependencyProperty CurrentProgressProperty =
DependencyProperty.Register("CurrentProgress", typeof(int), typeof(GameFlowControl), new FrameworkPropertyMetadata(50, FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
#region MinProgress
public int MinProgress
{
get { return (int)GetValue(MinProgressProperty); }
set { SetValue(MinProgressProperty, value); }
}
public static readonly DependencyProperty MinProgressProperty =
DependencyProperty.Register("MinProgress", typeof(int), typeof(GameFlowControl), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsRender));
#endregion
Binding those values to the label as shown above works fine, but apparently those bindings do not work for my ProgressBar. What i have tried so far:
Changing orders of Value, MinValue and MaxValue.
Added a typo to the TemplateBinding (like CurrentProgressXYZ), which gives me a compile error (so the properties are recognized)
Added default values to the Properties (see 0, 50, 1000).
Removed the binding and setting values directly: Value = 50, MinValue = 0, MaxValue=100 which shows the ProgressBar to show up as half filled.
Added Breakpoints to the getters of those properties, they were not triggered (which confuses me a lot!)
Any hints what could cause this?
Answer based on your question
The binding method you should use in this situation is Value="{Binding CurrentProgress, RelativeSource={RelativeSource AncestorType={x:Type GameFlowControl}}}". This traverses the visual tree upwards finding the first GameFlowControl control, then binding to the path from this relative position.
An Alternative
As an alternative if you are not utilizing the DataContext in the UserControl for any other purpose you could use the shorter method of binding.
Firstly you would need to assign the DataContext to the derived UserControl reference using something like this:-
public GasFlowControl()
{
InitializeComponent();
DataContext = this; //Set the DataContext to point to the control itself
}
Then your binding can be simplified down to this:-
<ProgressBar Value="{Binding CurrentProgress}"
MinValue="{Binding MinValue}"
MaxValue="{Binding MaxValue}"/>
<Label Content="{Binding CurrentProgress}"/>
To answer your confusion
Added Breakpoints to the getters of those properties, they were not triggered (which confuses me a lot!)
The reason you did not get any breakpoints triggering for property Getters and Setters is that the WPF framework does not use them. It internally calls GetValue(CurrentProgressProperty); and SetValue(CurrentProgressProperty, value); directly. They are there only for your convenience to include in your code and have the convenience of type casting and thus type checking when compiling.
If your code does not use them then they will never be called at all.

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

DependencyPropert not set from XAML with DynamicResource as parameter

I'm trying to develop a custom tri-state button user control and so far I've been using CTF to set properties.
But I would like to change this to be using the WPF property system with PropertiesDependencies.
Unfortunately I don't manage to make it work, when I set the property from my xaml (father) using a DynamicResource, the value is not set.
<common:StateImageButton x:Name="story_buttonRecord" BackTest="{DynamicResource backTest}" />
Here is the code I have in my button controller :
public ImageSource BackTest
{
get { return (ImageSource)this.GetValue(BackProp); }
set { this.SetValue(WidthProp,value); }
}
public static readonly DependencyProperty BackProp =
DependencyProperty.Register(
"BackTest",
typeof(ImageSource),
typeof(StateImageButton),
new FrameworkPropertyMetadata());
I don't even use the property in my button xaml yet, but it apparently doesn't even enter in the Setter. I've been searching a lot online without success. So maybe I'm missing something .
Thanks in advance for your help,
Boris
Also, WPF doesn't use the setter provided to set a property, it does it directly.
The way to debug when WPF sets a property is to add a callback for when the property is set, like so.
public static readonly DependencyProperty BackProp =
DependencyProperty.Register(
"BackTest",
typeof(ImageSource),
typeof(StateImageButton),
new FrameworkPropertyMetadata(OnBackChanged));
private static void OnBackChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
var sender = (StateImageButton)d; // Put a breakpoint here
}

C# WPF custom control not responding to XAML properties at design-time?

I've created a UserControl which is essentially a button. It's got an Image and a Label on it and I've created two properties to set the Image's source and the Label's text like so:
public ImageSource Icon
{
get { return (ImageSource)this.GetValue(IconProperty); }
set { this.SetValue(IconProperty, value); icon.Source = value; }
}
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(ImageSource), typeof(NavigationButton));
public string Text
{
get { return (string)this.GetValue(TextProperty); }
set { this.SetValue(TextProperty, value); label.Content = value; }
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(NavigationButton));
However, when I've added the control to my Page, the controls wont respond to any properties I set in XAML, e.g. <controls:MusicButton Icon="/SuCo;component/Resources/settings.png/> does nothing.
What am I doing wrong?
CLR properties that wrap dependency properties should never have any logic other than calling GetValue and SetValue. That is because they may not even be called. For example, the XAML compiler will optimize by calling GetValue/SetValue directly rather than using your CLR property.
If you need to execute some logic when a dependency property is changed, use metadata:
public ImageSource Icon
{
get { return (ImageSource)this.GetValue(IconProperty); }
set { this.SetValue(IconProperty, value); }
}
public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(ImageSource), typeof(NavigationButton), new FrameworkPropertyMetadata(OnIconChanged));
private static void OnIconChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
{
//do whatever you want here - the first parameter is your DependencyObject
}
EDIT
In my first answer, I assumed your control's XAML (be it from a template or directly in a UserControl) is correctly hooked up to the properties. You haven't showed us that XAML, so it was perhaps an incorrect assumption. I'd expect to see something like:
<StackPanel>
<Image Source="{Binding Icon}"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
And - importantly - your DataContext must be set to the control itself. You can do this in various different ways, but here is a very simple example of setting it from the code behind:
public YourControl()
{
InitializeComponent();
//bindings without an explicit source will look at their DataContext, which is this control
DataContext = this;
}
Have you tried setting the text property as well? The source of an image may just be wrong. Text is much more straight forward.
Also, in your example, you missed a quotation mark. So if it's copied from your real code, you may want to check that.
Barring those minor admittedly unlikely causes for your problem, I'd suggest setting the properties in code to check whether that has any effect. If it has, then you should really check your XAML.
Since you haven't posted the rest of your code, I can't really tell if you have problems somewhere else that might affect the control.
And yes, I know I'm not very helpful, but I've been working with WPF for only a little while. Hope it helps anyway.

Categories

Resources