I was under the impression that CLR wrappers for dependency properties were optional under WPF, and just useful for setting within your own code.
However, I have created a UserControl without wrappers, but some XAML that uses it will not compile without them:
namespace MyControlLib
{
public partial class MyControl : UserControl
{
public static readonly DependencyProperty SomethingProperty;
static MyControl()
{
SomethingProperty = DependencyProperty.Register("Something", typeof(int), typeof(MyControl));
}
}
}
XAML usage:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ctrl="clr-namespace:MyControlLib;assembly=MyControlLib">
<ctrl:MyControl Something="45" />
</Window>
Trying to compile this gives:
error MC3072: The property 'Something' does not exist in XML namespace 'clr-namespace:MyControlLib'. Line blah Position blah.
Adding a CLR wrapper in MyControl.xaml.cs like:
public int Something
{
get { return (int)GetValue(SomethingProperty); }
set { SetValue(SomethingProperty, value); }
}
means it all compiles and works fine.
What am I missing?
You could use dependency properties without wrappers inside runtime bindings, but to set the property like you want you must have C# property to allow xaml compiler to compile your code.
I believe it will compile without the wrappers if you specify the namespace prefix on the property.
They are optional, but without them the property does not show up in the XAML designer automatically
<ctrl:MyControl ctrl:MyControl.Something="45" />
Related
I know that I can make attached properties, for example
public enum HideOption
{
node,
tree
}
public static class Hide
{
public static readonly DependencyProperty OptionProperty
= DependencyProperty.RegisterAttached ( "Option",
typeof(HideOption),
typeof(Hide),
new PropertyMetadata(HideOption.node) ) ;
public static HideOption GetOption ( DependencyObject obj )
{
return (HideOption)obj.GetValue(OptionProperty);
}
public static void SetOption ( DependencyObject obj, HideOption value )
{
obj.SetValue(OptionProperty, value);
}
}
and use it on XAML nodes, like
<Grid m:Hide.Option="tree">
</Grid>
The attributes in the "x" namespace have a shorter syntax, like
<Grid x:Uid="MyGrid">
</Grid>
Is it possible to create my own attributes which would use this syntax, for example
<Grid m:Hide="tree">
</Grid>
or is it some special feature of the XAML Language not available to normal libraries?
This are not attached properties. The x namespace contains XAML compiler directives. They are instructions to the XAML parser and compiler or code generator. Like x:Class tells the compiler to link the generated XAML class with a partial declared C# class (code-behind). This directives are no DependencyProperties and don't participate in the dependency property system like attached properties do.
Since this directives are compiler level, I don't think that you can create them. You would need a way to tell the compiler how to interpret this directives.
Using:
Visual Studio Community Edition 2015
.Net 4.0
I've implemented this answer, producing my own CheckBox class complete with an IsChecked DependencyProperty. That property is backed by the IsChecked property on the WPF CheckBox, or would be if it would work. Working would mean my getter and setter are called when the checkbox is toggled.
If I rename my property to IsChecked_temp and modify the XAML to match, it works fine. I think this is a naming conflict, but why doesn't ElementName resolve it? My minimal test case follows.
EDIT 0: I forgot to mention, I get no errors or warnings.
EDIT 1: This answer was initially accepted because it works for the test case, but it's apparently not the entire answer. Applying it to my project (and renaming the CheckBox class to ToggleBox) yields a XamlParseException at every use of the property:
A 'Binding' cannot be set on the 'IsChecked' property of type 'ToggleBox'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
I'll try to get a minimal test case going to show this.
CheckBox.xaml
<UserControl x:Class="CheckBox_test.CheckBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Self">
<StackPanel>
<CheckBox IsChecked="{Binding IsChecked, ElementName=Self}" />
</StackPanel>
</UserControl>
CheckBox.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace CheckBox_test
{
public partial class CheckBox : UserControl
{
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
"IsChecked",
typeof(bool),
typeof(CheckBox),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.AffectsRender));
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
public CheckBox()
{
InitializeComponent();
}
}
}
MainWindow.xaml
<Window x:Class="CheckBox_test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CheckBox_test">
<Grid>
<local:CheckBox />
</Grid>
</Window>
MainWindow.xaml.cs (for completeness)
using System.Windows;
namespace CheckBox_test
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
Very interesting question (at least for me) so it turns out that there is really a conflict of names when you register your Dependency Property.
I'm not exactly sure if this is an answer but I think you'll find this interesting if you didn't knew or thought about it before.
I've used "CheckBox.IsChecked", but any unique name would suffice probably.
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register(
"CheckBox.IsChecked",
typeof(bool),
typeof(CheckBox),
new FrameworkPropertyMetadata(false,
FrameworkPropertyMetadataOptions.AffectsRender));
This works without change in the name of your property
public bool IsChecked
{
get
{
return (bool)GetValue(IsCheckedProperty);
}
set
{
SetValue(IsCheckedProperty, value);
}
}
When you create names for your dependency properties, you must choose
unique names that are not being used for dependency properties or
events in any base classes that you inherit from; otherwise, an
ArgumentException is thrown during runtime. For more information about
dependency properties and activity binding, see Custom Activity
Binding Sample and Simple Activity Sample.
https://msdn.microsoft.com/en-us/library/vstudio/ms734499(v=vs.90).aspx
Yet another reminder how big of a noob I am :)
Is it possible to call a custom dependency property in the XAML of the element in which it is defined?
I mean, i have the following simple code for my mainWindow:
Code
public partial class MainWindow : Window
{
public static readonly DependencyProperty SpecialToProperty = DependencyProperty.Register("SpecialTo", typeof(double), typeof(MainWindow));
public MainWindow()
{
InitializeComponent();
}
public double SpecialTo
{
get
{
return (double)GetValue(SpecialToProperty);
}
set
{
SetValue(DoubleAnimation.ToProperty, value);
}
}
}
How can i use that dependency property from the XAML partial code of the MainWindow class?
I mean something like:
<Window x:Class="WpfAnimationTEst.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
SpecialTo=200>
I know it can be done using attached dependency properties, but is it the only way? Is it not possible to call a dependency property defined in the code-behind?
Thank you and sorry if the question is some kind of stupid, i'm just learning and trying to understand WPF.
I found the answer after I initially posted a wrong answer:
The problem really lies in circular dependencies if you use andreask's answer. I had to create a BaseClass for all windows:
1) Create a new Window Base Class:
public class BaseWindow : Window {
public BaseWindow() { }
public static readonly DependencyProperty SpecialToProperty = DependencyProperty.Register("SpecialTo", typeof(double), typeof(BaseWindow));
public double SpecialTo {
get {
return (double)GetValue(SpecialToProperty);
}
set {
SetValue(SpecialToProperty, value);
}
}
}
This will be the new baseclass for all your windows.
2) Modify your MainWindow xaml: (Change YOURNAMESPACE (2x) to your namespace name)
<local:BaseWindow x:Class="YOURNAMESPACE.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YOURNAMESPACE"
Title="MainWindow" Height="350" Width="525" SpecialTo="100">
<Grid>
</Grid>
</local:BaseWindow>
3) And you also need to modify your partial MainWindow.cs:
public partial class MainWindow : BaseWindow {
public MainWindow() {
InitializeComponent();
}
}
That worked for me, however, you will always need to use the extra xaml markup in your window declaration.
I'm answering my own question because there seems to be many ways to solve it correctly. I've upvoted the answers that best helped me, but i can't set any as the correct answer since all are correct.
So i'll just post a conclusion. If you think that i'm mistaken, please post a comment and i will correct my mind.
The main answer to my question is no, it is not possible to directly call a custom dependency property defined at code-behind from its "linked" XAML file. It is mandatory to instantiate the control in which the property is defined to call it.
To me, the best workarrounds to use a custom dependency property in XAML, defined in the code-behind are the posted by #Clemens and #Noel Widmer. This and this
You can use custom dependency properties in XAML, but only if you instantiate the control in XAML. For example, take a customized TextBox element:
public class MyTextBox : TextBox
{
public static readonly DependencyProperty SpecialToProperty = DependencyProperty.Register("SpecialTo", typeof(double), typeof(MyTextBox));
public double SpecialTo
{
get
{
return (double)GetValue(SpecialToProperty);
}
set
{
SetValue(DoubleAnimation.ToProperty, value);
}
}
}
You can of course create an instance of MyTextBox in XAML and assign the SpecialTo property there:
<custom:MyTextBox SpecialTo="1.0" />
In your case, however, you're not instantiating the custom class MainWindow, but you create a new instance of class Window, and the Window class isn't aware of the custom dependency property (the SpecialTo property is not even available in Window, since you declared it within the MainWindow class).
For the dependency property to be recognized, you'd need to instantiate MainWindow directly:
<custom:MainWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
SpecialTo=200>
However, this means you need to omit the x:class directive that used to combine XAML and codebehind of your window (otherwise you'd run into circular dependencies), and I'm not sure if this correctly initalizes your window...
Yes, it is possible. Dependency properties are used to bind within XAML. If you want to bind to property defined in the code behind window you need to reference this window as XAML element, i.e. add tag for your main window x:Name="mainWindow", and next in the binding expression refer it as ElementName=mainWindow
WPF bindings uses CultureInfo.CurrentUICulture rather than CultureInfo.CurrentCulture which means they do not respect the preferences specified in Control Panel's Region and Language dialog.
To properly implement localisation in a WPF application it is therefore necessary to somehow assign CurrentCulture to the ConverterCulture of every binding.
This is best done with a StaticResource declared in App.xaml but there is a problem: the CultureInfo class has no public constructors. As a result, markup like this
<Application x:Class="ScriptedRoutePlayback.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:glob="clr-namespace:System.Globalization;assembly=mscorlib"
StartupUri="MainWindow.xaml">
<Application.Resources>
<glob:CultureInfo x:Key="CurrentCulture" />
</Application.Resources>
</Application>
generates a warning about the fact that CultureInfo has no public constructors. Despite this, the markup is sufficient to register an appropriately typed static resource in the namespace used by the designer, which stops markup references to {StaticResource CurrentCulture} from complaining in the rest of the app.
At run-time the failure of this markup to create an instance of CultureInfo is irrelevant because the accompanying Startup code assigns it from CultureInfo.CurrentCulture:
using System.Globalization;
using System.Windows;
namespace ScriptedRoutePlayback
{
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Resources["CurrentCulture"] = CultureInfo.CurrentCulture;
}
}
}
Finally, the question:
What is the preferred way to mark up a StaticResource that refers to an existing object such as a singleton obtained from a static property of a class, especially when said class lacks public constructors?
instead of defining a StaticResource, have you tried the x:Static markup extension when referring to CultureInfo.CurrentCulture in your bindings?
http://msdn.microsoft.com/en-us/library/ms742135.aspx
something like:
... {Binding ... ConverterCulture={x:Static glob:CultureInfo.CurrentCulture}}
alternatively, this answer or this answer may offer better alternatives for your situation.
May be there is no point to define resource in XAML.
base.OnStartup(e);
Resources.Add("CurrentCulture", CultureInfo.CurrentCulture);
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" />