Embedding one WPF app into another - Resource file not working - wpf

I have a requirement to embed one of our existing applications in our new one. I figured it would be quite easy, so I set made all the content of the origional application inside a UserControl "EmbeddedApp", with the theme applied in it's resources:
<UserControl x:Class="App.GUI.Window.EmbeddedApp"
...>
<UserControl.Resources>
<ResourceDictionary Source="/App;component/GUI/Themes/Theme.xaml" />
</UserControl.Resources>
...all the app stuff...
</UserControl>
And the window for this as a stand alone app then just looked like this:
<Controls:MetroWindow x:Class="App.MainWindow"
...>
<Window:EmbeddedApp/>
</Controls:MetroWindow>
Nice and easy. I tested the "embedding" function in a test application in that project and it works fine.
However, I'm getting resource issues when I embed it into a "full" application like this. There's an exception "Exception: Cannot find resource named 'AccentSelectedColorBrush'. Resource names are case sensitive." on line:
<Rectangle Name ="container" Grid.Row="0" Height="50" Fill="Black" Stroke="{StaticResource AccentSelectedColorBrush}"/>
in the depths of the embedded App. How could this be happening if this is defined in a static resource in Theme.xaml? Why would it work fine in an "empty" application?
I tried adding the theme manually:
Now, Here AccentSelectedColorBrush is found for the rectangle. However, I'm still getting the error AccentSelectedColorBrush not found within EmbeddedApp, it's also White - which isn't as it's defined in Theme.xaml.I can inspect it and the rectangle is resolving it fine:
If I remove the Theme.xaml, AccentSelectedColorBrush is not found.
Edit: I now have this:
<UserControl x:Class="MyNewApp.Pages.Views.EmbeddedAppView"
InheritanceBehavior="SkipAllNow"
...>
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/App;component/GUI/Themes/Theme.xaml" />
<!--<ResourceDictionary Source="pack://application:,,,/App;component/GUI/Themes/Theme2.xaml" />-->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<StackPanel Height="447" Width="539">
<Rectangle Width="100" Height="100" Fill="{StaticResource AccentSelectedColorBrush}"/>
<!--<App:EmbeddedApp Width="300" Height="300"/>-->
<Label Content="Texty Text"/>
<TextBox Text="Some Text"/>
<CheckBox IsChecked="True" Content="Test"/>
</StackPanel>
</UserControl>
Now, I'd expect the label and TextBox to be styled acording to Theme.xaml, but it's not doing that it's just using the default themes:
Yet in my "test" project, the Theme.xaml is applied fine:
So my conclusion is that:
<ResourceDictionary Source="/App;component/GUI/Themes/Theme.xaml" />
is not correct for an externally referenced project. I tried:
<ResourceDictionary Source="pack://application:,,,/App;component/GUI/Themes/Theme.xaml" />
but that has similar failure. It's definately finding it though, if I misspell and say put "Theme2.xaml" it comes up with an error. But for some reason it's not being applied properly.
Edit2 I've tracked down the problem to how resources are referenced between user controls. I've decided to create a new question that focuses on the actual problem at hand:
"Sub" UserControl cannot find resource - how to get resources to "flow" down the visual tree (without placing it in App resources)

Related

Only last icon in XAML shown when icon used from resources

