WPF: How to accept both string and FrameworkElement in dependency property (like wpf Label does)? - wpf

I am creating a custom WPF control that should have several content slots.
I'd like the user to be able to use either string, or a FrameworkElement as a value of property, for example:
<!-- MyHeading is a string -->
<MyControl MyHeading="Hello World" />
<MyControl>
<!-- MyHeading is a FrameworkElement -->
<MyControl.MyHeading>
<Expander Header="Hello">
World
</Expander>
</MyControl.MyHeading>
</MyControl>
I know that WPF ContentControl does this (accepts both strings and other elements), and I know that it has something to do with TypeConverter attribute (partially explained here), but I tried to look at ContentControl, Label, TextBlock and other controls in Reflector, and didn't find any TypeConverter atrribute there, and googling didn't help.
I first tried to implemet it like this, but it obviously doesn't know about how to convert string to FrameworkElement, and throws exception during control's initialization:
public FrameworkElement Heading
{
get { return (FrameworkElement)GetValue(HeadingProperty); }
set { SetValue(HeadingProperty, value); }
}
// Using a DependencyProperty as the backing store for Heading. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeadingProperty =
DependencyProperty.Register("Heading", typeof(object), typeof(DialogControl), new UIPropertyMetadata(new FrameworkElement()));
Then I tried to hack it like this:
public object Heading
{
get { return (object)GetValue(HeadingProperty); }
set
{
if (value is string)
{
var tb = new TextBlock();
tb.Text = (string) value;
tb.FontSize = 20;
SetValue(HeadingProperty, tb);
}
else if (value is FrameworkElement)
{
SetValue(HeadingProperty, value);
} else
throw new ArgumentOutOfRangeException("Heading can take only string or FrameworkElement.");
}
}
// Using a DependencyProperty as the backing store for Heading. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeadingProperty =
DependencyProperty.Register("Heading", typeof(object), typeof(DialogControl), new UIPropertyMetadata(null));
but it is pretty ugly and still doesn't instantiate :(.
Anyone knows how to do it? Thanks for your time!

The DependencyProperty should be of type Object. The magic happens in the when you bind the property as the Content for a ContentPresenter. You should also look into the ContentSource property if you want to handle Templating and StringFormatting properly.

As Bryan said just use object as your type. When WPF encounters a non-frameworkelement it will (assuming there is no DataTemplate to apply) call the object's ToString() method and use the text as the content. So not only can you use string, but also DateTime, Enum's, whatever.
Also, you should consider deriving from HeaderedContentControl if your control has both a header and main content. Then you don't need to implement either of those two content properties and you'll get all the bells and whistles for free such as data templating.

As the others have said, set the type to be object. To do type checking, use the validation callback on the dependency property. Then do checks for valid types.
public object Header
{
get { return (object)GetValue(HeadingProperty); }
set { SetValue(HeadingProperty, value); }
}
// Using a DependencyProperty as the backing store for Value. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HeadingProperty = DependencyProperty.Register(
"Heading",
typeof(object),
typeof(DialogControl),
new UIPropertyMetadata(null),
new ValidateValueCallback(Heading_Validation)
);
private static bool Heading_Validation(object source)
{
return source is string||
source is FrameworkElement ||
source == null;
}
This will check to see, before assignment, if the passed object is of type String, FrameworkElement or null.
Enjoy!

Related

How can I make a dependency property of a list of strings in WPF?

I have found some examples, but none seemed to work. I`m trying to bind a list of strings to my user control through this dependency property.
public IList ImageNames
{
get { return (IList)GetValue(ImageNamesProperty); }
set { SetValue(ImageNamesProperty, value); }
}
// Using a DependencyProperty as the backing store for ImageNames. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ImageNamesProperty =
DependencyProperty.Register("ImageNames", typeof(IList), typeof(DynamicWallpaperUserControl), new PropertyMetadata(new List<string>()));
From the ViewModel, I have a List String DesertImages which I`m binding to the user control. In Xaml:
<controls:DynamicWallpaperUserControl
Background="Transparent"
ImageNames="{Binding Path=DesertImages}" />
Visual Studio says the list is empty though Appreciate any help

How can I get databinding debug information in MVVM/Prism?

