WPF ToastNotifications from wpf class library does not load Resources - c#

I am developing a plugin and I want to use this notification toast library from nuget: Toast Notifications
One of the steps I have to do to setup the Toast Notifications library is this:
2 Import ToastNotifications.Messages theme in App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/ToastNotifications.Messages;component/Themes/Default.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
However, I don't have an Application file since I am developing a class library. I have added the resourcer Dictionary to the UserControl that is creating the notifications. Like this:
<UserControl.Resources>
<ResourceDictionary Source="pack://application:,,,/ToastNotifications.Messages;component/Themes/Default.xaml" />
</UserControl.Resources>
However, when I run the App I've got this exception:
{System.Windows.Markup.XamlParseException: Provide value on 'System.Windows.StaticResourceExtension' threw an exception. ---> System.Exception: Cannot find resource named 'InformationIcon'. Resource names are case sensitive.
But InformationIcon is an image inside the ToastNotifications library. What am I doing wrong?

Your problem is the main application that uses your plugin does not have a reference to the nuget package. So, you have two methods to solve this:
If you have access to the main application's project add the nuget lib to it.
If you do not. You have to load the assembly dynamically at runtime. Here is a good solution How to reference a DLL on runtime?
It searches through dlls in a given directory and finds classes that implement a particular interface. Below is the class I used to do this:
public class PlugInFactory<T>
{
public T CreatePlugin(string path)
{
foreach (string file in Directory.GetFiles(path, "*.dll"))
{
foreach (Type assemblyType in Assembly.LoadFrom(file).GetTypes())
{
Type interfaceType = assemblyType.GetInterface(typeof(T).FullName);
if (interfaceType != null)
{
return (T)Activator.CreateInstance(assemblyType);
}
}
}
return default(T);
}
}
All you have to do is initialize this class with something like this:
PlugInFactory<InterfaceToSearchFor> loader = new PlugInFactory<InterfaceToSearchFor>();
InterfaceToSearchFor instanceOfInterface = loader.CreatePlugin(AppDomain.CurrentDomain.BaseDirectory);

Related

System.UriFormatException: 'Invalid URI: The Authority/Host could not be parsed.' [duplicate]

The same line of code in the same assembly works for one test fixture but not another. Here is the line of code:
var dic = new ResourceDictionary { Source = new Uri("pack://application:,,,/MyApp.Wpf;component/ImageResources.xaml") };
The error I get in the other test fixture is System.UriFormatException : Invalid URI: Invalid port specified.
The uri string also works in xaml. Is there a better way to load a resource dictionary in code?
Cheers,
Berryl
=== UPDATE ===
As I found in this posting, an Invalid port was occurring because the pack scheme wasn't registered, which can be done with code like so:
if (!UriParser.IsKnownScheme("pack"))
UriParser.Register(new GenericUriParser(GenericUriParserOptions.GenericAuthority), "pack", -1);
I am guessing that the test fixture that was able to load the dictionary with the pack scheme without error is because the SUT is a user control there, and is somehow loading resources when an instance of the user control is created.
What I use is with UriKind like
var resource = new ResourceDictionary
{
Source = new Uri("/myAssemblyName;component/Themes/generic.xaml",
UriKind.RelativeOrAbsolute)
};
HTH
#Prince Ashitaka answer tells you how to correct your URI
However the preferred way of accessing a ResourceDictionary is that in XAML you add it on as a merged dictionary
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ImageResources.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
then you can access it via code using the TryFindResource(string Key) from any code behind file

Using Custom Resource in DevExpress WPF Theme

Objective:
I have a WPF project which shall be themed using DevExpress Themes.
There is a Login-UserControl that shall have a themable background image.
Implementation
I made a custom Theme. In that theme I have a Folder "CustomResources" in which there is an Image, let's call it "Background.png" and a "Brushes.xaml" that defines an ImageBrush like this:
<ResourceDictionary ...>
<ImageBrush x:Key="{CustomThemeKeyAssembly:CustomThemeResourcesThemeKey ResourceKey=LoginBackgroundImageBrush, ThemeName=CustomTheme}" ImageSource="Background.png" />
</ResourceDictionary>
Accordingly, I have a shared Assembly CustomThemeKeyAssembly that derives a Custom ResourceThemeKey.
In the Project, I register and set the Theme using ApplicationThemeHelper
var theme = new Theme("CustomTheme")
{
AssemblyName = "DevExpress.Xpf.Themes.CustomTheme.v17.2"
};
Theme.RegisterTheme(theme);
ApplicationThemeHelper.ApplicationThemeName = "CustomTheme";
and I reference the Resource through
Background="{dxci:ThemeResource ThemeKey={CustomThemeKeyAssembly:CustomThemeResourcesThemeKey ResourceKey=LoginBackgroundImageBrush}}"
As advised by DevExpress Knowledgebase / Support.
Problem
The Resource is only found and displayed, if I add a Merged Resource Dictionary like this:
ResourceDictionary loginBackgroundDictionary = new ResourceDictionary
{
Source = new Uri($"pack://application:,,,/{MyProject.Properties.Settings.Default.ThemeAssembly};Component/CustomResources/Brushes.xaml", UriKind.Absolute)
};
//Add LoginBackgroundImageBrush Dictionary
Resources.MergedDictionaries.Add(loginBackgroundDictionary);
No article or example mentions having to do this, though. So my impression is that I either am doing something wrong or I am missing some simple step like merging the Brushes.xaml into some ResourceDictionary.
Without that snippet I get a warning that the resource could not be found.
Question
Has anybody an idea where I am going wrong or what I am missing to get this working without that last snippet?
FYI: I am using DevExpress 17.2.3 and the ResourceKey Assembly is targeted to .net Framework 4.0
EDIT
Meanwhile, I tried adding the Brushes.xaml to Themes/Generic.xaml in the theme assembly like this:
<ResourceDictionary.MergedDictionaries>
<dxt:ResourceDictionaryEx Source="/DevExpress.Xpf.Themes.Office2016WhiteSE.v17.2;component/Themes/ControlStyles.xaml" />
<dxt:ResourceDictionaryEx Source="/DevExpress.Xpf.Themes.Office2016WhiteSE.v17.2;component/CustomResources/Brushes.xaml" />
</ResourceDictionary.MergedDictionaries>
It didn't make any difference. Same behavior as before.
Problem solved!
The problem was in the CustomThemeKeyAssembly
The wrong implementation was
public class CustomThemeResourcesThemeKey : ThemeKeyExtensionBase
{
public override Assembly Assembly => TypeInTargetAssembly != null ? TypeInTargetAssembly.Assembly : GetType().Assembly;
}
The working implementation is
public class CustomThemeResourcesThemeKey : ThemeKeyExtensionBase<ThemeResourcesThemeKeys> { }
The breaking difference is the override of the Assembly property. The default implementation makes it work. I did that because it was done so in an example. Support told me to stick with the default implementation and it worked.

WinRT StaticResource from ViewModel in referenced Assembly

I am in the process of porting one of our iOS applications to Windows 8/8.1. Using the MVVM design pattern I have created a ViewModel for one of the Pages to use. Similar to our WebApp the Windows application separates the layers by grouping relevant objects in Class Libraries. There is a Business/Model Layer (I will reference this as App.BLL) and a Data Access Layer (I will reference this as App.Data).
App references App.BLL, and App.BLL references App.Data. App.BLL contains a namespace called Items, which contains a Class ItemsViewModel. ItemsViewModel contains a ObservableCollection Items. When ItemsViewModels' constructor is called, it sets Items by calling a method contained in App.Data (List LoadItems()).
The issue I have been pulling my hair out over is, the designer is displaying an error on as seen below.
"Error 3 Type universe cannot resolve assembly: App.Data, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null."
I imagine this is due to App.BLL having a reference to App.Data, where App does not reference App.Data. I have also tried explicitly defining the assembly of xmlns:model (xmlns:model="using:App.BLL.Items;assembly=App.BLL").
This only leads to a separate error while in the designer only.
Error 7 Assembly 'App.BLL' was not found. Verify that you are not missing an assembly reference. Also, verify that your project and all referenced assemblies have been built.
If the designer is closed the first error mentioned is gone (when defining the assembly), and is replaced by:
Error 6 Unknown type 'ItemsViewModel' in XML namespace 'using:App.BLL.Products;assembly=App.BLL'
However, it does exist.
namespace App.BLL.Items
{
public class ItemsViewModel : IItemInterface
{
public ObservableCollection<Item> Items
{
get;
private set;
}
public ItemsViewModel()
{
Items = Item.GetItems();
}
private Item _selectedItem;
public Item SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnItemSelected(_selectedItem);
}
}
private RelayCommand<Item> _itemSelected;
public RelayCommand<Item> ItemSelected
{
get
{
return _itemSelected ??
(_itemSelected = new RelayCommand<Item>(item =>
{
SelectedItem = item;
//Notify Item Selected
}));
}
}
public event ItemSelectedEventHandler ItemSelectedChanged;
protected virtual void OnItemSelected(Item selectedItem)
{
ItemSelectedChanged(this, new ItemChangedEventArgs(selectedItem));
}
}
}
At this point I could not care less about the designer error's, as they go away while it is closed so it seems that at Runtime it would work. However with Error 6 above I can not compile.
<Page
x:Class="App.ItemsPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:model="using:App.BLL.Items"
mc:Ignorable="d">
<Page.Resources>
<model:ItemsViewModel x:Key="ItemSource" />
</Page.Resources>
<Grid DataContext="{Binding Source={StaticResource ItemSource}}" />
</Page>
I have looked around the web all day before asking a question here, I hope I provided everything needed to help in finding a solution.
Edit: I can't for the life of me get this formatted correctly. I will keep working on it, but if someone could edit that would be ok also.