when I try to use a material design icon from the icon pack that is defined in the ResourceDictionary, only the first icon in XAML is rendered at run time. I've followed an example that can be found here.
Example follows:
App.xaml:
<Application x:Class="TestWpf.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TestWpf"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<materialDesign:BundledTheme BaseTheme="Light" PrimaryColor="DeepPurple" SecondaryColor="Lime" />
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
<ResourceDictionary Source="pack://application:,,,/TestWpf;component/Dictionary1.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Dictionary1.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes">
<materialDesign:PackIcon x:Key="CashIcon" Kind="Cash" />
</ResourceDictionary>
MainWindow.xaml:
<Window x:Class="TestWpf.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800">
<StackPanel>
<Button Content="{DynamicResource CashIcon}" />
<Button Content="{DynamicResource CashIcon}" />
<Button Content="{DynamicResource CashIcon}" />
</StackPanel>
</Window>
And the result is a window that looks like this:
In xaml editor all buttons have icons on them, as expected:
Why is this happening and, more important, how to fix this?
P.S. We've found out that if you create two Cash icons in the ResourceDictionary and apply each to a button, then they will both be shown but again, only once, you can't have say 3 buttons and 2 icons in ResourceDictionary.
one more solution is to use a non-shared resource (x:Shared Microsoft docs)
<materialDesign:PackIcon x:Key="CashIcon" Kind="Cash" x:Shared="False"/>
x:Shared Attribute: When set to false, modifies WPF resource-retrieval behavior so that requests for the attributed resource create a new instance for each request instead of sharing the same instance for all requests.
A scenario for x:Shared="false" is if you define a FrameworkElement or FrameworkContentElement derived class as a resource and then you introduce the element resource into a content model. x:Shared="false" enables an element resource to be introduced multiple times in the same collection (such as a UIElementCollection). Without x:Shared="false" this is invalid because the collection enforces uniqueness of its contents. However, the x:Shared="false" behavior creates another identical instance of the resource instead of returning the same instance.
The PackIcon type is a Control. An element in the visual tree in WPF can only have a single parent. In other words, the pack icon is still a single instance added as child of the first button, then moved to the second, then to the third. You will in fact have to create multiple instances of the pack icon.
Instead of creating resources, you could use the PackIcon markup extension.
<StackPanel>
<Button Content="{materialDesign:PackIcon Cash}"/>
<Button Content="{materialDesign:PackIcon Cash}"/>
<Button Content="{materialDesign:PackIcon Cash}"/>
</StackPanel>
Depending on your actual scenario, you could alternatively create a DataTemplate, which will automatically create instances of the pack icons for each button.
<DataTemplate x:Key="CashPackIconTemplate">
<materialDesign:PackIcon Kind="Cash" />
</DataTemplate>
<StackPanel>
<Button ContentTemplate="{StaticResource CashPackIconTemplate}"/>
<Button ContentTemplate="{StaticResource CashPackIconTemplate}"/>
<Button ContentTemplate="{StaticResource CashPackIconTemplate}"/>
</StackPanel>

Why do resource files "disappear" from the WPF Designer when referenced from a Window?

