Numeric type as DependencyProperty - c#

How to register custom property which based on numeric type?
public class NumberBox : TextBox
{
public static readonly DependencyProperty FormatProperty = DependencyProperty.Register("FormatValue", typeof(Type), typeof(NumberBox), new UIPropertyMetadata(default(Double)));
public Type FormatValue
{
get
{
return (Type)GetValue(FormatProperty);
}
set
{
SetValue(FormatProperty, value);
}
}
}
XAML
<nb:NumberBox FormatValue="{System:Int32}"/>
I am sure, that is not perfect, but I really don't know how it make workable.
UPDATE:
Basically, me need to have a way to set the type of my number box. For example, if I need to use Double NumberBox I just set FormatValue="Double"

First issue is default metadata provided in last parameter of DP identifier is incorrect.
Instead of
new UIPropertyMetadata(default(Double)),
it should be
new UIPropertyMetadata(typeof(Double))
Second issue in XAML. Use x:Type to pass type.
<nb:NumberBox xmlns:sys="clr-namespace:System;assembly=mscorlib"
FormatValue="{x:Type sys:Int32}"/>

From here http://msdn.microsoft.com/en-us/library/ee792002%28v=vs.110%29.aspx, the types are x:Int32, x:Double, ...
So you want to use:
<nb:NumberBox FormatValue="{x:Type x:Int32}"/>
In the general sense, you would have to include the namespace in the XAML:
<Window ...
xmlns:ns="clr-namespace:MyNamepsace;assembly=MyAssembly"
>
<nb:NumberBox FormatValue="{x:Type ns:MyType}"/>
</Window>

Related

ObservableCollection is Null when I try to add TextBlocks through XAML to a custom control

