by Sl.ayer
31. July 2010 02:42
Blur and DropShadow effects offer easy way to enhance your application’s visual appeal. But they come with a big price tag, and if used incorrectly, could destroy user experience instead of improving it. In order to make the best use of these effects in Silverlight, it is important to understand how they work behind the curtain.
When Silverlight runtime renders an element with an effect (whether built-in or custom pixel shader), it first renders that element and all of its children into an off-screen bitmap. Then, using that bitmap as the input for the pixel shader effect, the output of the pixel shader is finally rendered to the screen.
What’s interesting about the Blur effect is that unlike custom effects that can only have one pass, it executes in two passes. The first pass blurs the image horizontally, while second pass finishes with a vertical blur. This is called separable blur, and it saves a significant amount of computation in exchange for using extra memory and fill rate.
The cost of separable blur with radius N (N tap filter) can be estimated as: 2 writes + 2 * N reads + 2 * N multiplies + 2 * (N – 1) additions per pixel. So, applying 9 tap blur effect to a 400 x 400 pixel element will take 3,200,000 memory operations and 4,800,000 arithmetic operations. Now you can see how applying the blur effect to a large element can choke even a high-end CPU. And yes, Silverlight 4 executes all effects, including blur and drop shadow, onto the CPU. The Windows Phone 7 version of Silverlight is an exception, because it doesn’t support custom pixel shaders, and executes Blur and Drop Shadow effects on the phone’s GPU.
The DropShadow effect is a little more complicated then the Blur effect. It starts in the same way as any other effect by rendering the element into a memory bitmap. Then an alpha mask is separated from the bitmap and blurred using the exact same two-pass method I described for blur. Finally, the bitmap and the blurred alpha mask combined to create an element with drop shadow.
Because DropShadow uses a blur filter, it will suffer the same performance problems as the Blur effect. Furthermore, DropShadow uses even more memory and more fill rate, making it very taxing on both the CPU and memory bandwidth. It is important to understand that the cost of applying the DropShadow effect depends entirely on the size of the element, regardless of how much or how little of the actual shadow can be seen.
As I mentioned before, applying an effect to an element with children will cause the complete visual sub-tree to be rendered into the bitmap and processed by pixel shader. This has an important implication – the easiest way to drive CPU utilization to 100% is to add a drop shadow to the large form with one tiny animated control.
This last bit of information about effects is not performance related, but still important to know. Applying an effect to a text element or its parent forces Silverlight to use its standard anti-aliased text rendering instead of ClearType. This is the second reason why you should not add effects to the top level controls.
Things you can do to improve performance
The recommendations I provide below hold true for all effects, but they are especially important for expensive effects such as DropShadow.
1. Use effects sparingly. This will not only improve your application’s performance, but it will also increase the impact from using them.
2. Avoid adding drop shadow to elements with children, especially if children are interactive or animated. In most cases, it should be possible to redesign the visual hierarchy in such a way that drop shadow is applied to an element without children.
3. Use alternative methods to achieve similar visual result. For example, drop shadow can be often approximated with the help of linear gradients. Pre-rendering the effect for static elements can offer big performance savings as well.
4. If you need to animate large element with a drop shadow, turn effect off before starting animation and turn it back on at the end. You will be surprised how much smoother animation will feel.
5. Consider creating a “fast” theme for your application with all nonessential effects removed. Netbook owners and mobile users will love you for this.
by Sl.ayer
22. July 2010 01:55
I was thinking of some fun ways to use the TipBubble control, aside from the obvious. Here’s an idea, how about using TipBubble to style TabControl?
Achieving the result you see on the image above is quite simple. Just make a copy of the default TabItem style and replace the TemplateTopSelected grid with the code below.
<Grid x:Name="TemplateTopSelected" Canvas.ZIndex="1" Visibility="Collapsed">
<tip:TipBubble
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1,1,1,0"
CornerRadius="3,3,0,0"
TipPosition="0.5"
TipSide="Bottom"
TipFill="#FcD400"
TipSize="10"
Margin="0 0 0 -8">
<tip:TipBubble.Background>
<LinearGradientBrush
EndPoint="0,0" StartPoint="0,1"
ColorInterpolationMode="ScRgbLinearInterpolation">
<GradientStopCollection>
<GradientStop Color="#FFE97F" Offset="1" />
<GradientStop Color="#FcD400" Offset="0" />
</GradientStopCollection>
</LinearGradientBrush>
</tip:TipBubble.Background>
<ContentControl
Cursor="{TemplateBinding Cursor}"
Height="Auto" Width="Auto"
x:Name="HeaderTopSelected"
FontSize="{TemplateBinding FontSize}"
FontWeight="Bold"
Foreground="#333" IsTabStop="False"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
Margin="6,4,6,4"/>
</tip:TipBubble>
</Grid>
Repeat this operation for TemplateBottomSelected, TemplateLeftSelected, and TemplateRightSelected to get the complete style. Remember to modify TipSide, Margin BorderThickness and CornerRadius to correspond with each template (i.e. tab on the bottom, tip on the top; tab on the left, tip on the right etc.)
by Sl.ayer
19. July 2010 18:40
TipBubble is one of the controls that comes with the Free Bubbles library (it is called this because its most obvious use is for making tooltips).
Below is a quick overview of TipBubble properties.
TipSide
TipSide property controls which side of the bubble to show the tip. It can be set to Bottom, Top, Left or Right.

