IOException when referencing App.xaml's ResourceDictionary - wpf

I'm trying to reference App.xaml's ResourceDictionary from a separate WPF window. I want to use resources from there in different windows, and this seems like the recommended way to do it. Unfortunately, I don't seem to be able to effectively reference App.xaml from the other window. Here is my App.xaml:
<Application x:Class="View.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ViewModel="clr-namespace:ViewModel;assembly=ViewModel"
xmlns:local="clr-namespace:View"
StartupUri="ClockView.xaml">
<Application.Resources>
<ResourceDictionary>
<local:PriorityToIconConverter x:Key="PriorityToIconConverter" />
</ResourceDictionary>
</Application.Resources>
Notes: I'm not using MainWindow, so I've replaced the startup URI with a form that always comes up. I noted that in some other answers, the location of MainWindow is sometimes the issue. In my case, I haven't seen any difference between using ClockView or MainWindow. Both ClockView and MainWindow exist in the root namespace, MainWindow is just never loaded. I also have more resources, but I've removed them for the sake of conciseness.
Here's a simplified example of the code where I'm trying to reference the ResrouceDictionary from App.xaml:
<local:AssistantWindow
x:Class="View.AutomatorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:properties="clr-namespace:View.Properties"
xmlns:local="clr-namespace:View"
mc:Ignorable="d"
Title="Tool"
x:Name="Tool"
Background="Transparent"
Height="600"
Width="450"
Topmost="{Binding Source={x:Static properties:Settings.Default}, Path=ToolAlwaysOnTop}"
MinHeight="515"
MinWidth="150">
<Window.Resources>
<ResourceDictionary Source="App.xaml" />
</Window.Resources>
Again, this is simplified to be concise. When I try to load this form, I get the exception:
System.Windows.Markup.XamlParseException: ''Set property 'System.Windows.ResourceDictionary.Source' threw an exception.' Line number '21' and line position '10'.'
Inner Exception
IOException: Cannot locate resource 'tool/app.xaml'.
The view for "Tool" is located in a folder that is also named "Tool." However, the xaml and code behind don't reference this namespace, I'm just using the folder to organize my classes. It looks like it's looking for App.xaml in the folder the view resides in. App.xaml resides in the root namespace (View). I've tried modifying the source in the xaml for Tool to:
- View.App.xaml
- View:App.xaml
- View/App.xaml
How can I get this reference to work, so I can share resources throughout my application? Thank you.

You can't load App.xaml like you're trying to do because it's not actually a ResourceDictionary. You can only specify ResourceDictionary files as the target of Source.
However, if you declare a resource in App.xaml, you can reference it anywhere without needing to load the file it's in. That's done for you automatically. Therefore, you can reference your converter at any time with {StaticResource PriorityToIconConverter}.
Note that if you moved it from the default starting location (the base project folder) you may have to update its location. Right click your project, then Properties. Navigate to the "Application" tab (should be the uppermost element on the left-hand sidebar) and look for the "Startup object" field. Set that to [ProjectName].[Namespace?].[Namespace?].App. When I tested it, mine worked without needing to manually change the location, but your setup may be different.

Related

windowsformhost cant load a usercontrol from another dll

So I have a dll from another project which contains many useful classes and controls for me (lets call it foo.dll). I'm making an WPF app. I need to use some of them in my app. I created my usercontrol for windows forms and referenced UserControlForMe from foo.dll. It's shown, all good. Now I want to insert my usercontrol into a wpf form. It looks like this:
<UserControl x:Class="FlatRectangular_Profile.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
xmlns:uc="clr-namespace:FlatRectangular_Profile.UC"
Height="2093" Width="717">
<Grid Name="grid">
<WindowsFormsHost>
<uc:WindowsFormsProfManual ></uc:WindowsFormsProfManual>
</WindowsFormsHost>
</Grid>
</UserControl>
But here I get an error "cant load type UserControlForMe from foo.dll". No info on that error. Again, UserControlForMe loads in WindowsFormsProfManual. All these is going on in one class library. I referenced everything that foo.dll needed.
No idea how what to do next. I also tried to load it in code in usercontrol.loaded event, but it fails too, and shows stacktrace which leads to the constructor of the UserControlForMe.
I guess you'll have to add the assembly to your namespace import to point your application in the right direction:
xmlns:uc="clr-namespace:FlatRectangular_Profile.UC;Assembly=MyDLL"
I found a workaround since I cant get why it is not working. If I load a UserControlForMe from foo.dll directly to the windowsformhost, it works. But if there is a "buffer" dll, it works in this dll, but doesnt open in futher window. Also I add a UserControlForMe programmatically to a windowsformhost.

WPF pack:/[assemblyName];component/... vs pack://application:,,,/[assemblyName];component/...?

