Trouble adding a DataTemplateSelector to a wpf XAML - wpf

This is my first time ever doing anything with XAML and I'm a bit lost.
I'm trying to add a DataTemplateSelector to my XAML page using the instructions found here.
However I'm stuck on the part where I'm supposed to "declare the TaskListDataTemplateSelector as a resource". This is the example given:
<Window.Resources>
...
<local:TaskListDataTemplateSelector x:Key="myDataTemplateSelector"/>
...
</Window.Resources>
However, the top level tag in the XAML document is <UserControl>, and I don't see anything about Window or Window.Resources.
Under the <UserControl> tag is a <UserControl.Resources> tag, but when I try to put the example code there, it gives me an error saying "The namespace prefix 'local' is not defined". I tried replacing "local" with the actual namespace, but got the same error.
The custom DataTemplateSelector class is in the codebehind for the XAML page, and is in the same namespace.

For anyone who googled this question like I did:
I think I found the answer.
You need to define the local prefix in your XAML file.
This can be done by placing the following namespace argument in the root element:
xmlns:local="clr-namespace:AssemblyName"
Change "AssemblyName" in your erm.. assembly's name.

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 can I localize Page.WindowTitle?

I'm creating a WPF wizard control following the MSDN Structured Navigation example. My working XAML looks like this, where my WizardBase is a subclass of System.Windows.Navigation.PageFunction, and MyPageOne is a subclass of WizardBase (namespaces and class names changed for privacy):
<local:WizardBase
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:My.Namespace"
x:Class="My.Namespace.MyPageOne"
KeepAlive="True"
WindowTitle="Page One">
This works great: when I navigate to this page in the wizard, the dialog title changes to "Page One". But now I want to internationalize that string. So I changed it to:
WindowTitle="{Binding Source={x:Static local:LocalizedStrings.PageOneTitle}}"
which fails at runtime with:
A 'Binding' cannot be set on the 'WindowTitle' property of type 'MyPageOne'. A 'Binding' can only be set on a DependencyProperty of a DependencyObject.
What's special about WindowTitle that it can be set but not bound? I'm assuming that I've just made some kind of novice error.
Oh, duh, it's really easy. I just want:
WindowTitle="{x:Static local:LocalizedStrings.PageOneTitle}"
That is, set it directly rather than applying via a binding. I was making it way too complicated...

Silverlight: Access XAML control from code

