Write markup extension as nested element - wpf

Is it possible to write markup extension as nested element rather than attribute? I am trying to use Boolean as key for ResourceDictionary entries.
Current code where ResourceDictionary key type is string:
<UserControl.Resources>
<my:ObjectToResourceConverter x:Key="StatusConverter">
<ResourceDictionary>
<BitmapImage x:Key="True" UriSource="/TestProject;/Resources/Open.png"/>
<BitmapImage x:Key="False" UriSource="/TestProject;/Resources/Closed.png" />
</ResourceDictionary>
</my:ObjectToResourceConverter>
</UserControl.Resources>
Desired code but doesn't compile due to:
Unrecognized tag x:Key
XAML
...
<BitmapImage UriSource="/TestProject;/Resources/Open.png">
<x:Key>
<x:Boolean>True</x:Boolean>
</x:Key>
</BitmapImage>
...

Well, yes, you usually can declare markup extensions with element syntax, but x:Key is actually a directive, not a markup extension. As described here, x:Key does not support element syntax in XAML 2006. If you use XAML 2009 it does, but it's unlikely that you are (or would want to).
But even if you could that, it wouldn't help, because (in XAML 2006; XAML 2009 might be different, didn't check) the key of a resource dictionary can only be set using string, x:Type, or x:Static. So for your case, you would need to define a static property that produces false, and set that as the key using x:Static.
Edit The part about only supporting string, x:Type, and x:Static is not completely true. I was too trusting of the compiler error message (which says 'Only String, TypeExtension, and StaticExtension are supported.'). There is at least one other supported key type: ComponentResourceKey. There may be more I'm forgetting or of which I am unaware. But in any case, arbitrary markup extensions (like a custom-defined one that returns a boolean) are not supported.

Related

What does the <vm:SimpleViewModel x:Key="viewModel"/> mean in WPF?

I am new to WPF and MVVM, actually started just a week back and I am trying to code up an application using both WPF and MVVM, while coding up an example I came across the following statement <vm:SimpleViewModel x:Key="viewModel"/> and I am trying to reason about it. I understand what 'x:' refers to, its the default XAML namespace mentioned in the XAML file and I have created a namespace for my own ViewModel class that the UI will be interacting with and I have given it an alias "vm" and SimpleViewModel is the ViewModel for my application, the statement for the purposes of reference is xmlns:vm="clr-namespace:MVVM_Tutorial".
My Reasoning for the statement <vm:SimpleViewModel x:Key="viewModel"/> is that a Window is a XAML element and has a resource dictionary that it refers to resolve and refer to certain elements, hence inside its resource dictionary which is defined in the "x:" namespace we are assigning a variable called "Key" whose value is the SimpleViewModel class defined in the "vm:" namespace. Just want to know if I am right with my reasoning or is there something that I am missing and would want to know proceeding further from here.
XAML is just markup that describes an object graph. Code is also markup that describes an object graph. I can say this
var window = new Window();
window.DataContext = new MyNamespace.MyViewModel();
or I can write the exact same thing like this
<Window xmlns:blahblah="clr-namespace:Normal.Xmlns.Deleted.For.Brevity"
xmlns:this="clr-namespace:MyNamespace">
<Window.DataContext>
<this:MyViewModel />
<!-- snip -->
Any object that can be instantiated in code can be used in xaml. There are some restrictions (e.g., default public constructor without arguments), but for the most part this is true. XAML just defines an object graph that is deserialized at runtime.
Since any type can be referred to in xaml, you could, hypothetically, have moved that instance of MyViewModel to a resource dictionary and referred to it via a StaticResource or a DynamicResource. Note, anything you put in a resource dictionary has to have a key, assigned via x:Key:
<Window xmlns:blahblah="clr-namespace:Normal.Xmlns.Deleted.For.Brevity"
xmlns:this="clr-namespace:MyNamespace"
DataContext="{DynamicResource lolderp}">
<Window.Resources>
<this:MyViewModel x:Key="lolderp" />
<!-- snip -->
XAML is a subset of XML, and uses XML namespaces to map to code namespaces in the current, or other, assemblies. It's how the framework knows what object MyViewModel refers to. To learn more, read this link on msdn.
I'm sure someone else can chime in with more clarification...
In the xaml file, the references of
"xmlns:[something]="clr-namespace:[yourProjectOrLibrary]".
Since your code-behind can be verbose with long name space references, and your SOLUTION may be made up of multiple projects (such as different DLLs), when the XAML is processed, it uses the "xmlns" as a reference to whatever "yourProjectOrLibrary" is... In your case the project/class "MVVM_Tutorial".
Now, the "vm". This is just an "alias" within the xaml, so anytime it is referencing a
The xaml knows where it originates to get resolution to control, properties, types, etc.
As for the "x:Key" part... Not positive, but when I was first building out my customized themes, also ran into confusion about the x:Key. My interpretation of this was found to be x:Key is like a private reference, but by being given the name ..x:Key="viewModel"... is making this "name" available later within the xaml file.
This "key" can then be referenced later in the xaml... For example,
<ControlTemplate x:Key="CTButton" TargetType="{x:Type Button}" >
<!-- Start border of button to have a rounded corners -->
</ControlTemplate>
Then later within the theme, I could reference this "Key"... in my case "CTButton". So if I wanted multiple controls to use / derive from same control template, I could have them reference it...
<someControl>
<Style>
<Setter Property="Template" Value="{StaticResource CTButton}" />
</Style>
</someControl
Again, I don't get EVERYTHING about all the xaml markup, but hopefully clarifies this for you some.

How to declare/define variable in pure XAML without code-behind

