How do I use an icon that is a resource in WPF? - wpf

I have a .ico file that is embedded as a resource (build action set to resource). I am trying to create a NotifyIcon. How can I reference my icon?
notifyIcon = new NotifyIcon();
notifyIcon.Icon = ?? // my icon file is called MyIcon.ico and is embedded

Your icon file should be added to one of your project assemblies and its Build Action should be set to Resource. After adding a reference to the assembly, you can create a NotifyIcon like this:
System.Windows.Forms.NotifyIcon icon = new System.Windows.Forms.NotifyIcon();
Stream iconStream = Application.GetResourceStream( new Uri( "pack://application:,,,/YourReferencedAssembly;component/YourPossibleSubFolder/YourResourceFile.ico" )).Stream;
icon.Icon = new System.Drawing.Icon( iconStream );

A common usage pattern is to have the notify icon the same as the main window's icon. The icon is defined as a PNG file.
To do this, add the image to the project's resources and then use as follows:
var iconHandle = MyNamespace.Properties.Resources.MyImage.GetHicon();
this.notifyIcon.Icon = System.Drawing.Icon.FromHandle(iconHandle);
In the window XAML:
<Window x:Class="MyNamespace.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:local="clr-namespace:Seahorse"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="600"
Icon="images\MyImage.png">

Well, you don't want to use the resx style resources: you just stick the ico file in your project in a folder (lets say "ArtWork") and in the properties, set the Build Action to "Resources" ...
Then you can reference it in XAML using PACK URIs ... "pack://application:,,,/Artwork/Notify.ico"
See here: http://msdn.microsoft.com/en-us/library/aa970069.aspx and the sample
If you want to be a little bit more ... WPF-like, you should look into the WPF Contrib project on CodePlex which has a NotifyIcon control which you can create in XAML and which uses standard WPF menus (so you can stick "anything" in the menu).

If you are just looking for the simple answer, I think this is it where MyApp is your application name and where that's the root namespace name for your application. You have to use the pack URI syntax, but it doesn't have to be that complicated to pull an icon out of your embedded resources.
<Window x:Class="MyApp.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"
mc:Ignorable="d"
Height="100"
Width="200"
Icon="pack://application:,,,/MyApp;component/Resources/small_icon.ico">

I created a project here and used an embedded resource (build action was set to Embedded Resource, rather than just resource). This solution doesn't work with Resource, but you may be able to manipulate it. I put this on the OnIntialized() but it doesn't have to go there.
//IconTest = namespace; exclamic.ico = resource
System.IO.Stream stream = this.GetType().Assembly.GetManifestResourceStream("IconTest.Resources.exclamic.ico");
if (stream != null)
{
//Decode the icon from the stream and set the first frame to the BitmapSource
BitmapDecoder decoder = IconBitmapDecoder.Create(stream, BitmapCreateOptions.None, BitmapCacheOption.None);
BitmapSource source = decoder.Frames[0];
//set the source of your image
image.Source = source;
}

Related

How to done the LeanFt testing for DataGrid in WPF?

