I have a custom button and I have setup a dependency property on the Foreground, the events are raising fine apart from the first attempt where a null is passed instead of the expected blue solid color brush.
The code changes the color fine on subsequent calls so it is just the initial setting I have a problem with. Any help would be appreciated please.
Here is my code:
Public Shared Shadows ReadOnly ForegroundProperty As DependencyProperty = DependencyProperty.Register("Foreground",
GetType(Brush), GetType(TouchButton), New PropertyMetadata(New SolidColorBrush With {.Color = Colors.Blue},
New PropertyChangedCallback(AddressOf OnForegroundChanged)))
I found the issue, it was in my binding that I was adding in code at run-time as the controls are added dynamically.
Related
I have a DependencyProperty declared like so;
Public ReadOnly ShowHideAddButtonProperty As DependencyProperty = DependencyProperty.Register("ShowHideAddButton", GetType(Boolean), GetType(DataNavigator), New FrameworkPropertyMetadata(True, FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf OnShowHideAddButtonChanged)))
It forms part of a standalone UserControl that I'm building (both because it will be useful to me in the future and because it's a good way to learn). When the control is first added to a project and that project is run it works well, thereafter it throws an ArguementException with a message stating that 'ShowHideAddButton' property was already registered by 'MyControl'.
So as one does I started looking up the possibility of Unregistering the dependency property but it would appear that this is not a good idea. Two questions arise from this.
To add further clarity, in the light of the answer below here is the full code relating to the dependency property. Making the method Shared causes 'ShowHideAddButton' and 'Add' to throw the same error as mentioned in my comment to the answer.
Public Shared ReadOnly ShowHideAddButtonProperty As DependencyProperty = DependencyProperty.Register("ShowHideAddButton", GetType(Boolean), GetType(DataNavigator), New FrameworkPropertyMetadata(True, FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf OnShowHideAddButtonChanged)))
'''////////////////////////////////////////////////////////////////////////////////////////////////////
''' <summary>
''' Gets or sets a value indicating whether the hide add button is shown.
''' </summary>
'''
''' <value> true if show hide add button, false if not. </value>
'''////////////////////////////////////////////////////////////////////////////////////////////////////
<Description("Set the visibility of the Add button on the Navigator Control"), Category("Navigator Buttons Visibility")>
Public Property ShowHideAddButton As Boolean
Get
Return CBool(GetValue(ShowHideAddButtonProperty))
End Get
Set(ByVal value As Boolean)
SetValue(ShowHideAddButtonProperty, value)
End Set
End Property
Private Shared Sub OnShowHideAddButtonChanged()
If ShowHideAddButton = True Then 'this now throws an error as well as Add below
Add.Visibility = Windows.Visibility.Visible 'Add being the button whose visibility is to be changed
Else
Add.Visibility = Windows.Visibility.Collapsed
End If
End Sub
1) why is this error occurring in the first place...presumably it's an error in my original code, but as it compiles without error I'm not sure what it might be?
2) Is it sufficient to simply wrap the offending line in a try Catch block to catch the offending error which is probably doable but doesn't really solve the problem or inform me as to why it's happening in the first place.
Some additional info:
The actual Control looks not unlike this:
It is comprised of a number of separate buttons and textboxes, and in the case of this problem the DependencyProperty ShowHideAddButton is a property of the DataNavigator Control but it needs to trigger the visibility of the Button named AddButton in the control. My problem is trying to figure out how to refer to that button.
Thanks
The new dependency property you declared shall be static (shared in VB.Net): Public Shared ReadOnly ShowHideAddButtonProperty As DependencyProperty = DependencyProperty.Register("ShowHideAddButton", GetType(Boolean), GetType(DataNavigator), New FrameworkPropertyMetadata(True, FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf OnShowHideAddButtonChanged)))
Check this out: DependencyProperty Class
The PropertyChangedCallback needs to be changed to PropertyMetadata in the DependencyProperty.Register.
Then the OnShowHideAddButtonChanged method's paramter signature needs to be changed to (DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs). Finally, in that method, you can reach your control like this var control = dependecyObject as YourControl. Therefore you can reach the instance fields, properties and methods in the static method.
I just discovered than I can do the following:
var button = new Button();
button.SetValue(TextBlock.TextProperty, "text");
var text = (string)button.GetValue(TextBlock.TextProperty); // text is "text"
While the above example is a bit unrealistic, it does show that I can attach a regular dependency property onto another object. It doesn't have to be a an attached property (TextBlock.TextProperty is not registerd with DependencyProperty.RegisterAttached().
This bares the questions why are there attached properties in the first place? The only difference I can see for now ist that I can't attach regular dependency properties in XAML. But that's about it. Are there any other differences?
Update:
To make it more clear, the below code works and looks pretty close to an attached property from the end users perspective:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
"Text",
typeof(string),
typeof(Button),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
...
button.SetValue(AttachedPropertyDeclarer.TextProperty, "text");
var text = (string)button.GetValue(AttachedPropertyDeclarer.TextProperty);
Compare this to the attached property way:
public static class AttachedPropertyDeclarer
{
public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
"Text",
typeof(string),
typeof(AttachedPropertyDeclarer),
new PropertyMetadata(default(string),OnTextChanged));
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// do something when text changed
}
}
The only effective differnce to an attached property here is that I have to declare the owner of type Button whereas in a attached property it would usually be AttachedPropertyDeclarer. But this only needs to be done if I need a changed event handler (i.e. OnTextChanged).
Regarding your example, you have not as you say, attached a regular dependency property onto another object. All your code has achieved is to store a string value in a Dictionary along with a reference to your object. That does not make it an Attached Property - importantly, you cannot access that string value from the Button directly, as there is no Text property on a Button.
What your code does is actually very similar to this:
Dictionary<object, object> values2 = new Dictionary<object, object>();
var button = new Button();
values2.Add(button, "text");
string text = values2[button].ToString();
Now to answer your question:
The main reason to declare an Attached Property is in order to add a property to a type that you didn't declare, thereby extending its functionality.
A great example of this would be to add a SelectedItems property to the ItemsControl or ListBox class. In doing so, we extend the current, or default functionality of the class. Another good example would be declaring an Attached Property that automatically brings added items into view (again in an ItemsControl or ListBox class).
UPDATE >>>
According to your comments, you seem to be refusing to accept the differences that I have outlined... you said:
There is literally no difference from the end users perspective except that I can't use it in XAML.
Firstly, do you not think that this is a huge difference?.. you won't be able to use it for data binding for a start. Furthermore, you keep saying that you can attach a property to a type that you haven't declared using a DependencyProperty, but you are 100% incorrect. You can reference an Attached Property directly in both code and XAML, while you can't reference what you are calling your attached property directly in either XAML or code.
All you are doing is storing a value in a Dictionary and you certainly don't need the overhead of a DependencyProperty to do that. There really is no comparison between doing that and declaring an Attached Property. From the Attached Properties Overview page on MSDN:
You might create an attached property when there is a reason to have a property setting mechanism available for classes other than the defining class.
Note the following part: a property setting mechanism
Adding values into a Dictionary is not a property setting mechanism. So again, you lose the ability to use your pretend Attached Property in Styles, Animations, Triggers, etc.
To clarify this situation for once and for all, you can develop a simple test project. Implement the IList SelectedItems Attached Property for a ListBox that I mentioned (you can find online tutorials for this) and then do the same using your pretend Attached Property (if it is even possible). The difference in the simplicity of development bewteen the two will clearly show you why you should use an Attached Property instead of a regular DependencyProperty.
If you look closely at dependency property identifier, all DP's are registered with class DependencyProperty and we pass the Owner class type and property name at time of registration.
Sample:
public static readonly DependencyProperty IsSpinningProperty =
DependencyProperty.Register(
"IsSpinning", typeof(Boolean), typeof(OwnerClass));
At time of registration it creates some unique hash code combining property name and owner class type to represent each DP uniquely.
So, when you set value for that DP on some object like in your case on Button, code flow is like this:
First it will get the unique value generated at time of registration of property and add the key value pair in private dictionary named _effectiveValues declared in class Dependency Object with Key set to unique hashcode at time of registration and value being the value set by user.
Note - No written documentation for this on MSDN but verified this by peeking into source code using reflector.
So, when you set the value from code behind it will work like I mentioned above because it does not validate before adding value in the dictionary if it belongs to that type or not and fetching value will get you the value from dictionary.
Not sure but might be constraint is there in XAML only where WPF guys enforced the type check. Sadly there is no written documentation for this on MSDN.
Attached properties are discovered, when you want to have control over an existing control, but dont want to extend it. A pretty good example is, there is no way to bind BlackOutDates property in XAML for WPF DatePicker. In that case you can use an Attached Property to attach a custom functionality to map the BlackOutDates. This suits good in MVVM, since attached properties provided way for binding in XAML.
public class BlackOutDatesAdapter
{
public static List<DateTime> GetBlackOutDates(DependencyObject obj)
{
return (List<DateTime>)obj.GetValue(BlackOutDatesProperty);
}
public static void SetBlackOutDates(DependencyObject obj, List<DateTime> value)
{
obj.SetValue(BlackOutDatesProperty, value);
}
// Using a DependencyProperty as the backing store for BlackOutDates. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BlackOutDatesProperty =
DependencyProperty.RegisterAttached("BlackOutDates", typeof(List<DateTime>), typeof(BlackOutDatesAdapter), new PropertyMetadata(null, OnBlackOutDatesChanged));
private static void OnBlackOutDatesChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var control = sender as DatePicker;
var list = (List<DateTime>)e.NewValue;
foreach(var date in list)
{
control.BlackoutDates.Add(new CalendarDateRange(date));
}
}
}
Binding in XAML will look like this,
<DatePicker VerticalAlignment="Center"
Width="200"
local:BlackOutDatesAdapter.BlackOutDates="{Binding BlackOutDates}"
DisplayDate="{Binding DisplayDate}" />
In the callback of property, you can do your own mapping of adding the dates to DatePicker. For more information, please read this post.
I got a binding source not being updated when the targeted DependencyProperty of a custom UserControl changes.
The source is a ViewModel loaded with MEF into the DataContext of my custom UserControl.
My binding looks like this in the root XAML of MyUserControl
// MyUserControl.xaml
<MyUserControlBase x:Class="MyUserControl" MyDependencyProperty="{Binding ViewModelProperty}">
If i use the MyDependencyProperty with a FrameworkPropertyMetadata and use the callback function when the property changes i can do the following which works fine
// MyUserControlBase.cs
private static void MyDependencyProperty_Changed(DependencyObject depObj, DependencyPropertyChangedEventArgs args)
{
var filter = (UserControl )depObj;
var vm = (ViewModel)filter.DataContext;
vm.ViewModelProperty= (VMPropType)args.NewValue;
}
Registration of the DependencyProperty in MyUserControlBase which inherit UserControl.
// MyUserControlBase.cs
public static readonly DependencyProperty MyDependencyPropertyProperty = DependencyProperty.Register("MyDependencyProperty",
typeof(VMPropType),
typeof(MyUserControlBase),
new FrameworkPropertyMetadata(null, MyDependencyProperty_Changed));
But why can't i get the simple two way binding to work when done in the XAML?
Output window show no binding failurs. I can see the ViewModel.ViewModelProperty getter is being called. Just not the setter once MyDependencyProperty changes.
It don't appear to be a problem with the ordering of events. The ViewModel is created long before DependencyProperty is changed for the first time.
I've also looked at Setting up binding to a custom DependencyProperty inside a WPF user control
But his problem seems slightly different since i actualy inherit from my own Base class which holds the DependencyProperty.
Thank you for any help.
Edit: with link to example solution.
Solution zip here
Sorry for the scary looking link, I don't know alot of quick fileshareing sites. If its bad post comment and I will remove it asap, but it seems ok.
Answer updated / irrelevant info deleted
After looking at the code in your sample I saw what the problem is. You have this "selector" control. In the BindDependencies method you set a binding on the MyControlBase.MyDependencyProperty. But at the same time you also bind this property to your control's datacontext (in MyUserControl.xaml). Effectively this means that in the BindDependencies method you are overwriting the binding to your viewmodel thus it is not active after that method - you can see this yourself by breaking into before and after the SetBinding call and calling BindingOperations.GetBindingExpression(control, MyUserControlBase.MyPropertyDependencyProperty) - the bindings are different. This is why your code does not work. I guess you will have to find another way of transferring the value there :)
Some additional info
In WPF a property can be a target of only one binding. This is actually very logical - if a property is bound to two sources - which one should it use? The fact that the binding is marked as OneWayToSource does not really matter in this situation as it still counts as a binding that targets the control's property.
One way you can investigate and see if it works for you is the MultiBinding - it does allow to bind the control's property to several sources by implementing your own IMultiValueConverter. You can find more info on this on MSDN in the link provided.
Do you expose the ViewModelProperty as a regular property..
Usually you do the following....
public static readonly DependencyProperty ViewModelPropertyProperty = DependencyProperty.Register("ViewModelProperty",
typeof(VMPropType),
typeof(MyUserControlBase),
new FrameworkPropertyMetadata(null, ViewModelProperty_Changed));
public VMPropType ViewModelProperty {
get { return (VMPropType)GetValue(ViewModelPropertyProperty); }
set { SetValue(ViewModelPropertyProperty,value); }
}
EDIT -- After comment.
When are you checking that the property has changed? By default WPF bindings only update the values when they lose focus, you change change the UpdateSourceTrigger property of the binding to alter this behaviour.
I was going to create a Style for MapPolygon, but I can't seem to add a Setter for anything other than the properties inherited from Control, which doesn't help very much since the MapPolygon doesn't actually use many of those properties.
I mainly want to be able to style the Fill, Stroke, and StrokeThickness properties. When I try to do this, however, I get the following error: "Object reference not set to an instance of an object". Am I correct in thinking this is because the properties that I am trying to style are not dependency properties (DependencyProperty)?
If my thinking here is indeed correct, would the easiest way to solve this problem be to create a custom MapPolygon control and create dependency properties for Fill, Stroke, and StrokeThickness?
Let me know if I need to clarify something.
Update:
public class StyledMapPolygon : MapPolygon {
public static readonly DependencyProperty FillProperty =
DependencyProperty.Register("Fill", typeof(Brush), typeof(StyledMapPolygon),
new PropertyMetadata(new SolidColorBrush(), new PropertyChangedCallback(OnFillChanged)));
private static void OnFillChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
StyledMapPolygon instance = (StyledMapPolygon) d;
instance.Fill = e.NewValue as Brush;
}
}
.
<Style x:Key="CustomStyle" TargetType="exts:StyledMapPolygon">
<Setter Property="Fill" Value="{StaticResource BuildingFillBrush}" />
</Style>
This is just a simplified version of a style that I would like to use. the StyledMapPolygon is a object I created inherited from MapPolygon. The only difference is that I created a DependencyProperty for "Fill" that just maps to the base property.
The error mentioned above still appears on "Fill" within the Setter, but it now works (displays correctly on the phone). I can live with the error there since it still runs, but I would very much like to have my app be error free.
Yes, a property must be a DependencyProperty in order to be set by a style.
There's nothing wrong with adding your own dependency property that wraps a property on the base class, but I wouldn't recommend trying to use the same property name. Create a differently named property, with property changed handler which relays the value which is set to the underlying property.
Of course if the "error" you mention is Intellisense there's really no reason to care, so long as code compiles and runs.
I struggle with binding FillProperty in a classe derived from Shape.
public static readonly DependencyProperty NumberNodeProperty = DependencyProperty.Register("Number", typeof(int), typeof(MyDerivedShape), new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsParentMeasure));
public MyDerivedShape( DerivedViewModel viewmModel):Shape
{
DataContext = viewmModel;
Binding FillColorBinding = new Binding("FillColor");
SetBinding(FillProperty, FillColorBinding);
Binding numberBinding = new Binding("Number");
SetBinding(NumberNodeProperty, numberBinding);
}
"FillColor" property is declared in a base Viewmodel, from which DerivedViewModel inherits.
"Number" property is declared in DerivedViewModel
FillProperty is the default dependency property in Shape base class.
NumberNodeProperty is a dependency property declared in MyDerivedShape
So , what happens is that when I change "Number" in the DerivedViewModel, change is propagated to the Shape (the Shape draws a number)
But when I change FillColor in the DerivedViewModel, Change is not propagated, and color is not changed . I use FillColor is of type SolidColorBrush.
It seems that the binding does not work... Is it a consequence "Inherits" property set to false for "FillProperty" depedency property ?
I answer myself, because I found the answer :
In fact , in another piece of code in the application , I do something like this :
MyDerivedShape.Fill = Brushed.Red
This has huge consequences,as It destroys the Binding I put in place !
It is connected to "Dependency Property Value Precedence", a topic I was not aware at all.
So, if you bind a ViewModel Property to Dependency Property, you should never then set the Dependency Property directly. If you do so, your binding is lost !