In my WPF application I use value converters from Catel framework. For convenience they derive from MarkupExtensionand return themselves from ProvideValue so I can just write {Binding Converter={catel:BooleanToCollapsingVisibilityConverter}} instead of adding them to a resource dictionary.
In some cases I have very long converter properties, so it is more convenient to put them into a resource dictionary like <UserControl.Resources><catel:BooleanToCollapsingVisibilityConverter x:Key="MyConverter" Link="..."/></UserControl.Resources> and reference them as a StaticResource. But when I do so, the project fails to compile with the following error: The name 'InitializeComponent' does not exist in the current context.
Is there a way to store such objects in resource dictionaries?
As a workaround I can inherit from desired value converter and put initialization code into a constructor, but this is not as convenient.
Related
I tried reading the MSDN article on markup extensions, but I can’t find out what they are (the article discusses what they do).
I cannot find a clear explanation of why we need markup extensions. If we can access a control object directly, why would we need a markup extension to access a binding object?
Do we need markup extensions so XAML is aware of the code behind (otherwise there is no way to get access any of the built in classes)? But then how can we access all the control types?
Markup extensions are not about access but extending functionality of markup (as the name implies) by doing whatever you want them to, like creating associations (Binding, x:Reference) or getting the type of a class (x:Type).
They can be used for just about anything, they are only necessary where the markup does not suffice on its own.
Rationale for markup extensions:
XAML is simple, which is a good thing. It is just an XML-based
language used to declare objects and the relationships between them.
One side effect of being simple is that it can be verbose. This
cumbersome verbosity was one of the main reasons why the concept of
markup extensions was introduced. A markup extension can be used to
turn many lines of XAML into one concise expression...
Another side effect of XAML’s simplicity is that it does not have any
“built in” knowledge of common artifacts used by WPF or the CLR; such
as resource references, data binding, a null value, arrays, static
members of a class, etc. Since XAML can be an integral part of
application development there needs to be some way for developers to
express those ideas in it.
<TextBox >
<TextBox.Text>A text in TextBox</TextBox.Text>
</TextBox>
<TextBox Text="{x:Static system:Environment.UserName}" />
This latter syntax also provides a way to use values other than a literal string (i.e., which is a new object) such as an already constructed object or a static object in our assembly. In this sense markup extensions are objects which decide
how a property's going to be set at runtime.
From https://wpftutorial.net/XAML.html:
Markup extensions are dynamic placeholders for attribute values in
XAML. They resolve the value of a property at runtime.
Markup
extensions are surrouded by curly braces (Example:
Background="{StaticResource NormalBackgroundBrush}").
WPF has some
built-in markup extensions, but you can write your own, by deriving
from MarkupExtension. These are the built-in markup extensions:
Binding
To bind the values of two properties together.
StaticResource
One time lookup of a resource entry
DynamicResource
Auto updating lookup of a resource entry
TemplateBinding
To bind a property of a control template to a dependency property of
the control
x:Static
Resolve the value of a static property.
x:Null
Return null
The first identifier within a pair of curly braces is the name of the extension. All preciding identifiers are named parameters in the
form of Property=Value. The following example shows a label whose
Content is bound to the Text of the textbox. When you type a text into
the text box, the text property changes and the binding markup
extension automatically updates the content of the label.
<TextBox x:Name="textBox"/>
<Label Content="{Binding Text, ElementName=textBox}"/>
Regarding what a markup extension is composed of:
All markup extensions derive from the abstract MarkupExtension class
and override its ProvideValue method. The naming convention is to
append the word Extension to the subclass’s name (only the Binding
class does not follow the pattern).
The XAML parser allows markup
extensions to be created within {curly braces} and it also allows you
to omit the Extension suffix when using a markup extension, if you
want to.
Example code:
<!--- Configure a binding markup extension via the special curly brace syntax --->
<TextBox Text="{Binding Path=Name}" Width="120"/>
<!--- Configure a binding markup extension via the standard element syntax --->
<Checkbox Content="Is person alive?">
<Checkbox.IsChecked>
<Binding Path="IsAlive"/>
</Checkbox.IsChecked>
</Checkbox>
In the XAML above, take a look at the TextBox’s Text property, and the
CheckBox’s IsChecked property. They both use the Binding markup
extension to bind their values to a property on the data context (a
Person object).
I'm writing markup extension. I have XAML like this
<TextBlock Text="{ui:Test SomeInfo}" />
and TestExtension with constructor taking one string argument. I'm getting "SomeInfo" string so everything is find. Now I want to nest extensions and write something like
<TextBlock Text="{ui:Test {Binding PropName}}" />
and it does not work as is. I had to add constructor which takes one argument of System.Windows.Data.Binding type.
Now I need to know
How should I retrieve a current value from the Binding object?
When should I do this? Should I subscribe to changes some way or ask for that value every time in ProvideValue method?
Update1 PropName should be resolved against DataContext of TextBlock.
Update2 Just found related question: How do I resolve the value of a databinding?
Bindings like this will not work because your MarkupExtension has no DataContext and it does not appear in the visual tree and i do not think you are supposed to interact with binding objects directly. Do you really need this extension? Maybe you could make do with the binding alone and a converter?
If not you could create a dedicated class which has bindable properties (by inheriting from DependencyObject), this however would still not give you a DataContext or namescope needed for ElementName or a visual tree needed for RelativeSource, so the only way to make a binding work in that situation is by using a Source (e.g. set it to a StaticResource). This is hardly ideal.
Also note that if you do not directly set a binding the ProvideValue method will only be called once, this means that even if you have a binding in your extension it may not prove very useful (with some exceptions, e.g. when returning complex content, like e.g. an ItemsControl which uses the binding, but you set the extension on TextBlock.Text which is just a string), so i really doubt that you want to use a MarkupExtension like this if the value should change dynamically based on the binding. As noted earlier: Consider converters or MultiBindings for various values instead.
I see a lot statements like
<TextBox x:Name="txtInput" />
or like
<BooleanToVisibilityConverter x:Key="boolToVis" />
Why the x: is needed and what it gives me.
<DockPanel.Resources>
<c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
And here we have also the c:
Thanks for help
It is nothing more than shortcuts to the different namespaces for XML. You can choose them as you like. If you look at the upper lines in your XAML you will find the line:
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Change the 'x' to 'wpf' for instance and you will see that you need to change all the 'x:' prefixes in your code to 'wpf:' to make it compile.
The 'c:' prefix references code of your own. Say you have a class library that compiles to MyLib.dll. This library contains a class named MyData. To be able to reference the MyData class you need something like:
xmlns:c="clr-namespace:MyClasses;assembly=MyLib"
in your XAML header.
You can then reference the MyData class in you XAML with c:MyData. But you are entirely free to change the 'c' to 'myfabulousclasses' or anything else you fancy.
The purpose of this? To distinguish classes or members that have the same name, but belong to different dll's.
The x: Prefix
In the previous root element example, the prefix x: was used to map the XAML namespace http://schemas.microsoft.com/winfx/2006/xaml, which is the dedicated XAML namespace that supports XAML language constructs. This x: prefix is used for mapping this XAML namespace in the templates for projects. The XAML namespace for the XAML language contain several programming constructs that you will use very frequently in your XAML. The following is a listing of the most common x: prefix programming constructs you will use:
x:Key: Sets a unique key for each resource in a ResourceDictionary (or similar dictionary concepts in other frameworks). x:Key will probably account for 90% of the x: usages you will see in a typical WPF application's markup.
x:Class: Specifies the CLR namespace and class name for the class that provides code-behind for a XAML page. You must have such a class to support code-behind per the WPF programming model, and therefore you almost always see x: mapped, even if there are no resources.
x:Name: Specifies a run-time object name for the instance that exists in run-time code after an object element is processed. In general, you will frequently use a WPF-defined equivalent property for x:Name. Such properties map specifically to a CLR backing property and are thus more convenient for application programming, where you frequently use run time code to find the named elements from initialized XAML. The most common such property is FrameworkElement.Name. You might still use x:Name when the equivalent WPF framework-level Name property is not supported in a particular type. This occurs in certain animation scenarios.
x:Static: Enables a reference that returns a static value that is not otherwise a XAML-compatible property.
x:Type: Constructs a Type reference based on a type name. This is used to specify attributes that take Type, such as Style.TargetType, although frequently the property has native string-to-Type conversion in such a way that the x:Type markup extension usage is optional.
http://msdn.microsoft.com/en-us/library/ms752059.aspx
http://msdn.microsoft.com/en-us/library/ms753327.aspx
It is part of a namespace. In your example the c: prefix is used to indicate that the MyData tag belongs to this namespace. You may take a look at the following article on MSDN which explains the x: prefix in XAML.
I am new in Silverlight.
When I add some control to my xaml file with Visual Studio it set controls name with Name property, but there is also x:Name.
Is there any difference and when to use each of them?
Thanks.
In Brief
Yes there is a difference. The bottom line is that x:Name can be used on object elements that do not have Name properties of their own.
A longer explanation
You can only use Name on an element that represents an object that actually does have a Name property. For example anything that derives from FrameworkElement.
The x:Name attribute may be placed on any element that represents an object regardless of whether that object actually has a Name property. If the object does have a Name property then the value of x:Name will be assigned to it hence you can't have both x:Name and Name on the same element.
When an object has a Name property or an x:Name property the value of that property is associated with the objects entry in the object tree. It is via the object tree that the FindName method of a FrameworkElement can find an object. FindName can find objects by name even if that object does not carry a Name property of its own since it uses the name recorded in the object tree.
The autogenerated code for a UserControl will contain field definitions for any element that that has a Name or x:Name property. The InitialiseComponent method that is generated will use the FindName method to assign values to these fields.
Example
The above Xaml creates two fields LayoutRoot of type Grid and MyBrush of type SolidColorBrush. If you were to change x:Name="LayoutRoot" to Name="LayoutRoot" that would change nothing. Grid has a Name property. However try changing x:Name="MyBrush" to Name="MyBrush". That doesn't work because SolidColorBrush doesn't have a name property. With the above Xaml you can then do code like this:-
public MainPage()
{
InitializeComponent();
MyBrush.Color = Colors.LightGray;
}
Open the definition of InitializeComponent and take a look at the auto generated code.
No, you just can't use them both. x:Name is what the XAML preprocessor actually uses and Name is just a convience property provided on the FrameworkElement class to set it.
From the MSDN reference:
If Name is available as a property on an element, Name and x:Name can be used interchangeably, but an error results if both attributes are specified on the same element.
Short answer: if you're writing stuff out in XAML, it's probably best to just use x:Name consistently.
Long answer: A previous answer mentioned that Name is a "convienience" property for accessing x:Name. That's correct. However, now that the tools environment for XAML in both Visual Studio and the Expression series has really matured and you are seeing more and more tool-generated XAML, you are also probably seeing more and more x:Name as opposed to Name. The tools prefer x:Name because that way they don't take a somewhat risky dependency (potentially specific to framework) re: how x:Name and Name are really the same, and they don't need to flipflop between setting Name if something happens to be a FrameworkElement and then x:Name on something like a Storyboard and generating a duality if you were to look at this XAML through something like a DOM. In other words, the "Name" attribute in XAML really is a lot less "convenient" to use nowadays than might have been conceived of in the original API design. Part of the "convenience" was to not have to map x:, but you have to do that anyways for x:Class and by now pretty much everyone has gotten used to using x: attributes and the general principles of XAML markup effectively.
I'm not sure of the statement made by the original poster that VS encourages using Name. Yes, Name appears as an intellisense option, but so does x:Name. And all the cases I see in the templates where an object is given a starting name are using x:Name even tho most of these are FrameworkElements.
I'm using the new d:DesignInstance feature of the 4.0 series WPF tools. Works great!
Only issue I'm having is: how can I set properties on the instance? Given something like this:
<Grid d:DataContext="{d:DesignInstance plugin:SamplePendingChangesViewModel, IsDesignTimeCreatable=True}"/>
How can I set properties on the viewmodel, aside from setting them in its default ctor or routing it through some other object initializer?
I gave this a try but VS gives errors on compile "d:DataContext was not found":
<Grid>
<d:DataContext>
<d:DesignInstance IsDesignTimeCreatable="True">
<plugin:SamplePendingChangesViewModel ActiveTagIndex="2"/>
</d:DesignInstance>
</d:DataContext>
For the moment I'm going back to using a resource and 'd:DataContext={StaticResource SampleData}', where I can set the properties in the resource.
Is there a way to do it via a d:DesignInstance?
As #jberger you should probably use d:DesignData instead of inlining a d:DataContext.
However you can set the d:DataContext inline in the xaml file as well, the secret is to use the correct class (DesignProperties) to qualify the d:DataContext property:
<d:DesignProperties.DataContext>
<plugin:SamplePendingChangesViewModel ActiveTagIndex="2"/>
</d:DesignProperties.DataContext>
How do you know what class to qualify with? Mouse over a property that is set in attribute syntax and a tooltip will appear with the fully qualified property name.
Note also that im not using the d:DesignInstance markup exstension as its job specifically is to create a instance of a type that you provide the name for (or generate a proxy of that type if it cant be instanciated at design-time). Thats not what we want, we want to define the instance in inline xaml in this case.
Indeed, d:DesignData (also a markup extension) works much the same way, except that it looks for a xaml file and deserializes that to the actual instance to use instead of just using the default constructor.
Just for completeness i should also mention that you can use DesignData and DesignInstance with element syntax as well by using their full class names (xxxExtension):
<d:DesignProperties.DataContext>
<d:DesignDataExtension Source="SampleData.xaml"></d:DesignDataExtension>
</d:DesignProperties.DataContext>
This is true for most markup exstensions but its not required to follow this naming convension (The Binding class is a notable exception) More info can be found here:
Markup Extensions and WPF XAML