I thought it would be fun to create a WPF screen saver. I built one with Robert Hogue‘s most excellent Material Group “Background Animation” visuals. (You can find it in his Sample Pack.) You can download the screen saver and/or the code.
However, I thought it would be even more fun if everyone else would write screen savers too. 🙂 To facilitate this, I’ve written a VS template for WPF screen savers.
Screen Saver Template – Installation Instructions
- Download the template here.
- Move the zip file to <MY DOCUMENTS>Visual Studio 2005TemplatesProjectTemplatesVisual C#”.. (DO NOT unzip it)
When creating a new project, “Screen Saver Application (WPF)” will now be an “Visual C#” project type option.
Deploying the Screen Saver
In order to deploy your screen saver, you must rename the RELEASE build of the screen saver executable to have a “.scr” extension:
- Go to binRelease folder of your project.
- Rename the .exe to .scr. (e.g.”ScreenSaver.exe” becomes “ScreenSaver.scr”)
- If using .NET Application Settings, see important note below.
Installing the Screen Saver
To install on a user’s machine:
- Copy the .scr file (& any dependent files) to convenient location on your C: drive.
- Right click the .scr file.
- Select Install.
To configure on a client machine:
- In the Windows Screen Saver Dialog, select the screen saver.
- Click Settings button.
To uninstall:
- Delete .scr file.
Screen Saver Files
The template creates the following main files for you:
- App.xaml/App.xaml.cs – sets up screen saver application.
- Window1.xaml/Window1.xaml.cs – main visuals of screen saver
- Settings.xaml/Settings.xaml.cs – settings window of screen saver
Screen Saver Modes
The screen saver can be launched with different command line arguments:
- <no args>: Display screen saver
- “/s”: Display screen saver
- “/c”: Show settings window
Debugging
In DEBUG configurations, the screen saver window’s “topmost”-ness and “shutdown on key/mouse input” are disabled. To close the window, hit Ctl-F4.
To debug the settings window…
- Go to the project properties pane. (Right click the project in the Solution Explorer
& select “Properties”). - Select Debug on the left tabs.
- Find “Command Line Args” textbox under “Start Options”.
- Enter: /c
Saving Screen Saver Settings
I highly recommend using the .NET Application Settings feature to save user-configured screen saver settings.
Here’s the quick run down of how to do it.
- Determine which settings you need. The default settings store only supports limited Type, so make sure to use an appropriate format.
- Add the settings to the Settings.settings file using the designer. By default, these are saved to a per user, file system-based .NET settings store.
- Access the settings using Properties.Settings.Default.YourSettingName.
For the screen saver above, I defined one setting in the designer:
In my Settings.xaml.cs file, I accessed it:
//initialize color picker with BackgroundColor application setting
TypeConverter colorTypeConverter = TypeDescriptor.GetConverter(typeof(Color));
MyColorPicker.Color = (Color) colorTypeConverter.ConvertFrom(Properties.Settings.Default.BackgroundColor) ;
As well as saved it:
//set BackgroundColor application setting to color picker's color
TypeConverter colorTypeConverter = TypeDescriptor.GetConverter(typeof(Color));
Properties.Settings.Default.BackgroundColor = colorTypeConverter.ConvertTo(MyColorPicker.Color, typeof(string)) as string;
//flush application settings
Properties.Settings.Default.Save();
Finally, I renamed “MaterialGroupScreenSaver.exe” to “Spiral.scr.”
IMPORTANT NOTE:
By default, the .NET Application Settings framework stores user settings based on the executing assembly name. If you use .NET Application Settings with the default settings store,
YOU MUST GIVE YOUR SCREEN SAVER ASSEMBLY A NAME WITH 8 CHARACTERS OR LESS.
Why? The Windows Screen Saver Dialog launches the screen saver (for settings & preview) using the full assembly name (e.g. MyCoolScreenSaver.scr). However, when launching the screensaver for real, Windows uses the shortened version (e.g. MYCOOL~1.SCR). Since the name is different, the settings are loaded from a different place.
Release Notes
- Does not support real time preview in the Windows Screen Saver Dialog’s embedded display.
- The screen saver duplicates the visuals on each monitor by creating an additional instances of Window1.
Not alot of respones, but man, this is great! You are the first who managed to do this, and believe me, it will find a good use. It was exactly what I was looking for. Now the purple Aurora XAML file can finally be used as screensaver! thx
Hey, nice job!
I was wondering if you could help me out here. I am using your screensaver sample for a wpf screensaver I am working on. I am using the application settings as recommended by you, but I was working how would I read the application settings into the XMAL data? I would like to be able to change the speed ratio value.
– Regards
Dan
Quick edit.
I meant XAML.
Hello,
Is it possible to set the screensaver to open a specific web site when it is interrupted by the user? Any suggestions would be great.
When I try to open a screensaver project in VS 2005, I get the message:
The project file … cannot be opened. The project type is not supported by this installation.
Is there something I’m missing? I installed the template already.
Karen,
I compiled the project using VS2005. However, after rename to clear.scr file, right click did not show install option. What part I did not follow correctly? I am using XP.
Thanks
I figured it out. Thanks.
Don’t ever apply for a credit card without considering all the details. The best way to choose the right credit card is to make an apple-to-apple comparison. A great site that helps to do that is
discover balance transfer more card
Any chance you could update the template for VS 2008?
Thanks!
Looks like this template works for VS2008 now. Good job! I’m writing a bubbles screensaver for my toddler to play with.
Very cool work Karen,
It’s work fine on my vista, also thanks for sharing the code with the template.
Window1.xaml in Visual Studio 2008 throws an exception
Cannot convert string ‘pack://application:,,,/Microsoft.Windows.Design.Developer;component/Images/Fit_To_Window.png’ in attribute ‘Source’ to object of type ‘System.Windows.Media.ImageSource’. Bitmap color context is not valid. Error at object ‘ControlTemplate_11’ in markup file ‘Microsoft.Windows.Design.Developer;component/themes/ZoomControl.xaml’.
at System.Windows.Markup.XamlParseException.ThrowException(String message, Exception innerException, Int32 lineNumber, Int32 linePosition, Uri baseUri, XamlObjectIds currentXamlObjectIds, XamlObjectIds contextXamlObjectIds, Type objectType)
at System.Windows.Markup.XamlParseException.ThrowException(ParserContext parserContext, Int32 lineNumber, Int32 linePosition, String message, Exception innerException)
at System.Windows.Markup.XamlTypeMapper.ParseProperty(Object targetObject, Type propType, String propName, Object dpOrPiOrFi, ITypeDescriptorContext typeContext, ParserContext parserContext, String value, Int16 converterTypeId)
at System.Windows.Markup.OptimizedTemplateContent.ParseDependencyProperty(String attribValue, Int16 attributeId, Int16 converterTypeId, DependencyProperty& dp, Object& propertyValue)
at System.Windows.Markup.OptimizedTemplateContent.LookForShareableRecord(BamlRecord bamlRecord, DependencyProperty& dp, Object& dpValue)
at System.Windows.Markup.OptimizedTemplateContent.ReadPotentiallyShareableRecord(BamlRecord bamlRecord)
at System.Windows.Markup.OptimizedTemplateContent.ReadRecord(BamlRecord bamlRecord)
at System.Windows.Markup.OptimizedTemplateContent.AddContentRecord(BamlRecord bamlRecord)
at System.Windows.Markup.TemplateBamlRecordReader.AddContentRecord(BamlRecord bamlRecord)
at System.Windows.Markup.TemplateBamlRecordReader.ReadRecord(BamlRecord bamlRecord)
at System.Windows.Markup.BamlRecordReader.Read(Boolean singleRecord)
at System.Windows.Markup.TemplateTreeBuilderBamlTranslator.ParseFragment()
at System.Windows.Markup.TreeBuilder.Parse()
at System.Windows.Markup.XamlTemplateSerializer.ConvertBamlToObject(BamlRecordReader reader, BamlRecord bamlRecord, ParserContext context)
at System.Windows.Markup.BamlRecordReader.ReadElementStartRecord(BamlElementStartRecord bamlElementRecord)
at System.Windows.Markup.StyleBamlRecordReader.ReadElementStartRecord(BamlElementStartRecord bamlElementRecord)
at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord)
at System.Windows.Markup.StyleBamlRecordReader.ReadRecord(BamlRecord bamlRecord)
at System.Windows.Markup.BamlRecordReader.Read(Boolean singleRecord)
at System.Windows.Markup.StyleTreeBuilderBamlTranslator.ParseFragment()
at System.Windows.Markup.TreeBuilder.Parse()
at System.Windows.Markup.XamlStyleSerializer.ConvertBamlToObject(BamlRecordReader reader, BamlRecord bamlRecord, ParserContext context)
at System.Windows.Markup.BamlRecordReader.ReadElementStartRecord(BamlElementStartRecord bamlElementRecord)
at System.Windows.Markup.BamlRecordReader.ReadRecord(BamlRecord bamlRecord)
at System.Windows.Markup.BamlRecordReader.ReadElement(Int64 startPosition, XamlObjectIds contextXamlObjectIds, Object dictionaryKey)
at System.Windows.ResourceDictionary.CreateObject(Int32 valuePosition, Object key)
at System.Windows.ResourceDictionary.RealizeDeferContent(Object key, Object& value, Boolean& canCache)
at System.Windows.ResourceDictionary.GetValueWithoutLock(Object key, Boolean& canCache)
at System.Windows.ResourceDictionary.GetValue(Object key, Boolean& canCache)
at System.Windows.ResourceDictionary.GetValueWithoutLock(Object key, Boolean& canCache)
at System.Windows.ResourceDictionary.GetValue(Object key, Boolean& canCache)
at System.Windows.ResourceDictionary.get_Item(Object key)
at System.Windows.DeferredResourceReference.GetValue(BaseValueSourceInternal valueSource)
at System.Windows.DependencyPropertyChangedEventArgs.get_NewValue()
at System.Windows.FrameworkElement.OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, OperationType operationType)
at System.Windows.StyleHelper.ApplyTemplatedParentValue(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1& childRecordFromChildIndex, DependencyProperty dp, FrameworkElementFactory templateRoot)
at System.Windows.StyleHelper.InvalidatePropertiesOnTemplateNode(DependencyObject container, FrameworkObject child, Int32 childIndex, FrugalStructList`1& childRecordFromChildIndex, Boolean isDetach, FrameworkElementFactory templateRoot)
at System.Windows.StyleHelper.LoadOptimizedTemplateContent(DependencyObject container, ParserContext parserContext, OptimizedTemplateContent optimizedTemplateContent, FrameworkTemplate frameworkTemplate, IComponentConnector componentConnector, IStyleConnector styleConnector, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)
at System.Windows.FrameworkTemplate.LoadContent(DependencyObject container, List`1 affectedChildren, UncommonField`1 templatedNonFeChildrenField)
at System.Windows.StyleHelper.ApplyTemplateContent(UncommonField`1 dataField, DependencyObject container, FrameworkElementFactory templateRoot, Int32 lastChildIndex, HybridDictionary childIndexFromChildID, FrameworkTemplate frameworkTemplate)
at System.Windows.FrameworkTemplate.ApplyTemplateContent(UncommonField`1 templateDataField, FrameworkElement container)
at System.Windows.FrameworkElement.ApplyTemplate()
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Designer.Viewport.MeasureOverride(Size availableSize)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
at System.Windows.Controls.ScrollContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureCell(Int32 cell, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureCellsGroup(Int32 cellsHead, Size referenceSize, Boolean ignoreDesiredSizeU, Boolean forceInfinityV)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.ScrollViewer.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Grid.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at MS.Internal.Helper.MeasureElementWithSingleChild(UIElement element, Size constraint)
at System.Windows.Controls.ContentPresenter.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Controls.Control.MeasureOverride(Size constraint)
at System.Windows.FrameworkElement.MeasureCore(Size availableSize)
at System.Windows.UIElement.Measure(Size availableSize)
at System.Windows.Interop.HwndSource.SetLayoutSize()
at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
at System.Windows.Interop.HwndSource.set_RootVisual(Visual value)
at MS.Internal.Designer.VSIsolatedDesigner.ViewHolder.Initialize()
at MS.Internal.Designer.VSIsolatedDesigner.ViewHolder..ctor(UIElement content)
at MS.Internal.Designer.VSIsolatedDesigner.VSIsolatedView.get_ViewHandle()
at MS.Internal.Host.Isolation.IsolatedView.get_ViewHandle()
at MS.Internal.Designer.DesignerPane.LoadDesignerView()
Bitmap color context is not valid.
at MS.Internal.HRESULT.Check(Int32 hr)
at System.Windows.Media.ColorContextHelper.OpenColorProfile(IntPtr pProfile)
at System.Windows.Media.ColorContext.FromRawBytes(Byte[] data)
at System.Windows.Media.ColorContext.FromStream(Stream stm, String filename)
at System.Windows.Media.ColorContext.Initialize(Uri profileUri, Boolean isStandardProfileUriNotFromUser)
at System.Windows.Media.ColorContext..ctor(PixelFormat pixelFormat)
at System.Windows.Media.Imaging.BitmapSource.CreateCachedBitmap(BitmapFrame frame, BitmapSourceSafeMILHandle wicSource, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, BitmapPalette palette)
at System.Windows.Media.Imaging.BitmapFrameDecode.FinalizeCreation()
at System.Windows.Media.Imaging.BitmapFrameDecode..ctor(Int32 frameNumber, BitmapSourceSafeMILHandle sourceHandle, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, BitmapDecoder decoder)
at System.Windows.Media.Imaging.BitmapDecoder.SetupFrames(BitmapDecoder decoder, ReadOnlyCollection`1 frames)
at System.Windows.Media.Imaging.BitmapDecoder.get_Frames()
at System.Windows.Media.Imaging.BitmapFrame.CreateFromUriOrStream(Uri baseUri, Uri uri, Stream stream, BitmapCreateOptions createOptions, BitmapCacheOption cacheOption, RequestCachePolicy uriCachePolicy)
at System.Windows.Media.ImageSourceConverter.ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, Object value)
at System.ComponentModel.TypeConverter.ConvertFromString(ITypeDescriptorContext context, CultureInfo culture, String text)
at System.Windows.Markup.XamlTypeMapper.ParseProperty(Object targetObject, Type propType, String propName, Object dpOrPiOrFi, ITypeDescriptorContext typeContext, ParserContext parserContext, String value, Int16 converterTypeId)
Please help!
Description:
Stopped working
Problem signature:
Problem Event Name: CLR20r3
Problem Signature 01: wpf_sc~1.scr
Problem Signature 02: 1.0.3208.17600
Problem Signature 03: 48f31900
Problem Signature 04: PresentationCore
Problem Signature 05: 3.0.0.0
Problem Signature 06: 470bc96a
Problem Signature 07: 4be
Problem Signature 08: 5
Problem Signature 09: System.IO.FileFormatException
OS Version: 6.0.6001.2.1.0.768.3
Locale ID: 1033
Read our privacy statement:
http://go.microsoft.com/fwlink/?linkid=50163&clcid=0x0409
This is such a great tutorial. Thanks!
One question: How can I automatically have the exe file renamed to a .scr and placed in the appropriate directory (or install automatically). I don’t want to force novice users to need to go through manual steps to get the screensaver installed.