I came across this oddity while trying to resolve issues using merged ResourceDictionaries in a WPF app I'm working on.
I have custom controls (TextButton, MenuButton) and resources (colors, brushes, control styles and custom control templates) defined in an external DLL ("common"). In another library I have a user control that uses these styles ("pluginA").
As long as I was working with the standard WPF controls (TextBlock, Button, Grid etc.) - I could apply the styles from the "common" dll without any problems. The designer would pick up the style and apply it correctly.
If I plop in one of the custom controls (TextButton) into the User Control in "pluginA" - the designer would find the custom control, but couldn't resolve the type for the style to be applied (Type reference cannot find the type named '{clr-namespace:Common}TextButton').
The xmlns declaration in my usercontrol looks like this:
<UserControl x:Class="PluginA.Views.LeftBarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:core="clr-namespace:Common.Core;assembly=Common"
xmlns:common="clr-namespace:Common;assembly=Common"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<core:SharedResourceDictionary Source="/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
With this definition, the designer doesn't apply any styles - but it works in runtime. Great, but not quite that helpful as I don't want to run the application to see if a minor tweak took effect.
So I tried this:
<core:SharedResourceDictionary Source="pack://application:,,,/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />
But that didn't change anything (designer still wouldn't find the resources). In the process of changing the code, I got to this:
<core:SharedResourceDictionary Source="pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />
Now the designer is happy and can find the resources - runtime is happy and displays the resources, and yet I can't find any description of this being a valid PACK URI... Can anyone explain why this would work?
pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml
This is technically a valid URI, but it is not a valid pack URI. Parsing it according to the rules of the pack format would yield:
Package URI: <empty>
Part URI: /Common;component/Resources/DefaultTheme/DefaultTheme.xaml
In effect, you have made an absolute URI out of a part URI by appending the pack: scheme. However, without a well-formed package component, the result is not a valid pack URI. And, interestingly, the Uri class will not actually parse the original string as an absolute URI; it is parsed incorrectly as a relative URI, and that is part of the reason it works when assigned to ResourceDictionary.Source. Let's take a look at the property setter:
public Uri Source
{
get { return _source; }
set
{
// ...
_source = value;
Clear();
Uri uri = BindUriHelper.GetResolvedUri(_baseUri, _source);
WebRequest request = WpfWebRequestHelper.CreateRequest(uri);
// ...
}
The key lies within BindUriHelper.GetResolvedUri(_baseUri, _source). The logic there, which differs from much of the pack URI handling in WPF, sees that _source is not an absolute URI (at least according to the broken Uri class), so it attempts to combine it with the resolved base URI, which we presume to be pack://application:,,,/. The URIs are combined via new Uri(Uri baseUri, Uri relativeUri), which works only because Uri incorrectly parsed the original string as a relative URI. The URI which ultimately gets used to create the WebRequest is equivalent to:
new Uri(
new Uri("pack://application:,,,/"),
new Uri("pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml"))
...which produces:
pack://application:,,,/Common;component/Resources/DefaultTheme/DefaultTheme.xaml
And viola, we end up loading the resources from a valid pack URI even though we gave it an invalid one.
We know that the "bad" URI works because it gets accidentally transformed into a good one. As to why that same "good" URI not work in the designer when it's used directly, that is very curious.
Perhaps you simply need to rebuild both the Common project and the project that is attempting to merge the resource dictionary. If it still fails, then it's possible your UserControl.Resources has a different BaseUri when running in the designer than it does at runtime. Let's see if we can figure out what the BaseUri is at design time. Modify your UserControl as follows:
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
...
xmlns:m="clr-namespace:System.Windows.Markup;assembly=System.Xaml"
x:Name="Root">
<UserControl.Resources>
<ResourceDictionary">
<Style x:Key="BaseUriTextStyle" TargetType="TextBlock">
<Setter Property="Text"
Value="{Binding ElementName=Root,
Path=Resources.(m:IUriContext.BaseUri)}" />
</Style>
</ResourceDictionary>
</UserControl.Resources>
<TextBlock Style="{StaticResource BaseUriTextStyle}" />
</UserControl>
See what gets displayed in the designer. It may give us a clue.

Setting design time DataContext on a Window is giving a compiler error?