Stackoverflow has other similar questions, but they seem to be related to usage in multiple assemblies or with the formatting of ResourceDictionary Source values. This question relates to single assemblies and the tests listed at the end demonstrate the Source value works as-is.
The following describes a small test application that illustrates the issue.
The test application has a style XAML file (MyStyle.xaml):
<ResourceDictionary
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<SolidColorBrush x:Key="FontColorKey" Color="DarkBlue" />
</ResourceDictionary>
Which is used in a UserControl (PanelChoice.xaml):
<ToggleButton
x:Class="PanelNS.PanelChoice"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="30" Width="100" Background="Orange"
>
<ToggleButton.Resources>
<ResourceDictionary >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Styles/MyStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="FontColorKey" Color="Yellow" />
</ResourceDictionary>
</ToggleButton.Resources>
<TextBlock
Foreground="{StaticResource FontColorKey}"
Background="Pink" Text="Testing"
/>
</ToggleButton>
Which, in turn, is used on a test Window (MainWindow.xaml):
<Window x:Class="IncludeStyleTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PanelNS"
Title="MainWindow" Height="200" Width="200"
>
<Grid Background="Green">
<local:PanelChoice />
</Grid>
</Window>
Tests to isolate this issue:
This code compiles and when run displays green, orange and pink rectangles with yellow text in the middle (as expected).
Viewing PanelChoice.xaml in the XAML Designer shows orange and pink rectangles with yellow text in the middle (as expected).
However, viewing MainWindow.xaml in the designer shows Cannot create an instance of "PanelChoice" and lists Cannot locate resource 'styles/mystyle.xaml'. in the Visual Studio Error List pane.
If the <ResourceDictionary Source="/Styles/MyStyle.xaml"/> line in PanelChoice.xaml is removed (or commented out) and the project rebuilt, then viewing MainWindow.xaml in the designer shows green, orange and pink rectangles with yellow text in the middle and no error messages. It behaves as #1 when run.
To verify that MyStyle.xaml is properly referenced one can remove the <SolidColorBrush x:Key="FontColorKey" Color="Yellow" /> line in PanelChoice.xaml instead of removing MyStyle.xaml. This case behaves just as #1, but the text is dark blue instead of yellow. This demonstrates that MyStyle.xaml is properly referenced and is accessible.
NOTE: Visual Studio 2015 and 2017 both exhibit this behavior.
Take out the leading / in the .xaml reference so that it looks like this instead:
<ResourceDictionary Source="Styles/MyStyle.xaml"/>
The control is then able to be displayed properly in the Window when in the designer.
Another way to get it to show properly is to use the full physical path (you wouldn't do it this way, but just demonstrating the behaviour) e.g.:
<ResourceDictionary Source="\Users\colin.smith\Documents\visual studio 2017\Projects\WpfApp15\WpfApp15\Styles\MyStyle.xaml"/>
Yey another way that works:
<ResourceDictionary Source="/WpfApp15;component/Styles/MyStyle.xaml"/>
If you use the property picker to select the Source for your ResourceDictionary it does not put a leading / at the start of the Source when referring to the MyStyle.xaml that is in your Styles folder.
The issue seems to be with the designer. When it's providing a design surface which has to "include" another control which you have created in "the same" project, it must be doing something wrong when referring to those ResourceDictionaries with leading / paths.
Another way to get it to work...
If you move/create your "controls" in a separate "User Control" or "Custom Control" library, then you will be using a "pack" reference to refer to the resources...and the Window will be able to display that control properly in the designer.
I'm sure you can find an example of creating user controls in their own library...but will quickly show what it would kinda look like.
<ToggleButton
x:Class="WpfControlLibrary1
.PanelChoice"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="30" Width="100" Background="Orange"
>
<ToggleButton.Resources>
<ResourceDictionary >
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/WpfControlLibrary1;component/Styles/MyStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
<SolidColorBrush x:Key="FontColorKey" Color="Yellow" />
</ResourceDictionary>
</ToggleButton.Resources>
<TextBlock
Foreground="{StaticResource FontColorKey}"
Background="Pink" Text="Testing"
/>
</ToggleButton>
Then add reference to your WpfControlLibrary1 library, and use:
<Window x:Class="WpfApp15.MainWindow"
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:local="clr-namespace:WpfApp15"
xmlns:controls="clr-namespace:WpfControlLibrary1;assembly=WpfControlLibrary1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid Background="Green">
<controls:PanelChoice />
</Grid>
</Window>

Cannot see FontAwesome Icons on Parent Window

Summary -- I cannot see FontAwesome icons in the designer when looking at my MainWindow.xaml view that includes a control that has the FontAwesome icons in it.
We are using Visual Studio 2012 to develop a WPF application using Simple MVVM. In our application, we use FontAwesome for most of our icons. I created a resources library that has a reference to FontAwesome (AppStyles.xaml).
Here is an excerpt from my AppStyles.xaml file that references FontAwesome.
<Style x:Key="FontAwesome" TargetType="Control">
<Setter Property="FontFamily" Value="/Fonts/#FontAwesome" />
</Style>
I have created a HeaderView.xaml view that shows a toolbar of options the user can select from. Example of one of the buttons the user can click is below.
<Button Command="{Binding ShowStartScreenAction}">
<Button.Template>
<ControlTemplate>
<StackPanel Orientation="Horizontal" Margin="0">
<Label Content="" Style="{StaticResource FontAwesomeLabel}" />
<Label Content="Home" Style="{StaticResource ButtonLabel}" />
</StackPanel>
</ControlTemplate>
</Button.Template>
</Button>
On the HeaderView.xaml view, the FontAwesome icons show up correctly (). A house in this case.
In my MainWindow.xaml view, I have the HeaderView.xaml view added as a control.
<ctrls:HeaderView Grid.Row="0" Grid.ColumnSpan="2" />
The problem I am having is that the FontAwesome does not show up correctly on MainWindow when I view it in the Designer, so I cannot see how the HeaderView.xaml and all my other controls look together inside MainWindow.
Here is my reference in MainWindow.xaml to my resources library where the FontAwesome reference is.
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources;component/Styles/AppStyles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
The application runs fine, but it would be nice to be able to see what I have in the designer without having to run the application to see it every time. Can someone help?

Visual Studio 2010 - Dictionary Not found but it exists

Well, I´m developing a wpf application and I got a strange error on design time. This is the code of a wpf form:
<Window x:Class="ViewLayer.Frm_EnrollWaitingList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Frm_EnrollWaitingList" WindowStartupLocation="CenterScreen" BorderBrush="{x:Null}" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Height="390" Width="410"
WindowStyle="None"
AllowsTransparency="True"
ResizeMode="NoResize">
<Window.Resources>
<ResourceDictionary Source="Dictionary/WaitingListDictorionary.xaml"/>
</Window.Resources>
<Grid>
<Rectangle Margin="0,0,0,0" Name="rectangle1" Stroke="{x:Null}" Fill="#FF8C90AD" Opacity="0.95" />
<Button Style="{DynamicResource CommonButton}" Content="Salir" Height="80" HorizontalAlignment="Left" Margin="166,234,0,0" Name="btn_close" VerticalAlignment="Top" Width="180" />
</Grid>
</Window>
The problem starts here:
<Window.Resources>
<ResourceDictionary Source="Dictionary/WaitingListDictorionary.xaml"/>
</Window.Resources>
The ResourceDictionary exits and in execution time it works perfectly. But at design time sometime when a want to modify the form in visual studio designer i get the following error:
FileNotFoundException An error occurred while finding the resource dictionary "Dictionary/WaitingListDictorionary.xaml".
Unable to find the specified file.
at Microsoft.Windows.Design.Platform.ViewProducerBase.Microsoft.Expression.DesignModel.DocumentModel.IDocumentRootResolver.GetDocumentRoot(String path)
at Microsoft.Expression.Platform.WPF.InstanceBuilders.ResourceDictionaryInstanceBuilder.ProvideResourceDictionary(IInstanceBuilderContext context, DocumentCompositeNode resourceDictionaryReferenceNode, IDocumentRoot& relatedRoot)
And I can not edit the form with the designer.
Any idea? I repeat on execution time I have no problems.
The Source property is relative, and you window appears to be in the ViewLayer directory, so the Dictionary folder must also be in the ViewLayer directory if you use
Source="Dictionary/WaitingListDictorionary.xaml".
If the Dicionary folder is at the root level, try
Source="/Dictionary/WaitingListDictorionary.xaml".
You can also use a pack:// URL.
I could figure it out!
There was an error on the ResourceDictionary I was trying to use. I fixed it, and voila! Everything works like a charm.

"Resource with the name {Locator} cannot be found" Error when using mvvm-light user control

i am using the mvvm light toolkit to create a WPF application. I created a user control and a corresponding ViewModel. I created a ViewModel property in the ViewModelLocator. I bound the user controls datacontext to the property in the Locator class. When i edit the User Control in Blend or the VS Designer everything seems to work, since i can see my design time data.
When i now try to use my user control on the main window, which is created by the wpf template of the toolkit i receive the error "Resource with the name {Locator} cannot be found" and the row with my user control in the mainwindow.xaml is marked with a red line in Blend. In Visual Studio the same line is marked with the error: "Cannot create an instance of type MyView".
Edit:
This is the source code of the app.xaml
<Application.Resources>
<!--Global View Model Locator-->
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="True">
</Application.Resources>
This is the code of the EditCustomerView.xaml
<UserControl.DataContext>
<Binding Path="EditCustomer" Source="{StaticResource Locator}" />
</UserControl.DataContext>
This is the code in my main Window
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Skins/MainSkin.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Window.DataContext>
<Binding Path="Main" Source="{StaticResource Locator}"/>
</Window.DataContext>
<Grid x:Name="LayoutRoot" Background="{DynamicResource BasicBackground}">
<Grid.RowDefinitions>
<RowDefinition Height="0.927*"/>
<RowDefinition Height="0.073*"/>
</Grid.RowDefinitions>
<ListBox Margin="4" SelectedItem="{Binding Main.SelectedCustomer, Mode=Default, Source={StaticResource Locator}}" ItemTemplate="{DynamicResource CustomerTemplate}" ItemsSource="{Binding Customers, Mode=Default}"/>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="75" Content="Edit" Grid.Row="1" Command="{Binding EditCustomerCommand, Mode=Default}"/>
<Border x:Name="border" Opacity="0.75" Grid.RowSpan="2" Background="#FF706F6F" BorderBrush="Black" BorderThickness="1" Visibility="{Binding EditViewVisibility, Mode=Default}">
<views:EditCustomerView HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</Grid>
The application compiles and runs. The error is only occuring during design time.
Can you tell me what i am doing wrong?
Thank you in advance.
This is a known issue. Blend for some reason doesn't recognize the static global resource.
As a workaround you can create a local resource of ViewModelLocator in your Views.
<Window.Resources>
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="True">
</Window.Resources>
You have to include the ViewModel namespace.
The issue is reported in codeplex here
and in stackoverflow here
Seems it is resolved in Blend 4
I've come up with a pretty nice workaround to this problem since it doesn't appear to have been fixed in Blend 4:
In the constructor for your XAML UserControl just add the resources it needs, provided you're in design mode within Blend :
public partial class OrdersControl : UserControl
{
public OrdersControl()
{
// MUST do this BEFORE InitializeComponent()
if (DesignerProperties.GetIsInDesignMode(this))
{
if (AppDomain.CurrentDomain.BaseDirectory.Contains("Blend 4"))
{
// load styles resources
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri(System.IO.Path.Combine(Environment.CurrentDirectory, "Resources/Styles.xaml"), UriKind.Absolute);
Resources.MergedDictionaries.Add(rd);
// load any other resources this control needs such as Converters
Resources.Add("booleanNOTConverter", new BooleanNOTConverter());
}
}
// initialize component
this.InitializeComponent();
}
There may be some edge cases, but its working OK for me in the simple cases where before I'd get a big red error symbol. I'd LOVE to see suggestions on how to better solve this problem, but this at least allows me to animate user controls that otherwise are appearing as errors.
You could also extract out the creation of resources to App.xaml.cs:
internal static void CreateStaticResourcesForDesigner(Control element)
{
if (AppDomain.CurrentDomain.BaseDirectory.Contains("Blend 4"))
{
// load styles resources
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri(System.IO.Path.Combine(Environment.CurrentDirectory, "Resources/Styles.xaml"), UriKind.Absolute);
element.Resources.MergedDictionaries.Add(rd);
// load any other resources this control needs
element.Resources.Add("booleanNOTConverter", new BooleanNOTConverter());
}
}
and then in the control do this BEFORE InitializeComponent():
// create local resources
if (DesignerProperties.GetIsInDesignMode(this))
{
App.CreateStaticResourcesForDesigner(this);
}
This is hard to diagnose without seeing the code, but let me take a stab at it anyway.
It sounds like the problem is the wiring up of your Locator. Make sure you have the following code in your App.xaml
<Application.Resources>
<local:NameOfMyViewModelLocatorClass x:Key="Locator" />
</Application.Resources>
This should wire everything together.
Well to remove the issue even at design time you need to include the following condition in the constructor of ViewModelLocator:
if (ViewModelBase.IsInDesignModeStatic)
{
}
else
{
//Include function to create ViewModel here like the following
CreateMain();
}
Hopefully this would resolve the issue.

Resources