In my WPF Project, i am trying to create an ObservalbeCollection dependency property inside a custom control. I am not sure if i am doing it the right way but i am using the below code :
public static readonly DependencyProperty MenuOptionsDependency = DependencyProperty.Register("MenuOptions", typeof(ObservableCollection<TextBlock>), typeof(DropDownButton));
public ObservableCollection<TextBlock> MenuOptions
{
get
{
return (ObservableCollection<TextBlock>)GetValue(MenuOptionsDependency);
}
set
{
SetValue(MenuOptionsDependency, value);
}
}
The problem arises when i try to add TextBlocks through XAML to this control as follows :
<local:CustomControl1 x:Name="cmm">
<local:CustomControl1.MenuOptions>
<TextBlock/>
</local:CustomControl1.MenuOptions>
</local:CustomControl1>
This throws a design time error saying :
Collection 'CustomControl1'.'MenuOptions' is null
After going through the accepted answer on this SO post, i understand ObservableCollection, being a reference type, will be null as it will be default value. I read through the answer but i am still unclear/unsure on how to implement the solution in my situation.
I need to be able to add objects to the collection through XAML(and also through C#). I would really appreciate if someone points out where i am missing/what i am doing wrong.
You must never set the default value of a collection type dependency property to something else than null. When you assign a non-null default value by (static) property metadata, all instances of your control will use the same collection object.
Instead, set a default value in the control's constructor by SetCurrentValue:
public DropDownButton()
{
SetCurrentValue(MenuOptionsDependency, new ObservableCollection<TextBlock>());
}
Besides that, there is a strict naming convention, according to which the dependency property identifier field must be named as the property with a Property suffix. So your MenuOptionsDependency should actually be named MenuOptionsProperty.
It's also unclear whether the property type really needs to be ObservableCollection. You don't seem to register a CollectionChanged event handler anywhere, which indicates that your control is not supposed to react on such changes.
Consider a property declaration like this:
public DropDownButton()
{
SetCurrentValue(MenuOptionsProperty, new List<TextBlock>());
}
public static readonly DependencyProperty MenuOptionsProperty =
DependencyProperty.Register(
nameof(MenuOptions), typeof(IEnumerable<TextBlock>), typeof(DropDownButton));
public IEnumerable<TextBlock> MenuOptions
{
get { return (IEnumerable<TextBlock>)GetValue(MenuOptionsProperty); }
set { SetValue(MenuOptionsProperty, value); }
}

Custom DependencyProperty set from DataTemplate

I'm working with a custom control that has several user-defined dependency properties. I'm running into the same issue described in this question.
My control is setting the default value of a custom dependency property in its constructor. When I use the control in a DataTemplate, the value set in the constructor is always used, even if I try to set it in XAML.
The answer to the linked question explains that the value set in the C# code has a higher priority, and a better approach would be to specify the default value in the dependency property's metadata.
In my case, I can't specify a default because the dependency property doesn't have a single default value that applies in all cases. The default values depend on another property, so I must look them up when the control is created and not when the property is registered.
Here's some code to help illustrate my problem:
public partial class MyControl : UserControl
{
public static readonly DependencyProperty MyProperty =
DependencyProperty.Register(
"MyProperty",
typeof(int),
typeof(MyControl),
new FrameworkPropertyMetadata(
int.MinValue,
FrameworkPropertyMetadataOptions.None,
new PropertyChangedCallback("OnMyPropertyChanged")));
public MyControl() : base()
{
InitializeComponent();
this.MyProperty = GetDefaultPropertyValue();
}
public int MyProperty
{
get { return (int)GetValue(MyProperty); }
set { SetValue(MyProperty, value); }
}
private int GetDefaultPropertyValue()
{
// look up the appropriate default based on some other criteria
return 42;
// (in reality, the default value for "MyProperty"
// depends on the value of a "Mode" custom DependencyProperty.
// this is just hard coded for testing)
}
}
The XAML usage looks something like this:
<!-- View displays 4 (desired) -->
<local:MyControl MyProperty="4" />
<!-- View displays default of 42 (desired) -->
<local:MyControl />
<!-- View displays default of 42 (wanted 4) -->
<DataTemplate x:Key="MyTemplate">
<local:MyControl MyProperty="4"/>
</DataTemplate>
To summarize:
The desired behavior is that the value from XAML is used first. If the value is not specified in the XAML, then I would like to fallback to the default value set in the control's constructor.
If I just include the control directly in a view, I get the expected behavior. If the control is used inside a DataTemplate, then I always get the default set in the constructor (even when the data template explicitly sets another value).
Is there any other way to specify the default value when the control is used in a template? The only option I can think of is to break the control up into several separate but similar controls, each of which uses a default value that is registered with the dependency property (which removes the need to have the default set based on the a Mode property).
Setting the default value in OnApplyTemplate while adding a small check should solve this:
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
// Only set the default value if no value is set.
if (MyProperty == (int)MyPropertyProperty.DefaultMetadata.DefaultValue)
{
this.MyProperty = GetDefaultPropertyValue();
}
}
Please note that although this will work, it's not ideal since setting the property's value by code will essentially clear any data bindings for this property. For example, the following binding will no longer work once you call MyProperty = 42 in code:
<local:MyControl MyProperty="{Binding SomeProperty}" />
It should be possible to set the value while maintaining any bindings by using SetCurrentValue(MyPropertyProperty, GetDefaultPropertyValue()); to modify the property instead of MyProperty = GetDefaultPropertyValue(), but I'm not sure I like that too much either.
A better solution
What I would do is introduce a new read-only property in addition to the existing one, which will act as a calculated property. For example:
private static readonly DependencyPropertyKey MyCalculatedPropertyPropertyKey =
DependencyProperty.RegisterReadOnly("MyCalculatedProperty", typeof(int), typeof(MyControl),
new PropertyMetadata(int.MinValue));
public static readonly DependencyProperty MyCalculatedPropertyProperty = MyCalculatedPropertyPropertyKey.DependencyProperty;
public int MyCalculatedProperty
{
get { return (int)GetValue(MyCalculatedPropertyProperty); }
private set { SetValue(MyCalculatedPropertyPropertyKey, value); }
}
private static void OnMyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MyControl)d).MyCalculatedProperty = (int)e.NewValue;
}
public MyControl()
: base()
{
InitializeComponent();
MyCalculatedProperty = GetDefaultPropertyValue();
}

Pass primitive Type as a parameter from XAML

