Archive for the ‘Silverlight’ Category
Avoid incorrect Silverlight XAP file caching
The code below appends the last-write filedate of the Silverlight Application XAP file to the path in the source parametre of the Silverlight object tag.
This will ensure that poorly constructed caching functionality of webbrowsers and proxy servers doesn’t incorrectly use old, wrong builds of the XAP file.
However it will still allow these caches to work. Furthermore a check is performed to avoid XAP file path alteration during debugging, this is to allow debugging tools such as Silverlight Spy to continue functioning.
<object id="Xaml1" data="data:application/x-silverlight-2," type="application/x-silverlight-2"
width="100%" height="100%">
<%––<param name="source" value="ClientBin/SilverlightApp.xap"/>––%>
<%
string orgSourceValue = @"ClientBin/SilverlightApp.xap";
string param;
if (System.Diagnostics.Debugger.IsAttached)
param = "<param name=\"source\" value=\"" + orgSourceValue + "\" />";
else
{
string xappath = HttpContext.Current.Server.MapPath(@"") + @"\" + orgSourceValue;
DateTime xapCreationDate = System.IO.File.GetLastWriteTime(xappath);
param = "<param name=\"source\" value=\"" + orgSourceValue + "?ignore="
+ xapCreationDate.ToString() + "\" />";
}
Response.Write(param);
%>
<param name="onError" value="onSilverlightError" />
FocusHelper
Here is a little helper class I use when implementing tab navigation in Silverlight. When FocusHelper.Start() is called at application startup it simply creates a timer which attempts to give the focused element a red border and a slightly red background. When I say attempts it’s because themes and styles may prevent the changes from showing. I have often found it helpful, because it is almost never clear which element in Silverlight has the focus. Notice that the functionality is disabled if your browser’s zoom is different from 100%.
public static class FocusHelper
{
public static void Start()
{
focusBorderBrush = new SolidColorBrush(Colors.Red);
focusBackground = new SolidColorBrush(Colors.Red);
focusBackground.Opacity = 0.1;
focusTimer = new Timer(new TimerCallback((o) =>
{
try
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
object temp = null;
if (System.Windows.Application.Current.Host.Content.ZoomFactor==1)
temp = FocusManager.GetFocusedElement();
if (temp != lastFocus)
{
if (temp is Control)
{
//Give the last control back its original color
if (lastFocus != null)
{
lastFocus.BorderBrush = lastBrush;
lastFocus.BorderThickness = lastThickness;
lastFocus.Background = lastBackground;
}
lastFocus = temp as Control;
lastBrush = lastFocus.BorderBrush;
lastThickness = lastFocus.BorderThickness;
lastBackground = lastFocus.Background;
lastFocus.BorderBrush = focusBorderBrush;
lastFocus.BorderThickness = new Thickness(1);
lastFocus.Background = focusBackground;
}
}
});
}
catch
{
}
}), null, 0, 100);
}
private static System.Threading.Timer focusTimer;
private static Control lastFocus = null;
private static Thickness lastThickness;
private static Brush lastBrush;
private static Brush lastBackground;
private static Brush focusBorderBrush;
private static Brush focusBackground;
}
PostponingTimer
This is a small timer class that I have found useful a couple of times.
It takes a job and a timeout in its Run() method, which it executes
after the timeout, unless you call the Run() method again, in which
case it postpones the execution of the job. I have mostly used this
in connection with some type of user input. For instance, doing
something when there has been a sufficient pause in scrolling or typing.
/// <summary>
/// This class can be used to execute a job just once after a specified
/// time since the last of a series of events has fired.
/// For instance, when implementing an Auto-Save feature in a textbox you
/// might want to avoid saving on every keypress event. In this case you can
/// call Run(() => Save(), 5000) in each keypress event. The PostPoningTimer
/// will then make sure that Save() is executed one time when 5 seconds has
/// past since the last keypress event. Any new keypresses will of course
/// repeat the process.
/// </summary>
public class PostponingTimer
{
private Timer timer;
private Dispatcher CurrentDispatcher
{
get
{
#if SILVERLIGHT
return System.Windows.Deployment.Current.Dispatcher;
#else
return Dispatcher.CurrentDispatcher;
#endif
}
}
private void Execute(Action job, Dispatcher dispatcher)
{
#if SILVERLIGHT
dispatcher.BeginInvoke(job);
#else
dispatcher.Invoke(job);
#endif
}
/// <summary>
/// If you keep calling Run() within timeout, job never gets executed.
/// Only when you stop calling Run() job will run once after timeout
/// milliseconds.
/// <para>Job will run on calling threads dispatcher. If in silverlight
/// the UI threads dispatcher is used.</para>
/// </summary>
/// <param name=”job”></param>
/// <param name=”timeout”></param>
public void Run(Action job, int timeout)
{
//Make sure the timer from last call is prevented from running.
if (timer != null) timer.Dispose();
//When not in SILVERLIGHT the line below makes sure to use the
//dispatcher of the calling thread.
//In silverlight the UI thread dispatcher is used.
Dispatcher dispatcher = CurrentDispatcher;
timer = new Timer(new TimerCallback((o) =>
{
Execute(job, dispatcher);
}), null, timeout, Timeout.Infinite);
}
/// <summary>
/// If you keep calling Run() within timeout, job never gets executed.
/// Only when you stop calling Run() job will run once after timeout
/// milliseconds.
/// <para>Job will run on the timer’s thread.</para>
/// </summary>
/// <param name=”job”></param>
/// <param name=”timeout”></param>
public void RunNonUI(Action job, int timeout)
{
//Make sure the timer from last call is prevented from running.
if (timer != null) timer.Dispose();
timer = new Timer(new TimerCallback((o) =>
{
job();
}), null, timeout, Timeout.Infinite);
}
/// <summary>
/// If you keep calling Run() within timeout, job never gets executed.
/// Only when you stop calling Run() job will run once after timeout
/// milliseconds.
/// <para>Actions will run on calling threads dispatcher. If in
/// silverlight the UI threads dispatcher is used.</para>
/// </summary>
/// <param name=”job”></param>
/// <param name=”timeout”></param>
/// <param name=”callback”></param>
public void Run(Action job, int timeout, Action callback)
{
//Make sure the timer from last call is prevented from running.
if (timer != null) timer.Dispose();
//When not in SILVERLIGHT the line below makes sure to use the
//dispatcher of the calling thread.
//In silverlight the UI thread dispatcher is used.
Dispatcher dispatcher = CurrentDispatcher;
timer = new Timer(new TimerCallback((o) =>
{
Execute(job + callback, dispatcher);
}), null, timeout, Timeout.Infinite);
}
/// <summary>
/// If you keep calling Run() within timeout, job never gets executed.
/// Only when you stop calling Run() job will run once after timeout
/// milliseconds.
/// <para>Actions will run on the timer’s thread.</para>
/// </summary>
/// <param name=”job”></param>
/// <param name=”timeout”></param>
/// <param name=”callback”></param>
public void RunNonUI(Action job, int timeout, Action callback)
{
//Make sure the timer from last call is prevented from running.
if (timer != null) timer.Dispose();
timer = new Timer(new TimerCallback((o) =>
{
(job + callback)();
}), null, timeout, Timeout.Infinite);
}
}