TipPosition
TipPosition property controls positioning of the tip on the side of a bubble. It accepts values from the 0 to 1 range, with 0 corresponding to top or left, 0.5 center, and 1 right or bottom.

TipSize
TipSize property allows you to change the size of the tip. Since the tip is made from an equilateral triangle, TipSize is the size of all of its sides.
TipFill
TipFill property defines the Brush used to fill the tip. Typically, TipFill should use the same Brush as Background property.
TipStrokeThickness
TipStrokeThickness defines the width of the stroke around the tip. In most cases, it should be the same as the corresponding side of the BorderThickness property.
Background, BorderBrush, BorderThickness, Padding…
All common control properties behave in the same way as you would expect for all other controls.
Examples
Basic TipBubble

<tip:TipBubble Background="#FF7FBC65"
TipFill="#FF7FBC65"
TipSide="Left"
TipPosition="0.5"
TipSize="10"
Padding="10 5"
BorderThickness="3"
BorderBrush="#FF89EE78"
TipStrokeThickness="2" >
<TextBlock Foreground="White">
Background="#7FBC65"
<LineBreak/>
BorderBrush="#89EE78"
</TextBlock>
</tip:TipBubble>
TipBubbble With Complex Content

<tip:TipBubble Background="#FF7FBC65"
TipSide="Left"
TipPosition="0.5"
TipSize="10"
TipFill="#FF7FBC65"
BorderThickness="3"
BorderBrush="#FF89EE78"
TipStrokeThickness="2" >
<Grid>
<Rectangle Margin="5"
Fill="#FF6FCD52"
RadiusX="2"
RadiusY="2">
<Rectangle.Effect>
<BlurEffect Radius="9" />
</Rectangle.Effect>
</Rectangle>
<TextBlock Foreground="White"
Margin="12 6"
FontWeight="Bold">
Complex Content Element
<LineBreak/>
with blured Background
</TextBlock>
</Grid>
</tip:TipBubble>
ToolTip stlyed using TipBubble
ToolTip style (sans animations)
<Style TargetType="ToolTip" x:Key="tipBubbleStyle">
<Setter Property="Padding" Value="8"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToolTip">
<bubbles:TipBubble
BorderThickness="0"
Padding="10"
TipSide="Bottom"
TipPosition="0.2"
TipFill="LimeGreen"
TipStrokeThickness="0"
CornerRadius="5"
Content="{TemplateBinding Content}">
<bubbles:TipBubble.Background>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<GradientStop Color="Yellow" Offset="0.0" />
<GradientStop Color="Red" Offset="0.25" />
<GradientStop Color="Blue" Offset="0.75" />
<GradientStop Color="LimeGreen" Offset="1.0" />
</LinearGradientBrush>
</bubbles:TipBubble.Background>
</bubbles:TipBubble>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Styled ToolTip
<Grid Width="250" Height=”100” Background="#eee">
<ToolTipService.ToolTip >
<ToolTip Placement="Top" Style="{StaticResource tipBubbleStyle}">
<TextBlock Foreground="#fff" Background="#7000">
<Run FontWeight=”Bold”>TipBubble</Run> is fun…
</TextBlock>
</ToolTip>
</ToolTipService.ToolTip>
</Grid>