TL;DR - I'm having a problem passing system types as a value to Type parameters in Silverlight. Is this some kind of known problem? Is it possible at all?
In details:
In my control I have dependency property of type Type. And there is a problem with passing types from System namespace, like int(Int32), string(String), Guid, decimal(Decimal), bool(Boolean). In these cases the depencency property receives null value (depencency property default value is set to some non-null value, so I see in OnPropertyChanged event that null is passed). For other types it works without problems.
Here is the code of my dependency property:
public static readonly DependencyProperty SomeTypeProperty = DependencyProperty.Register(
"SomeType", typeof(Type), typeof(Control1), new PropertyMetadata(typeof(EmptyType), OnSomeTypePropertyChanged));
public Type SomeType
{
get { return (Type)GetValue(SomeTypeProperty); }
set { SetValue(SomeTypeProperty, value); }
}
And the control's usage:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
[...]
<sl1:Control1 SomeType="sys:Boolean" />
What's interesting - it works in XAML designer in Visual Studio. I know this by displaying the property value, so the passed Type, in my Control1 control's content. But in Silverlight runtime environment it doesn't work.
I don't know why this is happening... However, here's a workaround..
Create the following class:
public class TypeOfRes
{
public object Object { get; set; }
public Type TypeOf
{
get { return Object == null ? null : Object.GetType(); }
}
}
Create the following resource in your page:
<local:TypeOfRes x:Key="booleanRes">
<local:TypeOfRes.Object>
<sys:Boolean>True</sys:Boolean>
</local:TypeOfRes.Object>
</local:TypeOfRes>
Reference the resource in your property:
<local:SilverlightControl1 MyType="{Binding Source={StaticResource booleanRes},Path=TypeOf}"/>

Simple object building by xaml

I have a simple class and I want to simply create instances of my class via xaml. But I'm still getting errors like: "'Test' member is not valid because it does not have a qualifying type name."
UserControl1.xaml.cs:
namespace WpfTestApplication1
{
public class UserControl1 : UserControl
{
public string Test { get; set; }
public UserControl1()
{
}
}
}
UserControl1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfTestApplication1">
<local:UserControl1>
<Setter Property="Test" Value="aaaa" />
</local:UserControl1>
</ResourceDictionary>
Please, help.
The way you have set the Property on your UserControl is not valid. You have set the Content of your UserControl by putting Setter inside the nodes.
First define Test as DependencyProperty if you want it to be binding target and then set it directly on UserControl as
<local:UserControl1 Test="aaaa"/>
Try to use DependencyProperty instead of default property.
As #us3r said...DependencyProperty is what you are looking for.
What you have to do is:
// Dependency Property
public static readonly DependencyProperty TestProperty =
DependencyProperty.Register( "Test", typeof(string),
typeof(UserControl1 ));
// .NET Property wrapper
public string Test
{
get { return GetValue(TestProperty ).; }
set { SetValue(TestProperty , value); }
}
Finally I found it out.
I defined the control in xaml as
<local:UserControl1 x:Key="xxx" Test="aaaa"/>
Without using setter and property statements, just by directly defining the property.
Thanks for help!

GetBindingExpression returns null in the Loaded event

I'm trying to call the GetBindingExpression method in the Loaded event, but it always returns null.
Is this expected behavior, or am I doing something wrong? If it is expected, after what event do binding expressions become available?
I just create custom control
public partial class LookUp : ComboBox
public static readonly DependencyProperty LookUpItemsSourceProperty =
DependencyProperty.Register("LookUpItemsSource"
, typeof(IEnumerable)
, typeof(LookUp)
, new PropertyMetadata(OnItemsSourcePropertyChanged));
public IEnumerable LookUpItemsSource
{
get
{
return this.GetValue(LookUpItemsSourceProperty) as IEnumerable;
}
set
{
this.SetValue(LookUpItemsSourceProperty, value);
}
}
And use this control in xaml
<Controls:LookUp Name="cb1" LookUpItemsSource="{x:Static Helper:DataManager.CycleLookUpData}"
Now i want to get binding expression when control initialized that method return null:
cb1.GetBindingExpression(LookUp.LookUpItemsSourceProperty)
x:static will set the value of key, it is not binding expression. You will have to use,
{Binding CycleLookUpData, source={x:static Helper:DataManager}}
If you don't use {Binding ... in XAML you can't use GetBindingExpression() method. In your case you set value instead of binding. You need to use cb1.GetValue(LookUp.LookUpItemsSourceProperty) instead.

Categories

Resources