Sunday, 16 December 2012

Tracking MouseMove in Silverlight

namespace MouseTracking
{
public partial class MainPage
{
readonly MouseTracker tracker = new MouseTracker();

public MainPage()
{
InitializeComponent();
tracker.StartTracking(this);
}
}
}
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;

namespace MouseTracking
{
public class MouseTracker
{
public MouseTracker()
{
TraceMouse = true;
}

public bool TraceMouse { get; set; }

public void StartTracking(UserControl sender)
{
sender.Loaded += sender_Loaded;
//TODO: Hook into specific FrameworkElements events? MouseOver, select, click, etc
}

void sender_Loaded(object sender, RoutedEventArgs e)
{
var page = (UserControl) sender;
page.MouseLeftButtonDown += page_MouseLeftButtonDown;
page.SizeChanged += page_SizeChanged;
page.MouseMove += page_MouseMove;
page.KeyDown += page_KeyDown;
page.Unloaded += page_Unloaded;

var data = string.Format("resolution={0}x{1}",
HtmlPage.Window.Eval("screen.width"),
HtmlPage.Window.Eval("screen.height"));

Write(DateTime.Now, page.ToString(), "Loaded", data);
}

void page_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var data = string.Format("ClickCount={0}", e.ClickCount);

Write(DateTime.Now, sender.ToString(), "page_MouseLeftButtonDown", data);
}

void page_SizeChanged(object sender, SizeChangedEventArgs e)
{
var data = string.Format("screen={0}x{1} page={2}x{3}",
(Application.Current.RootVisual as FrameworkElement).ActualWidth,
(Application.Current.RootVisual as FrameworkElement).ActualHeight,
(sender as FrameworkElement).ActualWidth,
(sender as FrameworkElement).ActualHeight);

Write(DateTime.Now, sender.ToString(), "SizeChanged", data);

}

private void page_KeyDown(object sender, KeyEventArgs e)
{
Write(DateTime.Now, sender.ToString(), "KeyDown", string.Format("key={0}", e.Key));
}

void page_Unloaded(object sender, RoutedEventArgs e)
{
Debug.WriteLine("Removing event handlers");

var page = (UserControl)sender;
page.Loaded -= sender_Loaded;
page.MouseLeftButtonDown -= page_MouseLeftButtonDown;
page.SizeChanged -= page_SizeChanged;
page.MouseMove -= page_MouseMove;
page.KeyDown -= page_KeyDown;
page.Unloaded -= page_Unloaded;
}

void page_MouseMove(object sender, MouseEventArgs e)
{
Write(DateTime.Now, sender.ToString(), "MouseMove", string.Format("coord={0},{1}", e.GetPosition(null).X, e.GetPosition(null).Y));
}

private void Write(DateTime time, string page, string eventName, string data)
{
string ipAddress = Application.Current.Resources["ipAddress"].ToString();

// call service here (ipaddress can be retrieved serverside using HttpContext object)
// for now we'll just output to debug window

if (TraceMouse)
Debug.WriteLine("{0} {1} {2} {3} {4}", ipAddress, time.ToString("MM/dd/yyyy HH:mm:ss.fff"), page, eventName, data);
}
}
}
<body>
<form id="form1" runat="server" style="height:100%">
<div id="silverlightControlHost">
<object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
<param name="source" value="ClientBin/MouseTracking.xap"/>
<param name="onError" value="onSilverlightError" />
<param name="background" value="white" />
<param name="minRuntimeVersion" value="5.0.61118.0" />
<param name="initParams" value="ipAddress=<%= Request.UserHostAddress %>"/>
<param name="autoUpgrade" value="true" />
<a href="http://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0" style="text-decoration:none">
<img src="http://go.microsoft.com/fwlink/?LinkId=161376" alt="Get Microsoft Silverlight" style="border-style:none"/>
</a>
</object><iframe id="_sl_historyFrame" style="visibility:hidden;height:0px;width:0px;border:0px"></iframe></div>
</form>
</body>
</html>
private void Application_Startup(object sender, StartupEventArgs e)
{
if (e.InitParams != null)
{
foreach (var item in e.InitParams)
{
this.Resources.Add(item.Key, item.Value);
}
}

this.RootVisual = new MainPage();
}

Source:  https://github.com/stevenh77/MouseTracking

Wednesday, 5 December 2012

PivotViewer ItemsLoaded event

Here is an example of the PivotViewer extended to feature an ItemsLoaded event.

This event fires when all the item data templates/trading cards have finished rendering.

Live demo:  http://stevenhollidge.com/blog-source-code/pivotviewerwithitemsloadedevent

using System;
using System.ComponentModel;
using System.Windows.Controls.Pivot;
using System.Windows.Threading;