I am making my first serious foray into Prism(Unity). I have a module with a toolbar control that gets loaded (properly) into the region that it is supposed to. This toolbar is a listbox with ItemsSource databound to the ToolButtons property on its ViewModel, the constructor for which instantiates and adds three ToolButtons to the ToolButtons collection.
My ToolButton class has three custom DependencyProperties: Title (string), ButtonFace (Image), ActiveDocumentCount (int). Styling is taken care of by a resource dictionary in the module with a Style and associated ControlTemplate. I have databound the properties, but none of the values or the image are displaying (other elements in the style are however) via TemplateBinding.
I am trying to debug the databinding, but to no avail. I do not get any massages pertinent in the Output window, and the 2nd and 3rd suggestions in this blog have produced no output either. I think that if I could get the verbose (i.e. PresentationTraceSources.TraceLevel=High) output, I could figure out what is happening on the databinding front.
EDIT:
Toolbutton Class
public class ToolButton : Button
{
public ToolButton()
{
//DefaultStyleKeyProperty.OverrideMetadata(typeof(ToolButton), new FrameworkPropertyMetadata(typeof(ToolButton)));
}
public Image ButtonFace
{
get { return (Image)this.GetValue(ButtonFaceProperty); }
set { this.SetValue(ButtonFaceProperty, value); }
}
public static readonly DependencyProperty ButtonFaceProperty =
DependencyProperty.Register("ButtonFace", typeof(Image), typeof(ToolButton), new PropertyMetadata(null));
public string Title
{
get { return (string)this.GetValue(TitleProperty); }
set { this.SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(ToolButton), new PropertyMetadata(""));
public int OpenRecordCount
{
get { return (int)this.GetValue(OpenRecordCountProperty); }
set { this.SetValue(OpenRecordCountProperty, value); }
}
public static readonly DependencyProperty OpenRecordCountProperty =
DependencyProperty.Register("OpenRecordCount", typeof(int), typeof(ToolButton), new PropertyMetadata(null));
}
Those DPs look ok SetValue in the CLR backed property is fine....but if you or anyone is setting a local value on those properites (e.g. by calling your CLR backed properties or DependencyObject.SetValue) then that will destroy the binding.
Related links:
http://arbel.net/2009/11/04/local-values-in-dependencyobjects/
http://blogs.msdn.com/b/vinsibal/archive/2009/05/21/the-control-local-values-bug-solution-and-new-wpf-4-0-related-apis.aspx
http://wpf.2000things.com/2010/12/06/147-use-setcurrentvalue-when-you-want-to-set-a-dependency-property-value-from-within-a-control/
Whats the difference between Dependency Property SetValue() & SetCurrentValue()

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" />

Array of references

I would like to have a DependencyPropery which is an array of referenced UIElements. In WPF we have the x:Array markup extension and also the x:Reference available but it can't get it working.
Any ideas on that?
Chris
The standard way to do this is in WPF is to assign the UIElementCollection class to your dependency property, like this:
public UIElementCollection ElementCollection
{
get { return (UIElementCollection)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(UIElementCollection), typeof(MyClass), new UIPropertyMetadata(null));
In the constructor of your class, you should set the dependency property to new UIElementCollection.
Just found the answer myself.
MyPropertyProperty = DependencyProperty.Register("MyProperty", typeof(UIElement[]), typeof(MyClass), new FrameworkPropertyMetadata(null, MyPropertyChanged));
And the corresponding XAML looks like:
<cc:MyClass.MyProperty>
<x:Array Type="UIElement">
<x:Reference>NameOfTheReferencedUIElement</x:Reference>
</x:Array>
</cc:MyClass.MyProperty>
This way the dependency property is automatically filled with an array of referenced UI objects in form of UIElements.
Chris

Is there a way to pass a parameter to a command through a keybinding done in code?

I am making a custom control I need to add some default keybindings, microsoft has already done with copy and paste in a textbox. However one of the keybindings needs to pass a parameter to the command which it is bound to. It is simple to do this in xaml, is there any way to do this in code?
this.InputBindings.Add(new KeyBinding(ChangeToRepositoryCommand, new KeyGesture(Key.F1)));
I found the answer:
InputBindings.Add(new KeyBinding(ChangeToRepositoryCommand, new KeyGesture(Key.F1)) { CommandParameter = 0 });
I apologize if my question was unclear.
The copy and paste commands are handled by the text box so parameters are not strictly passed, but i know what you are getting at.
I do this using a hack - and an attached property, like so
public class AttachableParameter : DependencyObject {
public static Object GetParameter(DependencyObject obj) {
return (Object)obj.GetValue(ParameterProperty);
}
public static void SetParameter(DependencyObject obj, Object value) {
obj.SetValue(ParameterProperty, value);
}
// Using a DependencyProperty as the backing store for Parameter. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ParameterProperty =
DependencyProperty.RegisterAttached("Parameter", typeof(Object), typeof(AttachableParameter), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits));
}
then in the xaml
<ListBox local:AttachableParameter.Parameter="{Binding RelativeSource={RelativeSource Self}, Path=SelectedItems}" />
which makes the parameter the selected items
then when the command fires on the window i use this to see if the command parameter is there (i call this from the can execute and the Executed)
private Object GetCommandParameter() {
Object parameter = null;
UIElement element = FocusManager.GetFocusedElement(this) as UIElement;
if (element != null) {
parameter = AttachableParameter.GetParameter(element as DependencyObject);
}
return parameter;
}
It is a hack, but i have not found another way to get the command parameter for a binding that is fired from a key binding. (I would love to know a better way)

Resources