The tag 'ViewModelLocator' does not exist in XML namespace clr-namespace:XXX

I have tried numerous other solutions without any success. I have a class called ViewModelLocator which is located in my portable class library. It has a property in it called ViewModels, which is of type Dictionay<K, V>
Then I have a Windows Phone 8 project that references the portable class library. I added the following to the WP8 app.xaml:
<Application
x:Class="Kaizen.WP8.Test.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:test="clr-namespace:Foo.Core.Portable.ViewModel;assembly=Foo.Core.Portable">
<Application.Resources>
<test:ViewModelLocator x:Key="ViewModelLocator">
<test:ViewModelLocator.ViewModels>
<test:SampleViewModel x:Key="sampleVM"/>
</test:ViewModelLocator.ViewModels>
</test:ViewModelLocator>
</Application.Resources>
</Application>
When I press F12 on the tags, it navigates to the correct class and or property in my pcl. Which indicates that VS knows about the objects, but when I try and build, I receive the following error:
The tag 'ViewModelLocator' does not exist in XML namespace
'clr-namespace:Foo.Core.Portable.ViewModel;assembly=Foo.Core.Portable'.
The tag 'SampleViewModel' does not exist in XML namespace
'clr-namespace:Foo.Core.Portable.ViewModel;assembly=Foo.Core.Portable'.
Could anyone please provide some assistance?
[Update]
I reference the pcl version of mvvm light in my pcl project. This is how the ViewModelLocator class looks like:
public class ViewModelLocator
{
public dynamic this[string viewModelName]
{
get
{
if (this.ViewModels.ContainsKey(viewModelName))
{
return this.ViewModels[viewModelName];
}
else
{
return null;
}
}
}
public Dictionary<string, ViewModelBase> ViewModels { get; set; }
public ViewModelLocator()
{
this.ViewModels = new Dictionary<string, ViewModelBase>();
}
}
My WP8 project also makes use of the mvvm light pcl assemblies. I noticed that, if I make use of the ViewModelBase class as the dictionary value, that when I get the errors. It's as there's an issue using the mvvm light pcl between the two projects?!
[Update]
Many thanks in advance!!
Kind regards,
I just had this problem with a .Net 4.5 project.
The solution for me was to change to .Net 4.0, ignore the warnings, and change back to .Net 4.5.
Then the problem was gone.
Don't know if it is a feasible way for others, but it worked for me.
Best regards.
Okay, so I'm not exactly sure what I did wrong in my first attempt, but I recreated the solution and performed more or less the same steps and I didn't receive the error again?! o_O
I know this is a bit late but I had the same problem with a WPF Desktop app and a control library. The library's default Target Framework was .Net 4 but the Desktop app just after I created in in Visual Studio was by default created with .Net 4 client profile. I changed the Desktop app from .Net 4 client profile to .Net 4 and it worked.