namespace PivotViewerDemo
{
public class MetroPivotViewer : PivotViewer, INotifyPropertyChanged
{
private readonly UiHelper layoutUpdatedFinished;

private string title;
public string Title
{
get { return title; }
set
{
if (title == value) return;
title = value;
NotifyPropertyChanged("Title");
}
}

private bool isLoading;
public bool IsLoading
{
get { return isLoading; }
set
{
if (isLoading == value) return;
isLoading = value;
NotifyPropertyChanged("IsLoading");
}
}

public MetroPivotViewer()
{
layoutUpdatedFinished = new UiHelper();
IsLoading = true;

this.StateSynchronizationFinished += MetroPivotViewer_StateSynchronizationFinished;
this.LayoutUpdated += MetroPivotViewer_LayoutUpdated;
}

void MetroPivotViewer_LayoutUpdated(object sender, EventArgs e)
{
layoutUpdatedFinished.Reset();
}

void MetroPivotViewer_StateSynchronizationFinished(object sender, EventArgs e)
{
layoutUpdatedFinished.SetTimeout(300, () =>
{
IsLoading = false;
this.View = this.GraphView;
NotifyItemsLoaded();
});
}

public event EventHandler ItemsLoaded;
public void NotifyItemsLoaded()
{
if (ItemsLoaded != null)
ItemsLoaded(this, null);
}

#region INotifyPropertyChanged

public event PropertyChangedEventHandler PropertyChanged;

public void NotifyPropertyChanged(string propName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}

#endregion

public override void OnApplyTemplate()
{
base.OnApplyTemplate();
}
}

public class UiHelper
{
private readonly DispatcherTimerContainingAction timer;

public UiHelper()
{
timer = new DispatcherTimerContainingAction();
}

public void SetTimeout(int milliseconds, Action action)
{
timer.Interval = new TimeSpan(0, 0, 0, 0, milliseconds);
timer.Action = action;
timer.Tick += OnTimeout;
timer.Start();
}

public void Reset()
{
timer.Stop();
timer.Start();
}

private void OnTimeout(object sender, EventArgs arg)
{
timer.Stop();
timer.Tick -= OnTimeout;
timer.Action();
}
}

public class DispatcherTimerContainingAction : DispatcherTimer
{
public Action Action { get; set; }
}
}

Source:  https://github.com/stevenh77/PivotViewerWithItemsLoadedEvent

Monday, 3 December 2012

Application Library Caching with PRISM

Your main Shell project xap file will reference all your application dependencies with Copy Local = true, which ensures your application has the DLL available.

For each referenced library, if it has been signed and a *.extmap.xml file is found in the same directory as the DLL then a zip file will be created for it in the Web Server ClientBin folder.  If not then the DLL will be be copied directly into the Shell.xap.

All your “Module” project / xap files should reference their dependencies with Copy Local = false.  This will let Visual Studio build each module project xap files but not copy the referenced libraries into the xap.

imageFor example this is the Prism extmap.xml file:

extmap

<?xml version="1.0"?>
<manifest>
<assembly>
<name>Microsoft.Practices.Prism</name>
<version>4.1.0.0</version>
<publickeytoken>31bf3856ad364e35</publickeytoken>
<relpath>Microsoft.Practices.Prism.dll</relpath>
<extension downloadUri="Microsoft.Practices.Prism.zip" />
</assembly>
</manifest>

AppManifest.xaml


This file is contained within each xap file and lets Silverlight know whether dependencies can be found within the xap or externally.


  • The “Deployment.Parts” section contains the libraries with Copy to Local = true.

  • The “Deployment.ExternalParts” section contains libraries with Copy to Local = false.

Note:  When PRISM loads modules it does not automatically download ExternalParts, see here. Here is an example of an AppManifest.xaml file:

<Deployment xmlns="http://schemas.microsoft.com/client/2007/deployment" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" EntryPointAssembly="PivotViewerDemo" EntryPointType="PivotViewerDemo.App" RuntimeVersion="5.0.61118.0">
<Deployment.Parts>
<AssemblyPart x:Name="PivotViewerDemo" Source="PivotViewerDemo.dll" />
<AssemblyPart x:Name="System.Xml.Serialization" Source="System.Xml.Serialization.dll" />
<AssemblyPart x:Name="System.Xml.Linq" Source="System.Xml.Linq.dll" />
</Deployment.Parts>
<Deployment.ExternalParts>
<ExtensionPart Source="System.Windows.Controls.zip" />
<ExtensionPart Source="System.Windows.Controls.Pivot.zip" />
</Deployment.ExternalParts>
</Deployment>

Configuring Silverlight application projects (Xap files)


Don’t forget to switch on application library caching for all your Silverlight applications (Shell and module projects).

image

How to cache your own Silverlight libraries


Simply sign the library (Project > Properties > Signing) by creating a new key file which requires a password then manually create an extmap.xml file:


image


Where to find the extmap.xml files


If you don’t have access to the extmap.xml files just create them yourself. 


You’ll need to know the assembly version number, right click on the file in Windows Explorer, select properties then click the Details tab.


assembly version


To find out the public key token use the sn.exe (strong name) application that comes with Visual Studio:


sn


See earlier in this blog post for an example of an *.extmap.dll file.


I want to store copies of each of my references within my code base, where can I find the DLLs


While many people use Nuget nowadays you may still wish to store the DLLs files yourself.  Here is a quick lust of locations so you can find them.


The Silverlight “core” libraries do not have to be included in either xap or zip files and can always be set to Copy Local False and do not need to be stored within your code base.


image


Other Microsoft and third party libraries can be added to a libraries (libs) folder within your solution, don’t forget to include the extmap.xml files.  Once the files are installed the Microsoft SDK files can be found here:


image


PRISM libraries can be downloaded from CodePlex:  http://compositewpf.codeplex.com/


Expression libraries can be downloaded from Blend SDK, Blend Service Pack, Silverlight Tools SP1, VS 2010 SP1.