DepedencyProperty within a MarkupExtension - wpf

Is it possible to have a DependencyProperty within a MarkupExtension derived class?
public class GeometryQueryExtension : MarkupExtension
{
public XmlDataProvider Source { get; set; }
public string XPath { get; set; }
public static readonly DependencyProperty ArgumentProperty = DependencyProperty.RegisterAttached(
"Argument",
typeof(string),
typeof(GeometryQueryExtension)); // this wont work because GeometryQueryExtension is not a DependencyProperty
public string Argument
{
get
{
return (string)GetValue(ArgumentProperty); // this wont even compile because GeometryQueryExtension doesnt derive from a class which has GetValue
}
set
{
SetValue(ArgumentProperty,value);// this wont even compile because GeometryQueryExtension doesnt derive from a class which has SetValue
}
}
}
The extension is used in the following snippet.
<Label.Content>
<local:GeometryQueryExtension Source="{StaticResource shapesDS}">
<local:GeometryQueryExtension.XPath>
/Shapes/Geometry/{0}
</local:GeometryQueryExtension.XPath>
<local:GeometryQueryExtension.Argument>
<Binding XPath="Geometry"/> <!-- will throw exception when processing this bind -->
</local:GeometryQueryExtension.Argument>
</local:GeometryQueryExtension>
</Label.Content>
Is it even possible to build such an extension or am i just barking up the wrong tree ?
(the code above wont compile and run, but i posted it here to best illustrate the problem).

No, you can only add dependency properties to classes that are derived from DependencyObject, MarkupExtention is derived directly from Object

Yea.. it’s an ugly problem.. However it has a simple non intuitive answer.
Create another markup extension to get the static resource.
So instead of using {StaticResource shapesDS}
You would create a new MarkupExtension called DataSetLocator
I'm not going to write the code but the Provide value would need to return your dataset based on a name or some other input.
Then you change your xaml to have your extension use the dataset locator extension example Source="{DataSetLocator name=shapesDS }"
It’s too bad that extensions don’t extend DependencyProperty but they don’t.

Just use IMarkupExtension instead of MarkupExtension and you can extend DependencyObject. At least in Silverlight 5 you can, but I would assume WPF also has it.

Related

WPF Dependency Object

Has anyone ever heard of implementing IDependencyObject instead of inheriting from it -- that way one could actually create a class hierarchy instead of having to use only interfaces when trying to get both dependency object/property and custom behavior on our classes.
I want to have a hierarchy of class kinds that are directly usable in the context of an existing structure, i.e. Polygon. I want to be able to use my PolyType in any place, and without any more dialogue and indirection that would be required if I place the PolyGon existing type as a Part of my DependencyObject. But I also want to be able to have my class as the a) the target of {Binding} markup extension, b) Animate properties of PolyType and c) apply themed styling to PolyType.
I want to implement IDependencyObject instead of being forced to inherit from it directly, and obstructing my ability to be a direct descendent and usable in place of, PolyGon.
Not sure why you have to inherit from DependencyObject. I use a custom code snippet that generates the following code to register a dependancy property:
public partial class UserControl1 : UserControl
{
public static DependencyProperty MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(Polygon), typeof(UserControl1), new FrameworkPropertyMetadata(new PropertyChangedCallback(MyProperty_Changed)));
public Polygon MyProperty
{
get { return (Polygon)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
private static void MyProperty_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
UserControl1 thisClass = (UserControl1)o;
thisClass.SetMyProperty();
}
private void SetMyProperty()
{
//Put Instance MyProperty Property Changed code here
}
public UserControl1()
{
InitializeComponent();
}
}
As you can see the DependencyObject can be any type of object. If this is not what you need, please post you code examples, or explain your situation better.

Tag Property in WPF DataGrid Column