I have the following XAML below for the main window in my WPF application, I am trying to set the design time d:DataContext below, which I can successfully do for all my various UserControls, but it gives me this error when I try to do it on the window...
Error 1 The property 'DataContext' must be in the default namespace or in the element namespace 'http://schemas.microsoft.com/winfx/2006/xaml/presentation'. Line 8 Position 9. C:\dev\bplus\PMT\src\UI\MainWindow.xaml 8 9 UI
<Window x:Class="BenchmarkPlus.PMT.UI.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:UI="clr-namespace:BenchmarkPlus.PMT.UI"
xmlns:Controls="clr-namespace:BenchmarkPlus.PMT.UI.Controls"
d:DataContext="{d:DesignInstance Type=UI:MainViewModel, IsDesignTimeCreatable=True}"
Title="MainWindow" Height="1000" Width="1600" Background="#FF7A7C82">
<Grid>
<!-- Content Here -->
</grid>
</Window>
I needed to add the mc:Ignorable="d" attribute to the Window tag. Essentially I learned something new. The d: namespace prefix that Expression Blend/Visual Studio designer acknowledges is actually ignored/"commented out" by the real compiler/xaml parser!
<Window
...
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
...
/>
The following was taken from
Nathan, Adam (2010-06-04). WPF 4 Unleashed (Kindle Locations 1799-1811). Sams. Kindle Edition.
Markup Compatibility
The markup compatibility XML namespace (http://schemas.openxmlformats.org/markup-compatibility/2006, typically used with an mc prefix) contains an Ignorable attribute that instructs XAML processors to ignore all elements/attributes in specified namespaces if they can’t be resolved to their .NET types/members. (The namespace also has a ProcessContent attribute that overrides Ignorable for specific types inside the ignored namespaces.)
Expression Blend takes advantage of this feature to do things like add design-time properties to XAML content that can be ignored at runtime.
mc:Ignorable can be given a space-delimited list of namespaces, and mc:ProcessContent can be given a space-delimited list of elements. When XamlXmlReader encounters ignorable content that can’t be resolved, it doesn’t report any nodes for it. If the ignorable content can be resolved, it will be reported normally. So consumers don’t need to do anything special to handle markup compatibility correctly.
Wow, what a pain! Let's hope MS puts in some VS design-time support for x:Bind.
We to be able to use the VS designer but also be able to switch easily to x:Bind instead of Binding. Here's what I did:
In my View, I added a property to get my ViewModel. This makes sense because x:Bind paths are relative to the Page (i.e. the View object).
In my Page XAML, I added the following to the <Page ... > at the top of the XAML:
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MyView, IsDesignTimeCreatable=False}"
DataContext="{x:Bind}"
This way, the Page's actual data context is set to the Page itself due to the {x:Bind}. That's because x:Bind is relative to the Page and there is no path given.
At the same time, due to the d:DataContext line, the VS designer reflects on the MyView class (without creating an instance) for the purpose of the VS designer interaction. This lets VS design from MyView, where you can then scroll down to the ViewModel property, expand it and select the item that you want to bind to.
When you do all that, the VS designer will create a Binding statement whose path is relative to the View, i.e. it happens to be exactly the same as the path that x:Bind expects. So, if you want to switch to x:Bind later on, you can just search and replace all "{Binding" with "{x:Bind".
Why do we even need the d:DataContext line to tell VS what class to look at? Good question, since you would think that VS could figure out the very next line sets the DataContext to the Page, using DataContext={x:Bind}. Go ahead and try it, it does not work and neither does it work if you change x:Bind to Binding relative to self.
Hopefully this situation will get cleaned up by MS !!
If you are not tooo fussy on the data have a look at the sample data found in xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
You use it like this...
<ItemsControl ItemsSource="{Binding Path=Report.Audit.Data}" d:ItemsSource="{d:SampleData}" Grid.Row="1">
<ItemsControl.ItemTemplate>
<DataTemplate>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
it then renders the items control with a few rows of data
I've solved the problem adding d:DataContext="{d:SampleData}" in the component definition (UserControl or Window).
<UserControl x:Class="TestControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:TestApp.Views"
DataContext="{Binding TestViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:SampleData}"
>

How can i make a prefix so i can address a folder in xaml

I always have problems making new prefixes in xaml. Most of the time, i get the message that the URI cannot be found in the assembly. My setup:
I have a WPF project (in a solution with class libs and asp.NET projects) with a MainWindow.xaml file. The XAML starts with : Window x:Class="MainWindow" ... .
So as default, there's no namespace given to it. In that same project i made a folder "Folder". In that folder, i have resx-files. What i need to do is make a prefix in xaml so i can address those files. I was thinking of :
xmlns:p="clr-namespace:WpfApplication.Folder"
and then for my controls
<Label Content="{x:Static p:NameResxFile.KeyName></Label>
However, the prefix generates the "URI cannot be found in the assembly" error. I'm i just failing at making prefixes?
Thanks in advance.
EDIT
If you cannot make a namespace ref to a folder, what is happening here?
xmlns specifies namespaces, it does not bother with folders or files, if you need access to an external resource you can load it into your control's resources via ResourceDictionary.
There was something like this i think:
<Window.Resources>
<ResourceDictionary x:Key="ExternalRes" Source="Folder/File.xaml"/>
....
</Window.Resources>
To reference an element of resource dictionary you should add that dictionary to your control's Resources collection or register it in the App.xaml file. After that you could just use StaticResource extension to get access to the element. Your code will look like this:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Folder/NameResxFile.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<!-- ... -->
<Label Content="{StaticResource KeyName}"/>
Things get trickier if you want to put the resource dictionary to another assembly and reference it. For this purpose refer to PackURIs in WPF article.

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