public string City
{
get { return GetValue(CityProperty).ToString(); }
set { SetValue(CityProperty, value); }
}
public static readonly DependencyProperty CityProperty =
DependencyProperty.Register("City", typeof(string), typeof(Object1));
If I make a mistake, here:
...Register("City"), typeof...
like for instance I forget to capitalize "city", or i.e "vity"
Is the dependency property subsystem just totally blown away? The string City property is still there right? I can set it in various ways and the static CityProperty thingamabob is still there, I can do something somewhere with that. I can do like Object1.CityProperty and such, But where is exactly is the breakdown/link? If that "City" literal in the register method and the City property don't match, then the string City property is just not a dependency property?
I guess also I mean, if the string City property is calling GetValue, then what is the difference? Will the subsystem 'find' everything and be able to support using string City property as the: a) target of binding b) animation c) styling
EDIT
In a somewhat disturbing development, the following 'works' . When you set the City property from XAML, it apparently stores it somewhere. What part(s) of a) using as a target for binding, b) styling, c) animation don't is a mystery to me.
namespace util
{
public class foo : FrameworkElement
{
public String City
{
get { return (String)GetValue(CityProperty); }
set { SetValue(CityProperty, value); }
}
// Using a DependencyProperty as the backing store for City. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CityProperty =
DependencyProperty.Register("city", typeof(String), typeof(foo), null);
}
}
namespace screwing_up_dependencies
{
public partial class MainPage : PhoneApplicationPage
{
public MainPage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var aFoo = this.FindName("bar");
if (aFoo is util.foo)
{
util.foo theFoo = (util.foo)aFoo;
((Button)sender).Content = theFoo.City;
}
}
}
}
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"
xmlns:util="clr-namespace:util"
>
<util:foo x:Name="bar" City="blah"></util:foo>
<Button Content="Button" Grid.Row="1" Click="Button_Click" Height="105"/>
</Grid>
EDIT 2
Furthermore, you can also do this. It apparently doesn't make any difference what the "Name" parameter to the register command is. And also it doesn't seem to matter what the OwnerType parameter is either.
<util:foo x:Name="bar2" City="{Binding ElementName=ContentPanel, Path=Width}"></util:foo>
public static readonly DependencyProperty CityProperty =
DependencyProperty.Register(Guid.NewGuid().ToString(), typeof(String), typeof(object), null);
var aFoo = this.FindName("bar2");
if (aFoo is util.foo)
{
util.foo theFoo = (util.foo)aFoo;
((Button)sender).Content = theFoo.City;
}
Will the subsystem 'find' everything and be able to support using string City property as the: a) target of binding b) animation c) styling
No.
Reflection is used by other systems to divine information about the instance. When the property city does not exist no operations can occur. For in C# one can have overloaded property names (i.e. City and city) and those are two separate entities in the eyes of the compiler and the runtime process reflecting off of an unknown instance.
is there any Lint tool available that will detect this kind of thing automagically
To avoid errors when creating dependency properties I use Jeff Wilcox's (Helpful Silverlight Snippets - Jeff Wilcox). Via using snippets which are geared towards the 6 types of dependency properties, it avoids the errors. Note that even though it is Silverlight, I use them without change in WPF.
Related
iv'e got a CompositeCommand exposed globally in my startup project
public static class Commands
{
public static readonly CompositeCommand DiceRolledCommand = new CompositeCommand();
}
in a ControlLibrary referenced by my startup project iv'e got a Control which has a DelegateCommand ,
each instance of this Control has to register it's Command with the globally exposed DiceRolledCommand.
what wold be the best practice of doing so :
here are 3 idea's of which the first 2 i don't like because they are a kinda of hack , where you take some programming component (dp) and alter it's use for your benefit , resulting in poor code and design .
1)
a regular decadency property of type CompositeCommand which will be set with DiceRolledCommand
and on it's CallBack register MyControl's DelegateCommand (OnDiceRolledCommand) .
public class MyControl : Control
{
public DelegateCommand<Tuple<int, int>> OnDiceRolledCommand { get; private set; }
public CompositeCommand GlobalDiceRolledCommand
{
get { return (CompositeCommand)GetValue(GlobalDiceRolledCommandProperty); }
set { SetValue(GlobalDiceRolledCommandProperty, value); }
}
public static readonly DependencyProperty GlobalDiceRolledCommandProperty =
DependencyProperty.Register("GlobalDiceRolledCommand", typeof(CompositeCommand), typeof(MyControl), new UIPropertyMetadata(null,GlobalDiceRolledCommandPropertyChanged));
private static void GlobalDiceRolledCommandPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myControl= d as MyControl ;
var compoisteCommand = e.NewValue as CompositeCommand;
compoisteCommand.RegisterCommand(myControl.OnDiceRolledCommand);
}
}
<local:MyControl GlobalDiceRolledCommand="{x:Static local:Commands.DiceRolledCommand}"/>
i don't like this approach since it's a kind of manipulation where a Dependency Property is used has a Complex logical setter .
2) i could also do the same as in (1) using a third party class with an attached property which will register the OnDiceRolledCommand in an attached property's CallBack
public static class Commands
{
public static readonly CompositeCommand DiceRolledCommand = new CompositeCommand();
public static ICommand GetRegisterToDiceRolledCommand(DependencyObject obj)
{
return (ICommand)obj.GetValue(RegisterToDiceRolledCommandProperty);
}
public static void SetRegisterToDiceRolledCommand(DependencyObject obj, ICommand value)
{
obj.SetValue(RegisterToDiceRolledCommandProperty, value);
}
public static readonly DependencyProperty RegisterToDiceRolledCommandProperty =
DependencyProperty.RegisterAttached("RegisterToDiceRolledCommand", typeof(ICommand), typeof(Commands), new UIPropertyMetadata(null,OnRegisterToDiceRolledCommandProperty);
private static void OnRegisterToDiceRolledCommandProperty(DependencyObject d , DependencyPropertyChangedEventArgs e)
{
var commandToRegister = e.newValue as DelegateCommand;
DiceRolledCommand.RegisterCommand(commandToRegister );
}
}
<local:MyContorl local:Commands.RegisterToDiceRolledCommand="{Binding OnDiceRolledCommand , RelativeSource={RelativeSource Self}}"/>
i also don't like this approach for the same reason as 1 ..
3) passing the composite command as a parameter to constructor , this approach is better since it keeps
the initializing logic in the constructor where it should be , i just can't figure out how to pass
an argument to a contractor through XAML , i'm not sure if it's even possible .
public class MyControl : Control
{
public MyControl(CompositeCommand globalDiceRolledCommand)
{
.........
globalDiceRolledCommand.Register(OnDiceRolledCommand);
}
}
<local:MyControl ..... >
Some how pass parameters to contractor in order to create the element in XAML
</local:MyControl>
to summarize :
A) any thoughts about (1) and (2) .
B) thoughts of how to accomplish 3 , and if it seems like good design .
C) Any good pattern of accomplishing this scenario.
thanks in advance .
Whenever I use Global Commands like that they are usually defined in either an Infrastructure class library which every library can reference. Or they are defined in a consuming core library that each module could reference directly.
I wrote a lot of this up in a Code Project article
Part 2 here
Please help me understand where the value "ABC" gets stored. When I run memory profilers I don't see any instance of MyClass, and in fact the binding works and the GroupBox.Header gets the value ABC...
Thanks for your help.
<GroupBox Header="{Binding Path=(local:MyClass.Tag1), RelativeSource={RelativeSource Self}}"
local:MyClass.Tag1="ABC" />
public class MyClass
{
public static readonly DependencyProperty Tag1Property = DependencyProperty.RegisterAttached("Tag1", typeof(object), typeof(MyClass), new UIPropertyMetadata(null));
public static object GetTag1(DependencyObject obj)
{
return obj.GetValue(Tag1Property);
}
public static void SetTag1(DependencyObject obj, object value)
{
obj.SetValue(Tag1Property, value);
}
}
Dependency properties maintain a dictionary internally. Values are stored using sparse storage mechanism. These properties are associated at the class level - being static. The value ABC is stored in the dictionary as key value pairs
Here is a pretty straight forward explanation of how it works: http://nirajrules.wordpress.com/2009/01/19/inside-dependencyobject-dependencyproperty/
Essentially as Hasan Fahim said, the dependency properties are stored in an internal Hashtable based on the property name and the owner of the property. By storing the property as associated with the owner, you can actually have unique entires in the HashTable for different objects of the same type. This means that the Get and Set methods do not need to be static.
Example:
public class Something
{
public static readonly DependencyProperty IsEditableProperty = DependencyProperty.Register("IsEditable", typeof(Boolean), typeof(ResourceCanvas), new PropertyMetadata(true));
public Boolean IsEditable
{
get { return (Boolean)this.GetValue(IsEditableProperty); }
set { this.SetValue(IsEditableProperty, value); }
}
}
With version I can instantiate many instances of type Something each containing a "different" value of IsEditable.
I made an usercontrol and it works great, but when I put two instances of this control to one window, only the last of them works. I tried to find solution and I realized, that dependency properties are shared, but I dont know how to get it work.
Here is my dependency property:
public double AnimatingVerticalOffset
{
get { return (double)GetValue(AnimatingVerticalOffsetProperty); }
set { SetValue(AnimatingVerticalOffsetProperty, value); }
}
public static readonly DependencyProperty AnimatingVerticalOffsetProperty;
static ListChooser()
{
ListChooser.AnimatingVerticalOffsetProperty =
DependencyProperty.Register("AnimatingVerticalOffset", typeof(double), typeof(ListChooser), new UIPropertyMetadata(OnAnimationVerticalOffsetChanged));
}
The dependency property itself must be static with no ties to one single instance. And that applies for its callbacks too (OnAnimationVerticalOffsetChanged in your case) - these must be static methods (don't worry, the object instance is passed via its parameter, you just have to do some type casting to ensure the object is the type you are working with).
You should use static initializer to initialize DP, the method you used (initializing in constructor) works, but the DP will overwrite for each instance.
See this question for deeper explanation.
EDIT:
Corrected code:
public double AnimatingVerticalOffset
{
get { return (double)GetValue(AnimatingVerticalOffsetProperty); }
set { SetValue(AnimatingVerticalOffsetProperty, value); }
}
public static readonly DependencyProperty AnimatingVerticalOffsetProperty =
DependencyProperty.Register("AnimatingVerticalOffset", typeof(double), typeof(ListChooser), new UIPropertyMetadata(OnAnimationVerticalOffsetChanged));
static ListChooser()
{
}
If the callback is not static, you will get compile error (=> you have to make it static).
EDIT:
Remember, the DP definition is static, not the property's value itself! DPs work exactly just like any other property, it just has some extra features: value inhertiance, bidnings, animation...
I have 2 controls A and B that need to share a dependency property.
A has the property defined as:
public static readonly DependencyProperty PathProperty= DependencyProperty.Register("PathProperty", typeof(string), typeof(A),
new PropertyMetadata(string.Empty, OnPathChanged));
public string Path
{
get { return (string)GetValue(PathProperty); }
private set { SetValue(PathProperty, value); }
}
private static void OnPathChanged(DependencyObject dobj, DependencyPropertyChangedEventArgs args)
{
//Dos something
}
Inside of class B,
I have
public static readonly DependencyProperty Path = A.PathProperty.AddOwner(typeof(B));
public string Path
{
get { return (string)GetValue(Path); }
set { SetValue(Path, value); }
}
Now, if I set the Dependency property Path on B explictly...(from code like Binstance.Path = "value" )
I would expect the OnPathChangedmethod to fire inside of A control?
Isnt that the expected behavior or am I missing something? How do I get this to work? ... i.e changing path property on B should fire OnPAthChanged on A
Thanks!
I think you've misunderstood the concept of DependencyProperties... Two separate controls do not receive updates of each other's events - nor does two Dependency-derived objects receive notifications of other objects' changes (E.g. if you have two textboxes - changing one's TextProperty, does nothing to the other). If you really want your second Control type to fire the static validation-callback - you need to make it public and call it in your registration of the DependencyProperty on class B. I wouldn't recommend it though - it gives you very tight coupling between the two classes that otherwise have nothing in common (as I understand your example).
I'm using WPF and have a data class which I bind to a control's DependencyProperties. I need to change the binding at run time under the control of a user. Ideally I'd like to be able to do something like this
myControl.SetBinding(UserControl.GetDependencyProperty("HeightProperty")
, myBinding);
Of course GetDependencyProperty taking a string doesn't work, I've got around this by creating my own static class
public static DependencyProperty GetDP(string Name)
{
switch (Name)
{
case "Height": return UserControl.HeightProperty;
case "Width": return UserControl.WidthProperty;
....
}
Is there a better way?
You haven't described how the user changes the target dependency property. Can you just store the DependencyPropertys themselves rather than strings? That way you don't have to do any conversion at all. Pseudo-code:
//just an array of all allowable properties
public DependencyProperty[] AllowedProperties { get; }
//the property the user has chosen
public DependencyProperty ChosenProperty { get; set; }
//called whenever ChosenProperty changes
private void OnChosenPropertyChanged()
{
//redo binding here, using ChosenProperty as the target
}
Edit after comments: You can use DependencyPropertyDescriptor.FromName to get a DependencyProperty from its name, assuming you know the type of the owner:
var descriptor = DepedencyPropertyDescriptor.FromName(nameFromExcel, typeof(YourUserControl), typeof(YourUserControl));
var dependencyProperty = descriptor.DependencyProperty;