by admin
17. July 2010 00:35
For quite some time now, .NET developers have been left out in the cold without official support from Facebook. No more, my friends! Today, Andrey Goder announced the first release of Facebook’s official C# SDK in his blog post. For many of us, this raises the following questions: what does it mean for all the unofficial .Net SDKs floating around? Do I keep using my own Facebook library or should I switch to the official SDK? The decisive factor in answering this question for all Silverlight developers is, of course, Silverlight support. Based on the first look, the official SDK is not Silverlight ready, although it should be easy enough to add support for an asynchronous communication model. Also, Facebook SDK is quite similar to GraphLight, in that neither provides any help with Facebook authentication. All in all, the alpha state of the first official .Net SDK is pretty obvious. For now, I will stick with my own GraphLight, but I will keep an eye on the Facebook SDK to see how its Silverlight support progresses.
by Sl.ayer
16. July 2010 05:17
I’ve been working on my Silverlight Comic Creator application for a pretty long time now. One of the more difficult tasks was creating speech bubble control that is customizable, easy to use and one that looks like it belongs in the comic. Well, today I am releasing my free Comic Bubble control to the public, so your application can have cool speech bubbles too without having to do all the heavy lifting.
You can add comic bubble to your Silverlight application in a few easy steps:
1. Download Free Comic Bubble Library
2. Add FreeBubbles.dll to your project references
3. Add custom namespace to the top parent control
<UserControl x:Class="BubblesApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:bubbles="clr-namespace:FreeBubbles;assembly=FreeBubbles"
4. Add Bubble control to your XAML
<bubbles:Bubble Text=”Hello”
FontFamily="Arial"
FontSize=”22”
OutlineThickness="2"
AllowEdit="True"
TailPoint=”30 70” />
5. Customize Bubble’s appearance by changing its properties
License
Comic Bubble Control is free for use in any non-commercial project. Send me a link to your project; I would love to see the creative ways that this control can be used.
by admin
14. July 2010 06:15
First, let me clarify what I mean by “application hijacking.” The traditional definition of hijacking is the following: “To seize control of a vehicle by use of force, especially in order to reach an alternate destination.” By modifying the definition to make it appropriate for web applications we get the following: Copying or embedding an application in a way that is not intended or permitted by the owner, with the goal of attracting users to the hijacker’s website. This issue is not new, nor is it exclusive to applications. Sites have being battling “deep linking,” copying of images, and other copyrighted materials for a long time now. Fortunately, a Silverlight application can be hardened to resist hijacking in a way that image or other passive content cannot. Below, I review different forms of application hijacking and explain how to detect them. Xap hijacking This most brazen form of application hijacking is done by downloading an application file (.xap) and placing it on the hijacker’s server. Guarding from this type of hijacking is important because it cannot be detected by analyzing web server logs. Luckily, detecting xap hijacking is pretty easy. Simply compare the location reported by App.Current.Host.Source to your own. If the location is not the one you expect then, your application has been hijacked. Comparing domains should be sufficient for most cases. if (App.Current.Host.Source.Host != "mydomain.com")
//sound the alarm!
Application “deep linking”
This happens when an application is embedded into the page of an unauthorized website (using <object> tag or silverlight.js) while pointing to the original xap file. This is probably the most common form of unauthorized embedding. It requires very little effort on the part of the hijacker, and leaves the owner with the bill for consumed bandwidth.
To detect if an application is deep-linked, check HtmlPage.Document.DocumentUri to see if the hosting page is located on the authorized domain. Watch out for InvalidOperationException! If you get it while trying to access HtmlPage’s properties, that means that the host webpage and your application are being served from different domains. See Security Settings in HTML Bridge for explanation. If you want to perform a deep-linking check on your own application hosted from a different domain (for example CDN), then you need to add the enableHtmlAccess parameter to your <object> tag.
While working on sample application, I noticed that xap files hosted on dropbox.com appear to be immune to deep-linking. I am not 100% sure why, but my current theory is that it is due to Content-Type set to “application/octet-stream.” You can also use more traditional techniques to fight deep linking, such as checking http referrer.
Iframe embedding
This situation is not specific to Silverlight apps, but to web pages in general. The solution to fight iframe embedding is often called “frame busting.” To bust out of iframe, all you need to do is to put the following javascript code in you page:
<script type="text/javascript">
if(top.location != location)
{
top.location.href = document.location.href;
}
</script>
Deterrents
If you detect that your application is hijacked, you have a few choices:
- Disable application without any explanation to the user
- Show user a message with hyperlink button offering to go to the application’s original site
- Keep working as if nothing happened, but send information about the hijacker’s website to your own web service (think of it as a Lojack for your app).
Whatever measure you choose, be considerate to your users. They are not the ones responsible for your application hijacking.
Conclusion
All this work wouldn’t be worth much if a hijacker can disassemble your application, and easily locate and neutralize your countermeasures. That is why I would recommend to always obfuscate your application if you are going to place anti-hijacking code in it.
It is worth remembering that embedding is not always bad; in fact some websites rely on embedding in their business model and actively encourage it. If your application is a popular target for embedding, you may want to consider making use of it rather then trying to fight it.
by admin
10. July 2010 22:29
In my previous post about the GraphLight library, I mentioned that the first step in using the library is to supply it with an access token. What I conveniently skimmed over is the explanation of what an access token is and how does one get a hold of it. I did this because answering those questions isn’t simple, and would benefit from dedicated elaboration. According to Facebook: “An access token allows an application to perform authorized requests on behalf of the user by including the access token in Graph API requests.” You can read about the process of obtaining an access token on the Facebook Developers Site. Although Facebook documentation provides a good starting point, it does not account for peculiarities of Silverlight. In this post, I will go over issues I encountered while implementing Facebook authentication in a Silverlight OOB application, and offer my solutions. Facebook documentation outlines two main flows of authentication available to applications: The first method utilizes sequence of redirects to Facebook site and back; the second method uses single sign-on with the JavaScript SDK. Of the two, only the former method can be used in a Silverlight OOB application due to restrictions on access to the hosting page’s DOM. Upon closer examination, the Desktop Application Authentication process emerges as the most obvious choice for an OOB application. Implementing a desktop authentication flow in accordance with Facebook documentation is quite straightforward: - Create WebBrowser control in code or in XAML
- Navigate to https://graph.facebook.com/oauth/authorize…
- Intercept the redirect to login_succes.html using LoadCompleted event and read the access token out of the URL
Problem #1 WebBrowser control needs Full-Trust to show pages from sites other then application’s origin. Because the Facebook authentication process requires redirect to facebook.com, the OOB application must be in full-trust mode! After many different attempts to find an acceptable workaround for standard OOB applications, I came to the conclusion that although it can be done, the resulting user experience is so poor that it is simply not worth it. Resolution: Configure application to require Full-Trust. Problem #2 Using the LoadCompleted event to intercept the redirect to login_succes.html doesn’t work because the Uri property of NavigationEventArgs is always null. If one is unable to read the access token out of the URL, using the Desktop Application Authentication process is no longer an option. Resolution: An alternative approach comes in the form of an authentication flow recommended for Web Applications and Mobile Applications. Web application authentication uses a two-step process, with the first step similar to that of desktop authentication, but instead of an access token, it returns code that can be exchanged for an access token in a separate step. In order to detect redirects and pass code to the Silverlight application, following steps need to be taken: 1. Create success.html page <html>
<head>
<title>Facebook Login Callback</title>
<script type="text/javascript">
window.external.notify(window.location.href);
</script>
</head>
<body />
</html>
2. Success page should be hosted on the same domain as the application and its url should start with Connect URL (see Facebook connect settings). Both conditions are sine quibus non.
3. Point redirect_uri parameter to the location of the success page
4. Add ScriptNotify handler to WebBrowser control:
browser.ScriptNotify += (a, b) =>
{
int n = b.Value.IndexOf("?code=");
if (n > 0)
{
//extract code from b.Value
//exchange code for access token as described in Facebook documentation
WebClient wc = new WebClient();
wc.DownloadStringAsync(new Uri(
string.Format(token_xchange, app_id, redirect_url, secret, code)));
wc.DownloadStringCompleted += (c, d) =>
{
//extract access token from d.Result
LoginSuccess(access_token);
};
}
else
{
if (b.Value.IndexOf("user_denied") > 0)
{
LoginFailed();
}
}
};
At last a bit of good news: The method described above actually works, but…
Problem #3
Doing a token exchange from a Silverlight application requires a secret key to be stored inside of the package redistributed to the end users, which is inherently not secure.
Resolution: Replace success.html with success.aspx or success.php or any other technology that allows one to execute code server-side. Perform token exchange on the server and simply pass the access token to ScriptNotify handler.
In an attempt to find a simpler solution, I found a post on the Facebook developers forums showing a way to get an access token in one step, without going through a token exchange. Unfortunately, that method relies on undocumented features and looks kind of “hacky,” so I am not going to present it here.
Postmortem
Implementing Facebook authentication in an OOB silverlight application turned out to be a challenge. Most of the issues I encountered were related to limitations of the WebBrowser control. Some security restrictions were expected and quite reasonable, while others appear to be to overreaching. It would be nice to see Microsoft considering use cases for Silverlight applications needing to login to OAuth based services (Facebook, Twitter, Flicker…).
Bonus feature: Logout or “What goes up must come down“
After all the trouble with authentication, it would be nice if logging out was simple… and it mostly is. Presently the only way to properly log a user out of Facebook is by redirecting the user to logout.php with app id and session as parameters. One little problem is how do we get a hold of the session? Well, as it happens, session is part of the access token and can be extracted from it with little effort.
private string logout_format =
"http://www.facebook.com/logout.php?app_key={0}&session_key={1}&next={2}";
public void Logout(string access_token)
{
access_token = HttpUtility.UrlDecode(access_token);
int s = access_token.IndexOf("|");
int e = access_token.LastIndexOf("|");
string session = access_token.Substring(s + 1, e - s - 1);
browser.Navigate(new Uri(string.Format(logout_format, app_id,
session, HttpUtility.UrlEncode(OAuthUrl))));
}
by admin
2. July 2010 17:12
If you are developing applications for Facebook, then you know that the old Facebook REST API has been replaced with the new Graph API. To make sure that my Facebook applications keep working, and considering the uncertain future of the Facebook Developer Toolkit, I decided to write my own Graph SDK - GraphLight. In designing GraphLight, my major goals were to make it small and simple to use, and to be compatible with the asynchronous programming model supported by Silverlight. After some experimentation, I decided to use Reactive Extensions Library to make the most of the asynchronous nature of Silverlight. GraphLight is very easy to use, as I will demonstrate with the following samples: First, let’s initialize GraphLigh by providing it with a valid access_token and then get information about the current user: Profile Me;
public MainPage_Loaded()
{
GraphApi.access_token = access_token;
GraphApi.Me.Subscribe(OnMe);
}
private void OnMe(Profile profile)
{
me = profile;
name.Text = me.name;
about.Text = me.about;
pic.Source = new BitmapImage(new Uri(me.Picture));
}
Next, let’s get the list of friends:
Me.Friends.Subscribe(
freinds =>
{
foreach (Profile friend in friends)
// do something application specific
}
);
Uploading a photograph is also quite easy:
album.Upload(“Me wrestling with polar bear”, photoStream)
.Subscribe(pid => status.Text = "Upload succesful pid=" + pid);
You can use reactive extensions to simplify complex asynchronous scenarios. For example, you can use ForkJoin to wait for all asynchronous downloads to finish, and then call the subscriber with the results:
List<Photo> allPhotos = new List<Photo>();
albums.Where(a => a.name != "Profile")
.Select(b => b.Photos)
.ForkJoin().Subscribe(
v =>
{
foreach (var photos in v)
{
allPhotos.AddRange(photos);
}
}
);
Fair warning: GrahLight is not a fully supported, take-care-of-it-all library. If you like to tinker with your code and modify your library to meet your needs, then GraphLight could be for you. I would also recommend looking at similar libraries on CodePlex, for example Facebook Graph Toolkit.
|
|
|