How to make loose Xaml content aware of custom controls - wpf

I have a loose XAML file...
<Style
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace"
TargetType="{x:Type local:CustomControl}">
<Setter Property="HoverOpacity" Value="1.0"/>
</Style>
... that I want to load at runtime. When I do I get an exception stating, "Type reference cannot find public type named 'CustomControl'." How can I make the loose XAML aware of my namespace?
I need to use HoverOpacity which is a dependency property of the CustomControl. Here is the code that I am currently using to load the XAML:
var resource = Application.GetResourceStream(new Uri("pack://application:,,,/Assets/HoverStyle.xaml"));
XamlReader.Load(resource.Stream);
BTW, I realize that the XAML is simple and I could just insert the Style in code, but this is a hello world XAML; its going to become a lot more complex, involving animations and such.
P.S. Another solution would be a way of either attaching a XAML file to a custom control derived from Panel (one that doesn't crash Visual Studio 2008) or a way of easily attaching triggers, data-triggers, entry-actions, and exit actions to custom controls.

Gosh darn it, I figured it out. I needed to specify the assembly name with the namespace; like so:
<Style
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace;assembly=MyAssembly"
TargetType="{x:Type local:CustomControl}">
<Setter Property="HoverOpacity" Value="1.0"/>
</Style>
I'll give answer credit to anyone who could answer my "P.S." question within the next two days. This whole situation seems a little wet, so I'd be really interested in alternatives.
Thanks :)

Related

How to correctly reference external xaml styles in a WPF application?

I believe my question is fairly simple and yet I am having difficulty implementing it successfully. I simply wish to extract the styling of elements in my WPF application because the xaml is rather crowded and xaml is often duplicated.
I therefore wish to place the styling in an external xaml file, in the form of a resource dictionary, then reference that file in the resources section of my code.
I have the following .xaml file:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="PTextBox" TargetType="TextBox" x:Name="PTextBox">
<Setter Property="Foreground" Value="#FFA1C8E7"/>
<Setter Property="BorderBrush" Value="#FFA1C8E7"/>
</Style>
And I reference the dictionary here:
<UserControl.Resources>
<ResourceDictionary x:Key="PegasusStyles">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../Resources/Styles/PegasusStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Visual studio has resolved the file location so I know this reference is correct.
The text box the styles are applied to then references the style:
<TextBox Style="{StaticResource PTextBox}"/>
If left as a static resource I get a xaml parse error like so:
An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
And if I make the resource dynamic then the styles simply do not get applied at runtime.
I'm not sure if xaml files require certain properties before run time but mine are as follows:
If someone could answer this mystery it would be wonderful. I googled till my fingers bled but none of the answers posted by others have resolved my issues and this seems very rudimentary.
EDIT: Solved. Switching the build action to Page instead of resource has fixed my issue as suggested by Andrew Stephens. This had been hidden by another underlying problem, which is that I had added a boolean to visibility converter (common tool) to my resources. This alone is fine but once I had declared a resource dictionary this converter needed to be brought inside the dictionary as well.
It sounds like a XAML syntax error somewhere, but can also be caused by an unhandled exception in the main window code-behind (if you have any code in here). There are a few ways to debug this cryptic exception here (read the comments for more tips)
Also the Build Action of your .xaml resource file should be "Page" rather than "Resource".
Try building the solution with your newly merged dictionary before you start referencing the external styles in your xaml.
It may seem counter intuitive but it is possible for visual studio to know about a type in another xaml file without the designer being aware which can cause bugs like this.
Koda

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 set WPF default values for properties, if possible?

I am just starting WPF and it is frustrating the hell out of me. It seems that many properties are null by default (at least those I am working on at the moment) and hence when it compiles and run, nothing happens.
Is there a quick way or a standard workflow procedure to set default values for WPF objects?
For example, I put a Canvas and a Button in XAML view, and then went to code view to add an event handler on the Button to Canvas.Children.Add(new Ellipse()) and then nothing happens. Then I thought maybe I should specify the Width and Height. Still nothing happens. Finally, after much struggling I found the Shape.Stroke property.
Then there is no intuitive Ellipse.X and Ellipse.Y to position the Ellipse. Again, took an hour to find the Canvas.SetLeft().
The final straw is when I try to do Canvas.SetLeft(Random.Next(0, (int)Canvas.Width)); It give a runtime error because Canvas.Width is NULL?!!? Goodness...
Sure, WPF gives a lot of features, but seems like a lot of work coming from a Winforms Graphics.DrawEllipse() .. *sweat*
In WPF if you dont explicitly set the Width/Height in xaml the size will be determined by the Elements layout Container, so to access the Width/Height of an Element like this you use the properties ActualWidth/Actualheight, these return the Rendered size of the Element
Example:
Canvas.SetLeft(Random.Next(0, (int)Canvas.ActualWidth));
If you want to create Default values for a Element you can create a style in xaml for that Element
Example:
<Style TargetType="Ellipse">
<Setter Property="Stroke" Value="Black"/>
</Style>
WPF does have a rough learning curve. One of the tougher things is to dispense somewhat with the techniques you may be used to and embrace the WPF-approach. Xaml is the way to go for defining controls and their properties - Xaml is a language whose only real purpose to do declaration well. In essence, think of the Xaml portion of your code as a glorified constructor.
<Window x:Class="TestWpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window"
Title="MainWindow"
Width="640"
Height="480">
<Canvas>
<Ellipse Canvas.Left="50"
Canvas.Top="50"
Width="142"
Height="88"
Fill="Black" />
</Canvas>
</Window>
The declaration above takes advantage of Xaml's nifty syntax for Attached Properties.
You might want to investigate Styles if you find yourself setting a set of common properties on like objects often.