I'm having a problem accessing a Panel control defined on the XAML of a page, the XAML is defined this way:
<UserControl
x:Class="PhoneBook.SilverlightMainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
mc:Ignorable="d" Width="400" Height="300" d:DesignWidth="993" d:DesignHeight="887">
<Grid x:Name="LayoutRoot" />
</UserControl>
The class is defined like this:
public partial class SilverlightMainPage : UserControl
{
public SilverlightMainPage()
{
InitializeComponent();
}
}
And I'm trying to instantiate it this way:
var silverlightMainPage = new PhoneBook.SilverlightMainPage();
SomeMethod((silverlightMainPage.LayoutRoot);
What I find strange is that when I put the dot after the object instance, it actually list LayoutRoot as one of the members, but when I try to compile the application it says that there's no member with that name.
Any ideas of what can be hapenning?
Thanks
EDIT: I also tried creating a property on the SilverlightMainPage class that returned the LayoutRoot element, but it also says that the class doesn't contain a definition for Layout root.
Is there any chance that you're trying to access SilverlightMainPage.LayoutRoot from a different assembly? In the MainPage.g.i.cs file, LayoutRoot (and all other controls defined in XAML) are marked "internal", i.e.:
internal System.Windows.Controls.Grid LayoutRoot;
You might want to try creating a public rather than an internal property that does a FindName("LayoutRoot") and returns the appropriate control.
Actually I found the problem.
I was generating the project automatically with a tool built by someone else in the company.
I did some extra tests and added a new UserControl to the project and tried to access the LayoutRoot from a property in the code behind, and it worked.
Then copied the exact same code to the file with the problem (just changing the class name) and it didn't compile.
Then I checked the project file, and found a section like this:
<ItemGroup>
<Compile Include="SilverlightMainPage.xaml.cs">
<DependentUpon>SilverlightMainPage.xaml</DependentUpon>
</Compile>
</ItemGroup>
Which for some reason was causing the compilation to fail.
I removed that section and now everything works fine.
Thanks for your answers though.

WPF UserControl cannot find XAML resource in referencing project

In my WPF project i keep a user control in a separate library project. The user control accesses resources in a separate XAML file, like this:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources/ViewResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Local styles here -->
</ResourceDictionary>
</UserControl.Resources>
The resource file, ViewResources.xaml, resides in a folder in the control library project named Resources. It has the default build action (Page) and custom tool (MSBuild:Compile).
The problem is when I reference the control library in my WPF application and use the user control. At runtime, I get the following XamlParseException:
Set property 'System.Windows.ResourceDictionary.Source' threw an exception.
...which wraps the IOException:
Cannot locate resource 'resources/viewresources.xaml'.
How can I fix this? I have tried to change the resource file's build action to "content" and have it copied to the output directory (that works for files and similar "dumb" resources). But to no avail. Also, it doesn't work property in the user control then.
Is there a better way to specify the path?
Will I have to move the resource file to the application project (I'd rather not, as it belongs in the user control's domain).
Found it.
Turns out there is a better way to specify the path, Pack URIs. I changed the XAML to the following:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/RoutingManager;component/Resources/ViewResources.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Local styles here -->
</ResourceDictionary>
</UserControl.Resources>
and that fixed it.
I thought it was worth posting this just in case anyone else is struggling with the same problem, as I've spent over two hours fighting with syntax, etc. only to find that the solution was dead simple, but not that apparent:
When referencing a packed resource from another control library, it seems to work fine at design time, and even compiles without error, but fails at runtime with the 'Set property 'System.Windows.ResourceDictionary.Source' threw an exception' error. It turns out that simply referencing the resource assembly from your control library is not enough, you ALSO need to add a REFERENCE to the assembly containing the resource dictionary in you main application assembly, else it seems it does not get compiled into the application. (i.e. Startup Application (the one with app.xaml) -> Add Reference -> select assembly with referenced resource file/s).
Hope this helps!
In my case I had the ResourceDictionary and the UserControl on the same Library, but separate from the main application. What worked for me was specifying the name of the assembly in the format Adam suggested in the comment AND I had to change the ResourceDictionary in the project from Embedded Resource to Page. I didn't try using the pack:// format, but I assume it would work too.
<ResourceDictionary Source="/AssemblyName;component/Assets/MyResource.xaml"/>
I had the same error (IOException - file not found), which cost me a day of my life that I'll never get back.
Using neither the simpler "/assemblyname..." nor the "pack://...." syntax worked for me.
I was referencing the resource assembly in my main assembly correctly.
The error disappeared when I changed my xaml resource file Build Action property to "Resource", as mentioned above.
However, I then encountered a XamlParseException at this line:
<ImageBrush x:Key="WindowBackground" ImageSource="Images/gradient.png" />
(which I had hand-typed).
This left the xaml resource file I was trying to include with effectively an invalid dependency.
Oddly the fix was to delete the ImageSource property I had typed, re-insert it BUT select the image from the pulldown menus that appear as a result.
Even though the resulting line appears exactly the same, it clearly isn't.
Starting to dislike WPF (VS2013), but hope this helps.
:0/
I had the same situation, but the Pack URIs didn't help me, I was still getting "Cannot locate resource..." exception in the referencing (executable) project. What helped me, was the setting of my ResourceDictionary files in the custom control library project as Embedded Resource.

wpf custom control not recognized

This is my first foray into custom controls, and it's not going well. I have a custom graph control derived from Canvas.
namespace Grapher2 {
public class SeriesManager : Canvas {
public SeriesManager() {
...
}
}
}
It's defined in the same project and namespace as my app. I tried adding a reference to the control in XAML as follows:
<Window x:Class="Grapher2.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:graph="clr-namespace:Grapher2"
Title="Grapher" Width="800" Height="600">
<StackPanel Name="container" Width="700" Height="500">
<graph:SeriesManager Name="seriesManager" Width="700" Height="500" />
</StackPanel>
But when I try to reference the control name "seriesManager" in the code-behind for the Window, I get "The name 'seriesManager' does not exist in the current context."
Furthermore, the XAML editor will not render the Window, giving a huge stack trace with the error: "Type 'MS.Internal.Permissions.UserInitiatedNavigationPermission' in Assembly 'PresentationFramework, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' is not marked as serializable."
I imagine the solution is something stupidly simple for anyone who's done custom controls. But I'm stumped.
did you try x:Name="seriesManager" in your xaml?
Edit: This may not be the issue seeing how you said your xaml isn't rendering. I'm guessing once you get the xaml to render in the designer... the code behind will work better.
Edit 2: Whenever I've had a problem with the designer rendering, it's because I'm doing something in the constructor of my custom control. Check your SeriesManager to see if you are doing something in its constructor that is causing a problem. Maybe you are referencing something that doesn't exist yet. If you do have extra code in your constructor, consider moving it to the UserControl_Loaded event.
Backing up Scott's answer here, since he helped me solve it:
What I did wrong was trying to access the control BEFORE InitializeComponent(), but was confused by 2 other error messages somewhere else in the code.
Just in case someone else has this error.

Resources