Please consider the following XAML markup (App.xaml file in Visual Studio 2010):
<Application x:Class="UpdateTrigger.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:UpdateTrigger"
xmlns:clr="clr-namespace:System;assembly=mscorlib"
StartupUri="MainWindow.xaml">
<Application.Resources>
<clr:String x:Key="MyString">My string</clr:String>
</Application.Resources>
</Application>
Can I write into MyString much like a variable in a C# program? That is what I am trying to do: I am trying to declare and define a variable through pure XAML, without any code-behind. Is this possible?
CLARIFICATION EDIT:
If I bind MyString, for example, to a TextBox in XAML, can a user type into that TextBox? I tried, but have not been able to do this.
Is it possible to bind to and modify a resource object? Yes and no. You can do it but the object needs to be mutable, so can't be a value type like an Int32 or Boolean, or String which is an immutable reference type. The object also needs to have some property that is being modified (the Path of the Binding) - you can't replace the entire object itself.
The more important question is probably, should you do this. The answer to that is usually no but there can be cases where it can sometimes be useful, for example, declaring a ViewModel instance directly in the View XAML to provide easy designer support. In general it's almost always better to be binding to objects that are part of your code so they can easily interact with other parts of your program without relying on runtime resource lookups. If you have data that's staying in the view, like a TextBlock that just mirrors the value of a TextBox, it's usually better just to bind them directly together with an ElementName Binding rather than adding an extra middleman.

How to specify default datatemplate as static resource in XAML

I have a default template defined for one of my classes. It works correctly and is applied as I'd expect, but I am using an attached property (detailed here, actually) for which I have to specify a DataTemplate. I have been unable to find an acceptable way of specifying my default template in XAML.
My data template looks something like this:
<DataTemplate DataType="{x:Type myNS:MyType}">
....
</DataTemplate>
So far I have attempted to specify it like this
attached:property.MyDataTemplate="{StaticResource {x:Type myNS:MyType}}"
but this throws an exception at runtime ("Cannot find resource named 'My.Full.NameSpace.MyType'. Resource names are case sensitive.").
I've done enough looking around to know that other people have similar problems but I haven't been able to find a decent solution. I am considering simply maintaining a duplicate DataTemplate with an x:Key so I can point at it. Is there a better way?
UPDATE:
Alright - it's been pointed out that this does work if you use DynamicResource instead of StaticResource. This does not make sense to me.
I've read a fair bit on DynamicResource vs StaticResource (among other thing, I read this thread). Here's what I do know:
If I specified a x:Key instead of a DataType I can use this template as a StaticResource.
When the page loads the template is in the dictionary and can be retrieved in code
var myTemplate = this.Resources[new DataTemplateKey(typeof(MyType))];
Can anyone explain what's happening here?
Give this a try: (Switch StaticResource to DynamicResource)
attached:property.MyDataTemplate="{DynamicResource {x:Type myNS:MyType}}"
My guess for the reason why this works:
This answer gives a good difference between StaticResource and DynamicResource. I'm guessing this Default template data isn't available when StaticResource tries to retrieve it(during the loading of the XAML) which isn't the case for DynamicResource
I guess, the problem because of your DataTemplate has DataTemplateKey with type myNS:MyType, but property.MyDataTemplate="{StaticResource {x:Type myNS:MyType}}" tries to find resource with string key matching your type full name.
Instead of using "{StaticResource {x:Type myNS:MyType}}" you should use:
"{StaticResource {DataTemplateKey {x:Type myNS:MyType}}}"
or its full equivalent:
"{StaticResource ResourceKey={DataTemplateKey DataType={x:Type myNS:MyType}}}".
Also, you don't need DynamicResource in this case.

What are XAML markup extensions?

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).

WPF styles: difference between x:Name and x:Type

While defining style in resource dictionary you can use either
x:Name="xyz"
and
x:Type="xyz".
and can reference this style in XAML like {StaticResource xyz}.
Most examples use 'x:Key', and the difference between 'name' and 'key' is that using 'x:name' lets you use this style definition code-behind?
FIXES:
The question is totally wrong. What was intended to be asked was the difference between x:Key and x:Name. But didn't go trying this code myself, but was just relying on memories - thought I have both in ResourceDictionary, which was wrong. And I also didn't have such code in
<xxx.Resources >
sections, since it doesn't work either. You can't reference Style that doesn't have x:Key (x:Name doesn't work here), and adding two styles without x:Key throws exception since both get the same (empty?) key in dictionary.
Ray puts all the difference in a very nice way, thanks.
My fault
This is a trick question. In fact, you cannot define a style in a ResourceDictionary using either
x:Type="xyz"
or
x:Name="xyz"
Here is the difference:
x:Type="xyz" is not valid XAML syntax.
x:Name="xyz" is actually valid XAML syntax that names an object (which affects the generation of code-behind) but does not provide a dictionary key.
x:Key="xyz" is also valid XAML syntax that provides a dictionary key but does not name an object.
In a dictionary a key is required, so you must specify x:Key (except that for FrameworkTemplate and its subclasses the key can be inferred from the TargetType or DataType). In a dictionary you may also specify x:Name if desired but it does not affect the key.
Note that x:Type is a markup extension that is predefined by XAML, whereas x:Name and x:Key are actual XAML keywords. So x:Type can only be used in markup extension syntax as the value of a property:
something="{x:Type whatever}"
whereas x:Name and x:Key are attributes that can be used on elements.
x:Name allows you to create a reference that you can use by name.
x:type allows you to create a reference that is used by that type
for instance
<Style TargetType="{x:Type Button}">
...
</Style>
creates a style that will automatically affect buttons

Resources