Information when DynamicResource could not be found during runtime?

In my current project I have a quite large WPF based application with lots of Static and DynamicResources.
Because of many refactorings and changes in the past there are lots of DynamicResources that can not be found during runtime and therefore no value is applied.
What I like to do is run the application and get an output, exception or whatever when a DynamicResource could not be found.
I have tried to build a DefaultTraceListener and a Converter that checks for unused DynamicResources, but to no avail.
Does anyone have a solution for me on how to achieve that?
Example:
<Grid.Resources>
<Style x:Key="myStyle1" TargetType="{x:Type TextBlock}">
<Setter Property="Background" Value="Blue"></Setter>
</Style>
</Grid.Resources>
<StackPanel>
<TextBlock Style="{DynamicResource myStyle1}">DynamicResource exists</TextBlock>
<TextBlock Style="{DynamicResource myStyle3}">DynamicResource does not exist</TextBlock>
</StackPanel>
How can I be informed during runtime that myStyle3 does not exist?
Thanks in advance !
There are many tools that show you witch binding doesn't work..
WPF Inspector is my favorite tool, take a look. WPF Inspector
Snoop utility is one of those. In short - in the top right corner you'll find DropDown list which allows filter visuals, just select Visuals with binding Error. Source: How to locate the source of a binding error?
In Visual Studio, you can enable all exceptions (with binding errors) in the Debug menu, Exceptions, then check everything.
But I don't know if it's exactly what you want, let other people answer this...

Application-level Resources in a Different Assembly

This question involves the Visual Studio (2008) WPF Designer's apparent inability to handle the usage of resources located at the App.xaml level if the App.xaml is in a separate assembly from the view.
To simplify the explanation of the problem I have created a test application. This application has two assemblies: View and Start. The View assembly contains a xaml window called Window1, and the Start assembly includes the App.xaml file. The App.xaml file in the Start assembly has its StartupUri set to the Window1 in the View assembly. Neither of these files have code-behinds (aside from the standard constructors and InitializeComponent() call).
The code for this example is as follows:
App.xaml:
<Application x:Class="Start.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="pack://application:,,,/View;component/Window1.xaml"
>
<Application.Resources>
<!-- Warning Text Style -->
<Style x:Key="WarningTextStyle" TargetType="TextBlock">
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Application.Resources>
Window1.xaml:
<Window x:Class="View.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
Height="300"
Width="300"
>
<Grid>
<TextBlock Text="This is test text" Style="{StaticResource WarningTextStyle}" />
</Grid>
</Window>
The Window1.xaml file contains a single TextBlock that references the App-level WarningTextStyle. This code works fine at runtime because the Window properly finds the App-level resource; however, at design-time the designer complains that it cannot find the WarningTextStyle.
Does anybody know of a clean and scalable solution to this problem?
My standard approach with large applications is to organize my app-level resources into resource dictionary files, and then merge those dictionaries in the App.xaml. To work around the problem that I've described above I have to merge those resource dictionaries into each view's resources. This seems very inefficient, and if I later add another resource dictionary then I need to merge that new dictionary into every view.
A silver bullet solution would re-direct the designer to find the app-level resources. A reasonable work around would be the merging of the app-level resource dictionaries into each view, but only at design-time. At runtime I would like to avoid merging these dictionaries in every view because of the efficiency issues.
I've tried merging the dictionaries on each view in the view's code-behind constructor, and then wrapping that logic in an if statement that checks the DesignerProperties.GetIsInDesignMode() method; however, the Visual Studio designer does not run the view's constructor - so this approach appears to be a bust.
Does anybody have a better solution or work around?
Can you merge the resource dictionary in your referenced assembly (be it App.xaml or your own resource dictionary) from your main (exe) assembly's App.xaml?
I just had a different idea: use a DynamicResource instead of a Static one. This might introduce a tiny performance hit, but I doubt it would be measurable.

Resources