How to use resource dictionary in prism modules at design time?

I am using prism framework in a silverlight app with multiple modules in separate XAPs.
I have a resource dictionary defined in my in my shell project. In my modules I can use the resources fine, but since the modules are decoupled from the shell until they are loaded at runtime the designer does not show them or recognize them.
Is there a way to make the modules aware of my resources at design time without merging my resource file in every view xaml?
My resource files are in a "common" project.
I think I have definitely solution for design-time resources.
Benefits:
It works in any module based (MEF, UNITY..) application.
It works in any designer (Visual Studio, Blend..)
It does not create multiple instances of the same ResourceDictionary
Let's consider following solution:
MyApp.Shell (.exe)
MyApp.Module1 (.dll) - loaded at runtime using MEF
MyApp.Module2 (.dll) - loaded at runtime using MEF
MyApp.Common (.dll) - referenced by all projects
you can define brushes, implicit styles, templates etc in MyApp.Common.
use my SharedResourceDictionary to include the ResourceDictionary in all projects. At design-time it will load the ResourceDictionary for each designer, at runtime the ResourceDictionary will be loaded only when necessary.
Usage example:
include SharedResourceDictionary in App.xaml
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
</ResourceDictionary>
</Application.Resources>
include SharedResourceDictionary everywhere designer fails to find
some share resource, e.g. in MyApp.Module1/UserControl1.xaml
<UserControl.Resources>
<common:SharedResourceDictionary SharedSource="MyApp.Common;component/CommonResources.xaml" />
</UserControl.Resources>
Source:
/// <summary>
/// Loads singleton instance of ResourceDictionary to current scope;
/// </summary>
public class SharedResourceDictionary : ResourceDictionary
{
/// <summary>
/// store weak references to loaded ResourceDictionary, to ensure that ResourceDictionary won't be instanciated multiple times
/// </summary>
protected static Dictionary<string, WeakReference> SharedResources = new Dictionary<string, WeakReference>();
public string SharedSource
{
get { return _SharedSource; }
set
{
if (_SharedSource != value)
{
_SharedSource = value;
sharedSourceChanged();
}
}
}
private string _SharedSource;
private void sharedSourceChanged()
{
//ResourceDictionary will be instanciated only once
ResourceDictionary sharedResourceDictionary;
lock (SharedResources)
{
WeakReference weakResourceDictionary = null;
if (SharedResources.ContainsKey(_SharedSource))
{
weakResourceDictionary = SharedResources[_SharedSource];
}
else
{
SharedResources.Add(_SharedSource, null);
}
if (weakResourceDictionary == null || !weakResourceDictionary.IsAlive) //load ResourceDictionary or get reference to exiting
{
sharedResourceDictionary = (ResourceDictionary)Application.LoadComponent(new Uri(_SharedSource, UriKind.Relative));
weakResourceDictionary = new WeakReference(sharedResourceDictionary);
}
else
{
sharedResourceDictionary = (ResourceDictionary)weakResourceDictionary.Target;
}
SharedResources[_SharedSource] = weakResourceDictionary;
}
if (Application.Current != null)
{
//if sharedResourceDictionary is defined in application scope do not add it to again to current scope
if (containsResourceDictionary(Application.Current.Resources, sharedResourceDictionary))
{
return;
}
}
this.MergedDictionaries.Add(sharedResourceDictionary);
}
private bool containsResourceDictionary(ResourceDictionary scope, ResourceDictionary rs)
{
foreach (var subScope in scope.MergedDictionaries)
{
if (subScope == rs) return true;
if (containsResourceDictionary(subScope, rs)) return true;
}
return false;
}
}
I have found there are a couple of solutions to this:
1) When you create a module project, leave the App.xaml in the project instead of deleting it and instantiate your resources in there just as if it were its own application by itself (you can also add a new Application class to the project if you have already deleted it). When your module is loaded into the shell that file will be ignored so it's essentially only valid during design time. This works well in visual studio and blend although if you have many modules, memory footprint may become a problem.
2) Using design time resources. Some info about setting this up here: http://adamkinney.com/blog/2010/05/04/design-time-resources-in-expression-blend-4-rc/. This offers only blend support and your views will be stripped of all styles and formatting in visual studio. This was not ideal for me because I like working on certain aspects of the UI in visual studio. There also doesn't seem to be a documented way of manually setting up design time resources.
Small own-experience guide for migrating resources from Shell to shared essembly and making designer work just fine
Some thoughts based on reading such questions and searching internet on the same/similar problem. I'm writing this primarily because of problem 2 (below), which is related to this issue, IMHO.
So, we had the same design, all styles and resources were in Shell. This produced 2 problems:
Context help in XAML-Editor was not available (<- resources not
found)
Designer wouldn't show up properly (<- resources not
found)
So we migrated all styles to shared assembly (Resources).
To solve the first problem you would need sth like Liero proposed, i.e. add resource dictionary to each UserControl. I didn't try his SharedDictionary, but normal ResourceDictionary definitely brings context help back and removes blue-underscore lines. Designer however still didn't show up properly.
So the second problem. There is a small trick to bring styles to designer at design time only described in this article. Basically you add a resource dictionary named DesignTimeResources.xaml to your project that contains reference to your resources:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources;component/Themes/Generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Than move it to Properties folder. Than edit manually project file and change the item for this file to this:
<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
</Page>
Basically it's a file that Blend would generate if you add design time resources. VS cannot create it, although can read it just fine. The editing of project file says that you don't want basically this file in release.
Two minor gotchas here also, perhaps it will help somebody.
When migrating resources from Shell to Resources, our Resources project won't build with weird errors that it cannot find UserControls referenced from style files (all problematic controls were defined in the Resources project as well). They were working just fine when referenced from Shell before. The problem was that some tools (like Resharper) automatically reference these controls in namespace like "clr-namespace:XXX;assembly=Resources". The ";assembly=Resources"-part you should delete, as it is the same assembly now.
We already head some local resources in our UserControls, like this:
<UserControl.Resources>
<PresentationHelpers:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
</UserControl.Resources>
So at first I just added new ResourceDictionary into this block, which asked me to provide an x:Key. I was so used to add resources directly to UserControl.Resources, that I didn't first realise that in order to merge another dictionary you would need <ResourceDictionary> tag that normally you could skip. So it will look like this:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<Helpers:RedbexResourceDictionary Source="pack://application:,,,/Resources;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<PresentationHelpers:BoolToVisibilityConverter x:Key="boolToVisibilityConverter" />
</ResourceDictionary>
</UserControl.Resources>
If you're looking to provide design time data for your views may I suggest reading this article. It shows how to use Blend to create design time data within your project which is not included in the release builds of the application.
Hope it helps.

Categories

Resources