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.
Related
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.
I have a XAMl string table that is working a treat when i need to refer to it from my controls in XAML.
However I could also do with being able to access it for use in other sections of code - such as validation messages in my model. As you cannot add a resource file to a silverlight I beed to use this.
someone must know what i need to call to get at the resource file, preferably strongly typed so intelli-sense can bail out my forgetfulness.
The Resource File definition
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:system="clr-namespace:System;assembly=mscorlib">
<system:String x:Key="test">test</system:String>
</ResourceDictionary>
Instead of listing the strings in XAML, why not using resource files (RESX) directly? This way Visual Studio will create wrappers around your resources using (publicresxfilecodegenerator) and you will be able to get rid of the magic strings, both in code as well as XAML.
You can use the indexer to receive this. Once you have a reference to the resource dictionary, you can use:
string test = (string)resources["test"];
For details, see Referencing Resources from Code.
I'd like to programmatically access static resources much as I would in XAML:
<TextBlock Text="{Binding Source={StaticResource My.Text.Key}}" />
This works whether my static resource is defined on the TextBlock, some parent element (e.g. UserControl) or even the application. It seems that either the StaticResource binding expression knows how to walk up the element tree, or the element itself does. I'd like to do the same thing programmatically:
<UserControl x:Class="MyCustomControl" ...>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources.xaml"/> <!-- Sets 'My.Text.Key' to System.String 'Hello, World!' -->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
</UserControl>
public partial class MyCustomControl
{
public MyCustomControl()
{
InitializeComponent();
string myCustomValue = this.Resources[MyCustomValue] as string; // myCustomValue becomes null!
}
}
Even in this simple test, my resource can't seem to be accessed programmatically. And this is the simplified version of what I was trying to really do: find a static resource via an element that I have a custom dynamic property attached to (e.g. uiElement.Resources[key]).
Despite your comment to the contrary I doubt the use of "." in your resource key is really the source of your problem. In this situation the "." has no special meaning and would not impact how the resource is accessed. (I've tried and failed to reproduce any problem with it).
There is though a very big difference between using the {StaticResource MyName} mark up extension and an attempt to find the resource programmatically.
The markup extension causes the XamlParser to look for the specified key the Resources property of the FrameworkElement to which the property being assigned belongs. If the key is not found it looks for it in the parent FrameworkElement and it keeps going until it reaches the root FrameworkElement. If it is still not found it has a look in the Application's Resources property.
On the other hand this code:-
string myCustomValue = this.Resources[MyCustomValue] as string;
sf just looking in the single Resources property for the user control. No attempt is made to hunt down the key in ancestors or in the application resources. Its a simple Dictionary lookup. This I suspect is what was really tripping you up.
Having said that I would say the using "." in a resource key may not be a good idea. The "." does have meaning in various XAML scenarios already so using it in key names as well has the potential to confuse a developer reading the code even though Silverlight is quite happy with it.
I want to write a POCO in XAML, and use a DataTemplate to display that object in the GUI at runtime. So far, so good; I know how to do all that.
Since I'll already have a DataTemplate that can transform my POCO into a WPF visual tree, is there any way to get the Visual Studio designer to play along, and have the Design View show me the POCO+DataTemplate's resulting GUI, as I edit the POCO's XAML? (Obviously the designer wouldn't know how to edit the "design view"; I wouldn't expect the Toolbox or click-and-drag to work on the design surface. That's fine -- I just want to see a preview as I edit.)
If you're curious, the POCOs in question would be level maps for a game. (At this point, I'm not planning to ship an end-user map editor, so I'll be doing all the editing myself in Visual Studio.) So the XAML isn't WPF GUI objects like Window and UserControl, but it's still not something where I would want to blindly bang out some XAML and hope for the best. I want to see what I'm doing (the GUI map) as I'm doing it.
If I try to make a XAML file whose root is my map object, the designer shows "Intentionally Left Blank - The document root element is not supported by the visual designer." It does this even if I've defined a DataTemplate in App.xaml's <Application.Resources>.
But I know the designer can show my POCO, when it's inside a WPF object. One possible way of accomplishing what I want would be to have a ScratchUserControl that just contains a ContentPresenter, and write my POCO XAML inside that ContentPresenter's Content property, e.g.:
<UserControl ...>
<ContentPresenter>
<ContentPresenter.Content>
<Maps:Map .../>
</ContentPresenter.Content>
</ContentPresenter>
</UserControl>
But then I would have to be sure to copy the content back out into its own file when I was done editing, which seems tedious and error-prone, and I don't like tedious and error-prone. And since I can preview my XAML this way, isn't there some way to do it without the UserControl?
I'm doing this right now, actually. Create a ResourceDictionary and reference it from the other XAML file. For example, make one file containing you plain old object, i.e.:
<Windows:ResourceDictionary>
<Collections:ArrayList x:Key="PreferenceList">
<NumericPreference id="server.port"
helpText="The port on which the server should listen for incoming connections (default is 30588)"
min="1"
max="65535"
step="1"
displayName="Port"
validationName="Port number" />
</Collections:ArrayList>
</Windows:ResourceDictionary>
(where NumericPreference is replaced by your POCO), and then reference it like so:
<UserControl>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Preferences.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<!-- Your code here -->
</Grid>
</UserControl>
... But yes, you'd still need your "scratch user control" hooked up to it to see the designer result, but there's no copying and pasting involved. The key part here is the ResourceDictionary Source="YourStaticResource.xaml"
You can't have the map as the root element (the root element must be ResourceDictionary), but you can have it as the only child element of the ResourceDictionary.
To reference the resource, use, of course {StaticResource XXX} or {DynamicResource XXX} where XXX is the x:Key you gave the POCO in its XML file (in this case I gave the referenced POCO object, the ArrayList, the "PreferenceList" key)
I'm fairly certain that you aren't going to get what you want here.
WPF won't process much in the way of logic in the design window. That includes (for the most part) DataTemplate and IValueConverter objects that you use in your XAML data bindings, since those objects usually work with (POCO) objects that are not instantiated until run-time.
This could explain why it works in the UserControl example, since you ARE clearly creating an instance of your Map POCO right there in the XAML. The designer window absolutely will not attempt to render anything that is based on bindings or templates that refer to objects that Visual Studio can't instantiate at design-time. This basically means that you can't have your objects show up in the design window if you are trying to create those objects in your C# (or whatever) code behind the scenes. Your back-end code cannot be run by the design window, because it has to be built by the compiler and run before any of it can execute. (Previous versions of Visual Studio use extreme workarounds to try and remedy this, and Microsoft no longer provides this support.) Markup languages like XAML don't have that restriction since they contain no logical execution sequence, so the design window can render them on the screen using only the parsed XAML markup.
In a nut-shell, I don't think the XAML design window was ever intended to be used the way you are trying to use it.
If you really want to be able to see your POCO in the designer, but you don't want to have to insert it into a UserControl with a ContentPresenter --- try deriving your POCO from an appropriate root-element that the designer can render, and adding a Serialize method to read/write it to/from files.
If these solutions don't work for you, then you are probably going to have to deal with Visual Studio not rendering your Map objects in the design window. Maybe this will give you some motivation to create that stand-alone map editor after all, even if you don't ship it out to the end-user. You may want to spend the time to write a simple editor, even if it's for your use only. Visual Studio won't replace your custom map editor - at least, not in any way that will be useful to you.
How do you bind resources string to Xaml in Silverlight?
You need to add this reference to the App.xaml
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Then you need to add the string into the <Application.Resources> section
<sys:String x:Key="ResourceString">Resource String</clr:String>
Then all you need to do is refer to *{StaticResource ResourceString}
for example:
<TextBlock Text="{StaticResource ResourceString}"></TextBlock>
Been a while since this was asked and answered, I just wanted to add an additional answer as the first one is not entirely correct. I think he's asking for resources, aka. text written in .resx files. It doesn't make sense at all to add individual strings into the StaticResources collection in the application.
I blogged recently on how to simplify the way you work with resources in Silverlight, enabling both automatic update when the culture changes and a dependency property which gives you simpler syntax.
http://sondreb.com/blog/post/Simplifying-Text-Resources-in-Silverlight.aspx