I need to save an string inside a Datagrid Column which differs from the Header.
This is needed because I generate a Datagrid dynamically and want to translate the Column Headers while generating them. Then I bind the whole XAML to a ContentControl.
No problem till here... But I want to reorder and resize the columns, so I need to lookup them afterwoods. For this I need the original (not translated) ColumnHeader.
In my opinion a Tag property of the column would solve this problem, but there is no :(
In WPF, you have virtually unlimited "Tag" properties by using Attached Properties. An attached property can be set on any DependencyObject. A good example of such an attached property is Grid.Row. Since you can define them, you also have the possibility of naming them something more meaningful than Tag.
Sample code for defining an attached property:
public static class SomeClass {
public static readonly DependencyProperty TagProperty = DependencyProperty.RegisterAttached(
"Tag",
typeof(object),
typeof(SomeClass),
new FrameworkPropertyMetadata(null));
public static object GetTag(DependencyObject dependencyObject) {
return dependencyObject.GetValue(TagProperty);
}
public static void SetTag(DependencyObject dependencyObject, object value) {
dependencyObject.SetValue(TagProperty, value);
}
}
Usage :
<DataGridColumn SomeClass.Tag="abc" />

Why does data binding to DynamicResource not work?

The following code does not work. How do I make it work?
<Image Source="{DynamicResource {Binding VM.ImageKey}}" />
This is an incorrect usage of the DynamicResource MarkupExtension. Correct it would be:
<Image Source="{DynamicResource VM.ImageKey}" />
Assuming you have a resource with a key "VM.ImageKey" defined somewhere like this:
<Bla.Resources>
<BitmapImage x:Key="VM.ImageKey" UriSource="C:\Uri\To\Image.jpg" />
</Bla.Resources>
However if you want to bind against some property form the current DataContext you must not use DynamicResource but Binding:
<Image Source="{Binding VM.ImageKey}" />
Assuming your current DataContext is an instance that has a property called VM wich again has a property called ImageKey wich is a derived type of ImageSource.
This behaviour is by design. Binding works only on dependency properties of dependency objects and MarkupExtension is not dependency object.
It cannot work since the DyamicResource is a MarkupExtension and not a dependency property. Databinding only works with dependendcy properties.
However, there is a semi smooth workaround. Create a DynamicTextBlock class that extends a TextBlock.
The xaml:
<TextBlock x:Class="Rebtel.Win.App.Controls.DynamicTextBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"/>
The codebehind:
public partial class DynamicTextBlock : TextBlock
{
public static readonly DependencyProperty TextKeyProperty = DependencyProperty.Register(
"TextKey", typeof(string), typeof(DynamicTextBlock), new PropertyMetadata(string.Empty, OnTextKeyChanged));
private static void OnTextKeyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var me = ((DynamicTextBlock)d);
if (e.NewValue != null)
{
me.TextKey = (string) e.NewValue;
}
}
public string TextKey
{
set { SetResourceReference(TextProperty, value); }
}
public DynamicTextBlock()
{
InitializeComponent();
}
}
Usage:
<local:DynamicTextBlock TextKey="{Binding TextKeyProperty}" />
The TextKeyProperty then returns a key that can be found in the ResourceDictionary. The same approach can be taken for an Image and its Source property.
If you want to specify the resource key dynamically you should specify it using the ResourceKey markup extension - not sure if it supports bindings in the way you want it to however. See here for more details.
I'm assuming that in this case, VM.ImageKey refers to a property on a data source whose value you wish to use as a resource dictionary key. The idea being that your data source can determine which image is used by supplying a resource key. (Most of the other answers on this page are unhelpful, because they have unfortunately missed what you're trying to do, assume that you want to use the literal text "VM.ImageKey" as a resource key, which I'm pretty sure isn't what you're asking for.)
This doesn't seem to be supported, but there's another approach that can enable you to select an image resource through a key determined by databinding: https://stackoverflow.com/a/20566945/497397

How to Add Custom Silverlight XAML Attributes?

Is it possible to introduce 'custom' attributes into different UI Elements in XAML ? Also to read them later like we add attributes for server controls in ASP.NET ?
I intend to read specific attributes and operate on them together.
It sounds like you're trying to find Attached Properties.
An attached property lets you add in a property, definable in Xaml, which can be "attached" to any UIelement. You then retrieve them in code like any other Dependency Property.
Here is the approach I tend to take with this.
Create a new class file called Meta:-
namespace SilverlightApplication1
{
public static class Meta
{
#region SomeValue
public static string GetSomeValue(DependencyObject obj)
{
return (string)obj.GetValue(SomeValueProperty);
}
public static void SetSomeValue(DependencyObject obj, string value)
{
obj.SetValue(SomeValueProperty, value);
}
public static readonly DependencyProperty SomeValueProperty =
DependencyProperty.RegisterAttached("SomeValue", typeof(string), typeof(Meta),
new PropertyMetadata(null));
#end region
#region SomeOtherValue
// Boilerplate code from above.
#end region
}
}
A value can now be attached in XAML like this:-
<TextBox x:Name="txt" local:Meta.SomeValue="Hello, World!" />
At some point in code this value can be retrieved with:-
string value = Meta.GetSomeValue(txt);
Note you don't have to stick with String as the type of the property you can pretty much use any type you like with the limitation that if you can to attach it in XAML the type must be compatible with the way XAML constructs objects (for example requires a default constructor).
The way I've accomplished that is by creating a new class that inherits the base control.
For example, I have a class called WebTextBox that inherits TextBox. And inside WebTextBox are some custom properties and events. By doing this you're inheriting all the behaviors of the TextBox control. But you can get creative here if you choose, even modifying the behavior by overriding events and such.
Anyway, after you create the class you'll then have to add the namespace for the project to the XAML. Something like this:
xmlns:me="clr-namespace:YourNamespace;assembly=YourAssembly"
And then you can add a WebTextBox (or whatever you call it) like this:
<me:WebTextBox CustomAttribute="cool stuff" />

UserControl vs SurfaceWindow

I am trying to use values i declare inside a UserControl class to change things inside the SurfaceWindow class. Now what i know so far is that i have to use a DependencyProperty to get the value from the UserControl and then put it inside a public string.
public string MapValue
{
get { return (string)GetValue(MapValueProperty); }
set { SetValue(MapValueProperty, value); }
}
public static readonly
DependencyProperty MapValueProperty = DependencyProperty.Register("MapValue", typeof(string), typeof(MapManager));
Now my question is, how do i bind the public string (that is inside the UserControl) to a element (inside the SurfaceWindow)?
If i use the DependencyProperty do i make a new class or do i put it in the usercontrol code?
I would be very happy if someone could help me with this problem..
As far as i can tell you are trying to bind to a dependency property of some control in your window.
If this is the case you could use the ElementName syntax in the binding declarations such as:
<TextBlock Text="{Binding ElementName=MapControl, Path=MapValue}"/>
I had already have this inside my window control:
<Image x:Name="iGroundPlan" Source="{Binding ElementName=MapManager,Path=MapValue}" />
(MapManager is the name of my usercontrol)
But looks like it aint working, and i dont know why.. Its like the windows never knows when the value MapValue is updated in my usercontrol =\

Resources