Array of references - wpf

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

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

Binding or execute control.method in mvvm

Textbox has Clear and GetSpellingErrors methods etc.
Is it possible for me to have something like < TextBox Clear={binding...} />?
I am aware Clear is not an "Dependency" anything. I'm authoring an usercontrol. I can add the DependencyProperty, DependencyObject as needed. I just want to know how to bind a method to the VM.
PS I don't need alternatives for Clear, I know I can set the property to string.empty.
Turns out you can use ICommand and create it like any other DependencyProperty.
public static readonly DependencyProperty CancelCommandProperty = DependencyProperty.Register("CancelCommand", typeof(ICommand), typeof(AddressUserControl), new PropertyMetadata());
[BindableAttribute(true)]
public ICommand CancelCommand { get { return (ICommand)GetValue(CancelCommandProperty); } set { SetValue(CancelCommandProperty, value); } }
The only problem I still have is I need this to be a read-only binding obviously.
Tried
DependencyProperty.RegisterReadOnly(...)
but there appears to be a bug with ReadOnly DependencyProperty https://connect.microsoft.com/VisualStudio/feedback/details/540833/onewaytosource-binding-from-a-readonly-dependency-property

Custom object as a DependencyProperty

I have a custom class, MyPerson. All (relevant) properties implement INotifyPropertyChanged.
I created a UserControl to display it, and it all worked fine. Binding to properties like MyPerson.FirstName (a string) all work - they display and update (two way binding) as expected.
Now I want to do more complex stuff in the codebehind, so I wanted to create a DependencyProperty with a PropertyType of MyPerson, but I'm not sure how to construct the DependencyProperty, in particular the PropertyChangedCallback part.
Can this be done? How so?
Read on this article - Custom Dependency Properties
Something like -
public static readonly DependencyProperty MyPersonValueProperty =
DependencyProperty.Register( "MyPersonValue", typeof(MyPerson),
typeof(MyPersonControl), new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnPersonChanged) ) );
public MyPerson ThePerson
{
get { return (MyPerson)GetValue(MyPersonValueProperty); }
set { SetValue(MyPersonValueProperty, value); }
}
private static void OnPersonChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
// Property change code here
}

Binding public property in UserControl to property on parent does not work [duplicate]

I have a WPF UserControl project named FormattedTextBox that contains a TextBox and a WPF window project in the same solution.
My user control has two dependency properties registered like this:
public static readonly DependencyProperty NumberProperty =
DependencyProperty.Register("Number",
typeof(double),
typeof(FormattedTextBox),
new FrameworkPropertyMetadata());
public static readonly DependencyProperty NumberFormatStringProperty =
DependencyProperty.Register("NumberFormatString",
typeof(string),
typeof(FormattedTextBox),
new FrameworkPropertyMetadata());
I make an instance of my usercontrol in the main window. The main window inplements INotifyPropertyChanged and has a property named MyNumber. In the XAML of the main window I try to bind to MyNumber like this:
Number="{Binding Path=MyNumber,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
The binding doesn't work - I never get into the get or set on the Number property in the user control. Can anybody help?
When a dependency property is set in XAML (or by binding or animation etc.), WPF directly accesses the underlying DependencyObject and DependencyProperty without calling the CLR wrapper. See XAML Loading and Dependency Properties,
Implications for Custom Dependency Properties.
In order to get notified about changes of the Number property, you have to register a PropertyChangedCallback:
public static readonly DependencyProperty NumberProperty =
DependencyProperty.Register("Number",
typeof(double),
typeof(FormattedTextBox),
new FrameworkPropertyMetadata(NumberPropertyChanged));
private static void NumberPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
var textBox = obj as FormattedTextBox;
...
}

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

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!

Resources