I have created leanft project and created a sample with DataGrid, but it throws table was not found exception and also I am not sure the way of testing of DataGrid in leanft. Could you anyone help on this to fix this?
Datagrid sample:
<Window x:Class="WpfApplication12.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="datagrid_window"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid x:Name="msdatagrid" AutoGenerateColumns="True">
</DataGrid>
</Grid>
</Window>
I have set the itemsource for this datagrid from the code behind.
Leanft Test method:
public void TestMethod1()
{
SDK.Init(new SdkConfiguration());
Reporter.Init(new ReportConfiguration());
Process.Start(#"..\..\..\Debug\WpfApplication12.exe");
IWindow win = Desktop.Describe<IWindow>(new WindowDescription
{
IsChildWindow = false,
IsOwnedWindow = false,
AccessibleName = #"datagrid_window",
});
ITable table = win.Describe<ITable>(new TableDescription
{
Name = #"msdatagrid"
});
table.SelectCell(1, 1);
}
A test object not found exception means you didn’t create a correct description for your test object or its parent.
Try using the object identification center to spy for the datagrid, copy the description (using the second left button on the bottom) and paste it into your test.
More info about OIC is here:
http://leanft-help.saas.hp.com/en/latest/HelpCenter/Content/HowTo/TestObjects_OIC.htm
In your case it will look like this:
var table = Desktop.Describe<IWindow>(new WindowDescription
{
ObjectName = #"datagrid_window",
FullType = #"window",
WindowTitleRegExp = #"MainWindow"
}).Describe<ITable>(new TableDescription
{
ObjectName = #"msdatagrid"
});
This is how you can access datagrid cells for example:
var firstCell = table.Rows[0].Cells[1];
Assert.AreEqual("World", firstCell.Value);
firstCell.SetValue("World1");
Make sure you added the correct using statement according to the technology you are using.
Each technology test objects are defined in a dedicated namespace.
For WPF it should be:
using HP.LFT.SDK.WPF;
You used WindowDescription from the HP.LFT.SDK.StdWin namespace (according to its properties).
HP.LFT.SDK.StdWin is a namespace for native windows controls test objects and you can’t describe a WPF test object on a Window from StdWin namespace.
Note that for desktop applications, it is better if only one instance of the application is running.
I can also see that you are initializing the SDK and the Reporter.
It is recommended to use the visual studio LeanFT project template that already contain all you need (references, initialization) to start coding your tests.
The templates can be found under the C#\Test section in the New Project dialog of visual studio.
Hope it helps!

Cannot load resource dictionary with converter

Everything happens within the same VS project. I have a resource dictionary file living on it's own. When I try to load it programmatically I get the error
"Cannot create unknown type '{clr-namespace:MyAssembly.Helpers}IsNullConverter".
Here is how I load it :
StreamResourceInfo stream = Application.GetResourceStream(new Uri(#"MyAssembly;component/Resources/Resources.xaml", UriKind.Relative));
this.dynamicResources = XamlReader.Load(stream.Stream) as ResourceDictionary;
And here is the resource dictionary :
<ResourceDictionary 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:helpers="clr-namespace:MyAssembly.Helpers">
<helpers:IsNullConverter x:Key="IsNullConverter" />
Styles go here...
Note that it is tied to a code-behind file, but there is nothing in it. The Build-Action of the resource file is set to "Resource". This is driving me crazy since this morning and still no clue what the heck is going on...
Help.
Thank you.
Halelujah I fugured it out. All I had to do is load the resource dictionary directly
Uri uri = new Uri(#MyAssembly;component/Resources/Resources.xaml", UriKind.Relative);
this.dynamicResources.Source = uri;
And make sure Build Action of resource dictionary file is set to "Page"
\m/
Is the assembly referenced by your project? If not try adding a reference - if you don't want a dependency you could try loading the assembly:
http://www.dreamincode.net/forums/topic/78974-using-reflection-to-load-unreferenced-assemblies-at-runtime/
Alternatively you could add a x:Class definition to the resourcedictionary, and instantiate the class from the assembly instead of loading the xaml, and remember to call the generated InitializeComponent() from the constructor, the it will load.
Is it possible to set code behind a resource dictionary in WPF for event handling?
Your example would work fine if the ResourceDictionary and converter was in the same assembly as where you load from, as far as I can see :)

Changing ResourceDictionary doesn't visably affect Window in WPF

I have a simple WPF application I'm using for experimenting.
I have two themes defined in seperate xaml files, changing the xaml to point to them worked fine. By the way, in the xaml I'm using a straight ResourceDictionary element, not a ResourceDictionary.MergedDictionaries one.
I want to let the user select which theme to use, so I'm reseting the source property in code behind - but whilst the debugger tells me I've successfully set the value the applications appearance doesn't change.
So, how do you successfully apply a theme at runtime?
EDIT: This is how I'm declaring my "style" in the xaml:
<Window x:Class="WpfUI.winMain">
<Window.Resources>
<ResourceDictionary Source="Themes\Blah.xaml"></ResourceDictionary>
</Window.Resources>
// The windows grid and other controls...
</Window>
The simple answer is, you need to clear the applications merged resource dictionaries. Here is some code to get you started
ResourceDictionary dictionary = GetThemeResourceDictionary(yourTheme)
if (dictionary != null)
{
App.Current.Resources.MergedDictionaries.Clear();
App.Current.Resources.MergedDictionaries.Add(dictionary);
}
public ResourceDictionary GetThemeResourceDictionary(string theme)
{
if (theme != null)
{
Assembly assembly = Assembly.LoadFrom("WPF.Themes.dll");
string packUri = String.Format(YourThemeFolder/{0}.xaml", theme);
return Application.LoadComponent(new Uri(packUri, UriKind.Relative)) as ResourceDictionary;
}
return null;
}
If you want a really nice packaged solution, i would reccommend WPF themes. It introduces a ThemeManager class and a set of built in themes which are really incredible. If you have any difficulty installing it or adding a new theme, contact me :)

How to get at ResourceDictionary style when it is loaded from external xap and assemblies are MEF-fed?

I've got the following setup:
The main application loads a XAP with an IPlugin implementation. The Plugin contains a 'DisplayPanel' that contains a referenced Control with other controls. The DisplayPanel here is simply a container control to show referenced Control.
This referenced Control, from an assembly, uses a Style from a ResourceDictionary xaml in this assembly. At least that's what I want to have. The problem is that the referenced Control throws an error:
Cannot find a Resource with the Name/Key PlayerPanelGrad [Line: 1500
Position: 127]
I've tried to get at the style by referencing theResourceDictionary through a Merged Resource dictionary reference:
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="TableControls;component/ControlsStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
But that doesn't work.
How would you approch this?
the only way i got it to work is by loading the Resource dictionary into the control (in a Class Library) programmatically before the InitializeComponent call:
public ActionPanel()
{
StreamResourceInfo sr = Application.GetResourceStream(
new Uri("TableControls;component/ControlsStyle.xaml", UriKind.Relative));
Application.Current.Resources.Add("plop",sr.Stream);
// Required to initialize variables
InitializeComponent();
}
This question may be of help, although, honestly, I'm still trying to figure it out myself:
Using MEF to import a WPF DataTemplate?
//load other.dll dynamically first,and then use the following code:
StreamResourceInfo srf = Application.GetResourceStream(new Uri("otherdll;component/Resources/Brush.xaml", UriKind.Relative));
StreamReader sr = new StreamReader(srf.Stream);
string stt = sr.ReadToEnd();
ResourceDictionary dict = XamlReader.Load(stt) as ResourceDictionary;
Application.Current.Resources.MergedDictionaries.Add(dict);
For future reference, my XAML file was found in a subdirectory of the solution which needed the / character but also file was further in a subdirectory named Assets within it.
<ResourceDictionary
Source="/MyAssemblyName;component/Assets/RadResources.xaml" />
Also the .XAML file was built as Page in the solution.

Creating a CroppedBitmap at runtime - won't load from resource

I'm trying to write code that will load an image from a resource, and then crop it. This code works when I do all, or part, of it in XAML. I want to switch from all-XAML to all-code, so I can reuse this more than one place, with different Uris.
But when I try to do the same thing in code, I get a DirectoryNotFoundException, because suddenly it starts trying to look for a folder on disk, instead of loading the image from the resource.
If I load the BitmapImage in XAML, and then create a CroppedBitmap in XAML, everything works.
If I load the BitmapImage in XAML, and then write code to create a CroppedBitmap from it, everything works.
If I load the BitmapImage in code, without creating a CroppedBitmap from it, everything works.
But if I load the BitmapImage in code and create a CroppedBitmap in code, it tries to load from the filesystem instead of the resources, and I get a DirectoryNotFoundException.
Code samples are below. I'm sure I'm doing something stupid, but I've run through the whole thing three times now (once in my real app, once in a test app, and once while writing up this question), and I got the same results all three times.
For all of the following code samples, I've created an Images folder inside my project, and added an existing image there called "elf.png", with properties set to defaults (Build Action = "Resource"; Copy to Output Directory = "Do not copy").
Case 1: Both BitmapImage and CroppedBitmap in XAML.
<Window x:Class="WpfApplication8.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">
<Window.Resources>
<BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
<CroppedBitmap x:Key="croppedImage" Source="{StaticResource fullImage}"
SourceRect="0 0 240 320"/>
</Window.Resources>
<Image Source="{StaticResource croppedImage}"/>
</Window>
This shows the cropped portion of the bitmap, as expected.
Case 2: BitmapImage in XAML; CroppedBitmap in code-behind.
XAML:
<Window x:Class="WpfApplication8.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">
<Window.Resources>
<BitmapImage x:Key="fullImage" UriSource="Images/elf.png"/>
</Window.Resources>
<Image Name="image"/>
</Window>
Constructor in code-behind:
public Window1()
{
InitializeComponent();
var fullImage = (BitmapImage) FindResource("fullImage");
var croppedImage =
new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
image.Source = croppedImage;
}
This also shows the cropped portion of the bitmap, as expected.
Case 3: BitmapImage in code; no CroppedBitmap.
public Window1()
{
InitializeComponent();
var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
var fullImage = new BitmapImage(uri);
image.Source = fullImage;
}
This shows the entire bitmap. This isn't what I want, but does tell me that I know how to write C# code to create the right kind of Uri and load a BitmapImage from a resource.
Case 4: BitmapImage and CroppedBitmap in code.
public Window1()
{
InitializeComponent();
var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
var fullImage = new BitmapImage(uri);
var croppedImage =
new CroppedBitmap(fullImage, new Int32Rect(0, 0, 240, 320));
image.Source = croppedImage;
}
As far as I can tell, this just puts together the same pieces as before. It uses code that I know will load a BitmapImage from a resource, and code that I know will crop a section from a loaded BitmapImage. But somehow, when the two are put together, it forgets that the resource is there, and tries to load from disk. I get the following exception:
XamlParseException: "Cannot create instance of 'Window1' defined in assembly 'WpfApplication8, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Exception has been thrown by the target of an invocation. Error in markup file 'Window1.xaml' Line 1 Position 13."
Inner exception: TargetInvocationException: "Exception has been thrown by the target of an invocation."
Inner exception: DirectoryNotFoundException: "Could not find a part of the path 'C:\svn\WpfApplication8\WpfApplication8\bin\Debug\Images\elf.png'."
The inner-inner-exception stack trace shows that the original exception (the DirectoryNotFoundException) is being thrown by the line that instantiates the CroppedBitmap. I don't know why that line would be trying to read from disk, or why it doesn't work when the as-far-as-I-can-tell-equivalent XAML works fine.
Since I know the XAML is using the parameterless constructors, I also tried the following version, which should be much closer to what the XAML actually does:
public Window1()
{
InitializeComponent();
var uri = new Uri("Images/elf.png", UriKind.RelativeOrAbsolute);
var fullImage = new BitmapImage();
fullImage.BeginInit();
fullImage.UriSource = uri;
fullImage.EndInit();
var croppedImage = new CroppedBitmap();
croppedImage.BeginInit();
croppedImage.Source = fullImage;
croppedImage.SourceRect = new Int32Rect(0, 0, 240, 320);
croppedImage.EndInit();
image.Source = croppedImage;
}
Same exception, this time from the croppedImage.EndInit(); line.
Any ideas on how I can get the all-code version to correctly load the resource and crop the image? What's happening in the XAML version that's different?
The magic turned out to be in the BitmapImage's BaseUri property. BaseUri apparently serves as the "current directory" that UriSource is relative to.
When my BitmapImage was being loaded from XAML, BaseUri was being magically set to "pack://application:,,,/WpfApplication8;component/window1.xaml". When I modified code snippet #4 to explicitly set fullImage.BaseUri to that same value before creating the CroppedBitmap, everything worked.
Why it worked from XAML (and from just-BitmapImage-without-CroppedBitmap)
So where did this magic BaseUri value come from?
BaseUri is part of the IUriContext interface. IUriContext.BaseUri is set in two places in the WPF assemblies, and between my various examples, I managed to hit both of them. No wonder I was confused.
BamlRecordReader.ElementInitialize. The BAML loader automatically sets BaseUri anytime it loads an element that implements IUriContext. This explains why my examples #1 and #2 worked: they were loading from the compiled BAML resource.
Image.UpdateBaseUri (called whenever the Source property is changed). This checks to see if the Source implements IUriContext, and if so, sets its BaseUri. This explains why my example #3 worked: pushing the BitmapImage into the GUI forced it to get the right search path.
It only looks for the image in the EXE resources when BaseUri is set to the magic pack:// URI. Without that (as happens when everything is created in code and not pushed into the GUI), it only looks on disk.
The fix
As noted above, I could hard-code BaseUri. But the BaseUriHelper class provides a better fix:
fullImage.BaseUri = BaseUriHelper.GetBaseUri(this);
This sets fullImage to have the same BaseUri as the window (this). If this is done before creating the CroppedBitmap, everything works.

Resources