Tuesday, December 1, 2009
Microphone Access in Silverlight App: LIVE
You'll need to create an account and connect to a tutor to see it in action (click the 'Connect to a Tutor' button in the classroom to get started)--
Thursday, January 22, 2009
Microphone access in Silverlight via Flash and JavaScript
While it's true that you'll need to dip into Flash or Java for microphone/webcam support (at least until Silverlight 3, and possibly not even then), there's no reason you can't take advantage of Silverlight as your base application host and selectively use Flash as necessary for Silverlight's missing features. Then, using a JavaScript bridge, you can get these browser technologies communicating with each other fairly painlessly. This integrated solution is what we're considering at Tutor.com when we add voice communication support to the Tutor.com Classroom, and this post will detail how to use Flash for microphone support inside a Silverlight application, where the button controlling the microphone on/off switch is in the Silverlight application.
Flash: Microphone management
First, we'll create a simple Flash movie (I'm using ActionScript 2) that manages and outputs microphone input. Thankfully, there's really very little code you need to write to do this; just note that your Flash movie must be at least 250x150 to allow room for the microphone Allow/Decline dialog, and if you don't want the movie to be visible, you need to set its background color to transparent.
As an aside, note that there's similarly very little code you need to write to connect to a Flash Media Server (FMS) for real-time communication, although the example here omits the FMS part. As another aside, note that the code for Flash webcam support is almost identical, except instead of a Microphone object you're working with a Camera object.
OK, so in the first frame of your Flash movie, write a function to access the microphone and monitor microphone activity:
var mic:Microphone = null;
function toggleVoice(isOn:Boolean)
{
//setup the mic
if (mic == null)
{
//call Microphone.get() to access the microphone and prompt user with Allow/Decline dialog
mic = Microphone.get();
//Microphone.get() will return null if user declined access
if (mic == null)
return;
//setup onActivity handler to get notification of mic activity
mic.onActivity = function(active:Boolean)
{
//call out to JavaScript bridge via ExternalInterface
flash.external.ExternalInterface.call("IsTalking", active);
};
//create movie clip and attach mic to clip so we can hear output
this.createEmptyMovieClip("sound_mc", this.getNextHighestDepth());
sound_mc.attachAudio(active_mic);
}
//set the microphone gain as per the isOn input variable
mic.setGain(isOn ? 50 : 0);
}
Below the function, add a callback handler that makes the function callable via JavaScript:
flash.external.ExternalInterface.addCallback("ToggleVoice", this, toggleVoice);
Html: Application host page
When you add a Silverlight application to your solution in Visual Studio, the boilerplate html makes your application full-screen in the browser window (as in the Tutor.com Classroom); this is exactly what we ant. Next, we need to add our Flash html object tag. Silverlight is a bit picky about where you add this html tag since you need to preserve this 100% height style, so slot the Flash object tag immediately before the div tag, and style it with "position:absolute" so that it doesn't interfere in the html layout:
<form id="form1" runat="server" style="height:100%;">
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<object
id="voice"
style="position:absolute;"
classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=8,0,0,0"
width="250"
height="150"
align="middle"
...
/>
<div style="height:100%;">
<asp:Silverlight
ID="Xaml1"
runat="server"
...
/>
</div>
</form>
Javascript: Flash/Silverlight bridge
Next, we'll create the JavaScript function that our Silverlight app will call, which will in turn call into our Flash movie to set the Microphone input status. Since our Flash movie registered the ToggleVoice() callback function using ExternalInterface, Flash added a JavaScript entry point to function when the Flash movie loaded:
<script language="javascript" type="text/javascript">
function toggleVoice(on)
{
var flashVoiceObject = thisMovie("voice");
if (!flashVoiceObject)
return;
flashVoiceObject.ToggleVoice(on);
}
function thisMovie(movieName) {
if (navigator.appName.indexOf("Microsoft") != -1) {
return document.getElementById(movieName);
}
else {
return document[movieName];
}
}
</script>
We can also very simply call from JavaScript into Silverlight, and we'll do this to alert our Silverlight application when Flash notifies us of microphone activity:
function IsTalking(active)
{
//access the Silverlight application
var control = document.getElementById("Xaml1");
control.Content.Page.ToggleIsTalking(active);
}
Silverlight – Microphone toggle button
Finally, in Page.xaml, add a toggle button with Checked and Unchecked handlers, and an indicator that we'll show when the microphone is active:
<ToggleButton Content="Toggle Microphone Input" Checked="ToggleVoice_CheckedToggled" Unchecked="ToggleVoice_CheckedToggled" />
<TextBlock Text="You are talking..." Visibility="Collapsed" x:Name="IsTalkingIndicator" />
Then in Page.xaml.cs, implement the handler and call into the JavaScript function:
private void ToggleVoice_CheckedToggle(object sender, RoutedEventArgs e)
{
//call js layer to set microphone state
ScriptObject voiceToggleScriptObject = (ScriptObject)HtmlPage.Window.GetProperty("toggleVoice");
ToggleButton tb = sender as ToggleButton;
voiceToggleScriptObject.InvokeSelf(tb.IsChecked.Value);
}
Lastly, implement the ToggleIsTalking() function that we'll call from JavaScript when the Flash movie responds to the microphone's onActivity() event. You just need to decorate this function with the [ScriptableMember] attribute so that Silverlight registers the function with the JavaScript runtime:
[ScriptableMember]
public void ToggleVoiceOn(bool On)
{
IsTalkingIndicator.Visibility = (On) ? Visibility.Visible : Visibility.Collapsed;
}
And that's it! You now have a relatively straightforward Flash <=>JavaScript <=> Silverlight solution that affords you the best of all worlds.
Tuesday, December 9, 2008
Tutor.com Classroom How-To #11: Build a Silverlight ToolbarButton user control
These How-To tips are taken from The Tutor.com Classroom: Architecture and techniques using Silverlight, WPF, and the Microsoft .NET Framework.
You can check out the Silverlight Tutor.com Classroom in "practice" mode, although the real experience is with a live tutor on the other side!
One of the controls missing out-of-the gate from Silverlight is the Toolbar. There is no magic to the WPF Toolbar (it’s just a control container that auto-docks itself and auto-styles its children), but for free you get the flat button look-and-feel that users expect at the top of an application.
In Silverlight, we have to manually create this look-and-feel. Since our application’s toolbar consists solely of buttons (both normal and toggle buttons), and since the buttons in our toolbar have the “icon followed by a text description” format, we can abstract this to build the ToolbarButton user control.
Begin by creating a new user control. Define the styles for the Hover and Pressed states in your user control’s Xaml resources:
<UserControl.Resources>
<LinearGradientBrush x:Key="HoverBrush" StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="White" />
<GradientStop Color="#F8D28F" Offset=".3" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<LinearGradientBrush x:Key="PressedBrush" StartPoint="0,0" EndPoint="0,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#F8D28F"/>
<GradientStop Color="White" Offset=".3" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</UserControl.Resources>
Then, use a Grid to hold two Border objects; one contains the image and the text label, and the other is a half-opaque, white filled Border that we use when the button is disabled.
<Grid>
<Border x:Name="MainBorder" BorderThickness="1" CornerRadius="1" MouseEnter="Border_MouseEnter" MouseLeave="Border_MouseLeave" MouseLeftButtonUp="Border_MouseLeftButtonUp" Cursor="Hand" Margin="1">
<StackPanel Orientation="Horizontal" Margin="5,1,5,1">
<Image x:Name="BorderImage" Width="16" />
<TextBlock x:Name="BorderTextBlock" Style="{StaticResource blackText}" Margin="5" />
</StackPanel>
</Border>
<Border Background="#B2FFFFFF" x:Name="DisabledBackground" BorderThickness="1" CornerRadius="2" BorderBrush="#B2FFFFFF" Visibility="Collapsed" />
</Grid>
Next, wire up the IsEnabled, ToolTip, ImageSource, and Caption properties, and implement the hover and click functionality. Note that these properties are backed by dependency properties on the objects we defined in our Xaml.
public partial class ToolbarButton : UserControl
{
bool m_IsEnabled = true;
public new bool IsEnabled
{
set
{
MainBorder.Background = null;
MainBorder.BorderBrush = null;
DisabledBackground.Visibility = (value) ? Visibility.Collapsed : Visibility.Visible;
}
}
public string ToolTip
{
get { return ToolTipService.GetToolTip(MainBorder).ToString();}
set { ToolTipService.SetToolTip(MainBorder, value);}
}
public ImageSource ImageSource
{
get { return BorderImage.Source;}
set { BorderImage.Source = value;}
}
public string Caption
{
get { return BorderTextBlock.Text;}
set { BorderTextBlock.Text = value;}
}
public bool IsToggleButton { get; set; }
public bool IsToggled { get; set; }
public event MouseButtonEventHandler Clicked;
public ToolbarButton()
{
InitializeComponent();
}
private void Border_MouseEnter(object sender, MouseEventArgs e)
{
//if we're a toggle button and we're on...
if (this.IsToggleButton && this.IsToggled)
return;
Border b = sender as Border;
b.Background = Resources["HoverBrush"] as Brush;
b.BorderBrush = new SolidColorBrush(ColorHelper.FromHexString("FFCA8103"));
}
private void Border_MouseLeave(object sender, MouseEventArgs e)
{
//if we're a toggle button and we're on...
if (this.IsToggleButton && this.IsToggled)
return;
Border b = sender as Border;
b.Background = null;
b.BorderBrush = null;
}
private void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (!m_IsEnabled)
return;
if (this.IsToggleButton)
{
this.IsToggled = !this.IsToggled;
//set state
Border b = sender as Border;
b.Background = (this.IsToggled) ? Resources["PressedBrush"] as Brush : Resources["HoverBrush"] as Brush;
}
if (this.Clicked != null)
this.Clicked(sender, e);
}
}
Finally, in your container Xaml, use the ToolbarButton class inside a StackPanel with Orientation set to Horizontal:
<StackPanel Orientation="Horizontal">
<local:ToolbarButton ImageSource="/Resources/board.png" Caption="Add Whiteboard" Clicked="AddWhiteboard_Click" Margin="1" />
...
</StackPanel>
Friday, November 14, 2008
Tutor.com Classroom How-To #10: manually detecting and installing the Silverlight plug-in
These How-To tips are taken from The Tutor.com Classroom: Architecture and techniques using Silverlight, WPF, and the Microsoft .NET Framework.Use the isInstalled() function provided by Silverlight.js:
You can check out the Silverlight Tutor.com Classroom in "practice" mode, although the real experience is with a live tutor on the other side!
<script language="javascript" type="text/javascript">
Silverlight.InstallAndCreateSilverlight = function(version)
{
var retryTimeout = 1000; //the interval at which instantiation is attempted(ms)
if (Silverlight.isInstalled(version))
{
...
}
else if (!Silverlight.isInstalled(version))
{
TimeoutDelegate = function()
{
Silverlight.InstallAndCreateSilverlight(version);
}
setTimeout(TimeoutDelegate, retryTimeout);
}
}
Silverlight.InstallAndCreateSilverlight('2.0.30923.0');
</script>
Thursday, November 13, 2008
Tutor.com Classroom How-To #9: creating a Path object from a Stroke
These How-To tips are taken from The Tutor.com Classroom: Architecture and techniques using Silverlight, WPF, and the Microsoft .NET Framework.Simply transfer Stroke stylus points to a PolyLineSegment on a Path:
You can check out the Silverlight Tutor.com Classroom in "practice" mode, although the real experience is with a live tutor on the other side!
static Path getPathFromStroke(Stroke str)
{
//make a path from this stroke
Path path = new Path();
PathGeometry pg = new PathGeometry();
//start our figure from the first stylus point in the stroke
PathFigure fg = new PathFigure();
fg.Segments = new PathSegmentCollection();
fg.StartPoint = new Point(str.StylusPoints[0].X, str.StylusPoints[0].Y);
PolyLineSegment seg = new PolyLineSegment();
//add each additional stylus point to the line segment
for (int x = 1; x < str.StylusPoints.Count; x++)
StylusPoint sp = str.StylusPoints[x];
seg.Points.Add(new Point(sp.X, sp.Y));
fg.Segments.Add(seg);
pg.Figures = new PathFigureCollection();
pg.Figures.Add(fg);
path.Data = pg;
return path;
}
Wednesday, November 12, 2008
Tutor.com Classroom How-To #8: trapping and processing mouse movement in an InkPresenter
These How-To tips are taken from The Tutor.com Classroom: Architecture and techniques using Silverlight, WPF, and the Microsoft .NET Framework.In the MouseDown event, instantiate a module-level Stroke object (e.g. m_DrawingStroke) to collect points traversed by the mouse. Fire the StrokeAdded event so that listeners can prepare for the operation as necessary. Most importantly, call CaptureMouse() to notify the mouse input engine to give you high frequency mouse event notifications.
You can check out the Silverlight Tutor.com Classroom in "practice" mode, although the real experience is with a live tutor on the other side!
void Whiteboard_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
//get our current position
Point p = e.GetPosition(this);
//create a new styluspoint collection for our new stroke
StylusPointCollection coll = new StylusPointCollection();
coll.Add(new StylusPoint() { X = p.X, Y = p.Y });
m_DrawingStroke = new Stroke(coll);
//fire notification event
if (this.StrokeAdded != null)
this.StrokeAdded(m_DrawingStroke);
//begin capturing mouse input
this.CaptureMouse();
}
In MouseMove, add the traversed point to the Stroke’s StylusPoints collection, and fire the StrokeChanging event to alert interested listeners.
void Whiteboard_MouseMove(object sender, MouseEventArgs e)
{
//get our current position
Point p = e.GetPosition(this);
//add the traversed point to our collection
StylusPoint sp = new StylusPoint() { X = p.X, Y = p.Y };
m_DrawingStroke.StylusPoints.Add(sp);
//fire notification event
if (this.StrokeChanging != null)
this.StrokeChanging(m_DrawingStroke);
}
In MouseUp, release mouse capture and fire the StrokeComplete event.
void Whiteboard_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//release mouse capture
this.ReleaseMouseCapture();
//fire notification event
if (this.StrokeComplete != null)
this.StrokeComplete(m_DrawingStroke);
}
Monday, November 10, 2008
Tutor.com Classroom How-To #6: creating a horizontal WrapPanel that is transform-aware and exposes row and column counts
These How-To tips are taken from The Tutor.com Classroom: Architecture and techniques using Silverlight, WPF, and the Microsoft .NET Framework.Begin by deriving from Panel, which is the base class for container controls, and override the MeasureOverride() and ArrangeOverride() functions. These functions are called iteratively as the layout engine determines how to distribute available visual space. Have them call a custom function that takes either the available size (from the measure pass) or the final size (from the arrange pass), and a ShouldArrange parameter to specify which pass is processing, and returns a Size.
You can check out the Silverlight Tutor.com Classroom in "practice" mode, although the real experience is with a live tutor on the other side!
private Size measureAndOptionallyArrangeItems(Size size, bool ShouldArrange)
{
Point point = new Point(0, 0);
Size s = new Size(size.Width, 0);
//consider scale transform that might be affecting us
double xfactor = 1;
double yfactor = 1;
if (this.RenderTransform != null)
{
if (this.RenderTransform is ScaleTransform)
{
ScaleTransform st = (ScaleTransform)this.RenderTransform;
xfactor = st.ScaleX;
yfactor = st.ScaleY;
}
}
double largestHeight = 0.0;
this.Rows = 0;
this.Cols = 0;
foreach (UIElement child in Children)
{
if (child.DesiredSize.Height > largestHeight)
largestHeight = child.DesiredSize.Height;
//first row?
if (this.Rows == 0)
this.Rows = 1;
double desiredWidth = child.DesiredSize.Width;
//does this child cause us to wrap?
if (point.X > 0 && point.X + desiredWidth > size.Width * (1 / xfactor))
{
this.Rows++;
s.Height += largestHeight * yfactor;
//goto the next line
point.X = 0;
point.Y += largestHeight;
largestHeight = child.DesiredSize.Height;
if (ShouldArrange)
child.Arrange(new Rect(point, new Point(point.X + desiredWidth, point.Y + child.DesiredSize.Height)));
//set our current location in this new line
point.X = desiredWidth;
}
else
{
if (ShouldArrange)
child.Arrange(new Rect(point, new Point(point.X + desiredWidth, point.Y + child.DesiredSize.Height)));
point.X = point.X + desiredWidth;
//if we're doing first row, set columns
if (this.Rows == 1)
this.Cols++;
}
}
s.Height += largestHeight * yfactor;
return s;
}
Thursday, November 6, 2008
Tutor.com Classroom How-To #4: enforcing an MVC-style architecture
These How-To tips are taken from The Tutor.com Classroom: Architecture and techniques using Silverlight, WPF, and the Microsoft .NET Framework.The benefits of MVC-style architecture are numerous: testability, modifiability, simplicity of design, etc., and WPF/Silverlight Xaml “binding” provide an ideal structure to effectively detach the front-end from middle-tier business objects.
You can check out the Silverlight Tutor.com Classroom in "practice" mode, although the real experience is with a live tutor on the other side!
One simple way to enforce MVC-style architecture is to put classes with distinct responsibilities in separate assemblies, and add the minimal set of references only as required by each assembly. This enforces the principle of separation of concerns, since you’ve actually made it impossible for code in one assembly to be concerned with the business of another if it shouldn’t!
Monday, November 3, 2008
Tutor.com Classroom How-To #1: sharing code between Silverliht and WPF applications
These How-To tips are taken from The Tutor.com Classroom: Architecture and techniques using Silverlight, WPF, and the Microsoft .NET Framework.To actually share the code, use compile-time code sharing by choosing “Add As Link” when adding project files, rather than using our source code management’s “Share”. Using the “Add As Link” technique ensures that as changes are made to shared code, successfully building the solution guarantees that the changes are valid across all three applications. Source code management “Share” requires developers to check in their changes, do a “Get Latest Version” on the shared files, rebuild the solution, make any necessary changes, repeat, etc. In the meantime, the build is potentially broken.
You can check out the Silverlight Tutor.com Classroom in "practice" mode, although the real experience is with a live tutor on the other side!
Tuesday, September 30, 2008
make sure you manually stop storyboards on hidden objects
storyboards continue to run even if the object you’re animating is invisible, so you’re generally burning CPU cycles for nothing. in silverlight, you can stop any storyboard just by calling Stop:
myStoryboard.Begin();
myStoryboard.Stop();
in WPF, you need to specifically let the runtime know that you want Stop functionality when you call Begin via the isControllable paramater:
myStoryboard.Begin(this, true);
myStoryboard.Stop();
Thursday, July 10, 2008
error adding service reference to silverlight 2 app
if you run into problems adding a service reference to a sl2b2 app, it’s likely due to a sl2b2 install bug that manifests itself if you installed with certain pre-conditions. to fix it:
-----
(from http://silverlight.net/forums/t/17500.aspx)
First check your Silverlight Tools for VS 2008 install size on Add/Remove Programs window. If it is 1.14 MB, then you need to do the following:
1) Uninstall your Silverlight Tools for VS 2008,
2) Remove (delete) the following dll C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Microsoft.VisualStudio.ServicesProxy.dll
3) Re-Install Silverlight Tools for VS 2008.
-----
Wednesday, June 18, 2008
wpf/silverlight links
scott guthrie’s silverlight 2 intros are here
some silverlight references/articles i’ve found very helpful:
Silverlight User Interface Controls - Silverlight
Working with Animations Programmatically (Silverlight 2)
Excellent Data Binding Overview
End to End DataCentric App <-- VERY GOOD OVERVIEW OF LOTS OF STUFF
asp.net mvc overview:
http://weblogs.asp.net/scottgu/archive/2007/11/13/asp-net-mvc-framework-part-1.aspx
wpf and mvc:
http://www.codeproject.com/KB/WPF/MVCtoUnitTestinWPF.aspx
some good blogs:
http://geekswithblogs.net/wynapsetechnicalmusings/Rss.aspx <---- DON’T MISS THIS ONE! it’s a compilation of others’ relevant blog posts
http://blogs.msdn.com/delay/rss.xml
http://blogs.msdn.com/brada/rss.xml
http://blogs.msdn.com/corrinab/rss.xml
http://blogs.msdn.com/silverlight_sdk/rss.xml
http://www.drwpf.com/blog/Home/tabid/36/rssid/1/Default.aspx
regarding reflector, app is here: http://www.aisto.com/roeder/dotnet/. msft also released a bunch of their source code recently, you can find the silverlight-related code here: http://www.microsoft.com/downloads/details.aspx?FamilyID=ea93dd89-3af2-4acb-9cf4-bfe01b3f02d4&DisplayLang=en
Sunday, June 8, 2008
silverlight 2 beta 2
installer is here: http://www.microsoft.com/downloads/details.aspx?FamilyId=50A9EC01-267B-4521-B7D7-C0DBA8866434&displaylang=en
there is no problem installing this on your normal dev machine, but note that i had to manually uninstall KB949325 (in Vista it's listed under Program and Features > Installed Updates) before i could get beta 2 installed.
a good summary of changes is here: http://adoguy.com/2008/06/06/What_s_Changed_in_Silverlight_2_Beta_2.aspx
and fuller lists of breaking changes (there are lots of them!) are here: http://msdn.microsoft.com/en-us/library/cc645049(VS.95).aspx and http://blogs.msdn.com/silverlight_sdk/attachment/8574227.ashx.
the release version is expected “end of summer”, so assuming beta 2 is as solid as beta 1 was, this is the version that the classroom will first go live with--
Thursday, May 15, 2008
wpf: key concepts
databinding is key to writing less code for populating fields. you can databind to anything that implements INotifyPropertyChanged (for objects) or INotifyCollectionChanged (such as ObservableCollection, for collections). the syntax uses “{}” brackets and the keyword “Binding” and looks like this:
<TextBox Text={Binding Path=Name} />
elements in your xaml inherit the DataContext (the object or collection that you’re binding to) from their parent object(s). you can set the DataContext in code or via markup with the Source attribute of a Binding markup that generally points to a static resource:
<TextBox Text={Binding Path=Name, Source={StaticResource MyCollection}} />
the syntax definitely feels weird at first, but it gets easier as you start using it, and it lets you have nice MVC-style UI/business logic separation.
ItemTemplate works like a repeater or grid template in asp.net. you define exactly how you want the items in your ItemsContainer (e.g. a listbox) to be displayed:
<ListBox ItemsSource="{Binding Conferences, Source={StaticResource ConferenceManagerDS}}" SelectionChanged="ConferencesListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Id}"></TextBlock>
<ListBox ItemsSource="{Binding Members}"></ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
see here for a good overview: http://www.vsj.co.uk/dotnet/display.asp?id=500
dependency properties
the idea here is that the property owner doesn’t necessarily know the value of his own property, since it “depends” on external factors, like whether or not an animation is occurring. so instead of creating a normal {get; set;} property, you “register” your property with the global, static “PropertyManager”, and then you access the value of your property via the instance method DependencyObject.GetValue(). so if you have a Button, you access it’s FontStyle property like this:
b.GetValue(Button.FontStyleProperty)
almost always the property author will implement a normal C#-style property accessor as well, which just calls the GetValue() and SetValue() dependency methods for you, so you can still say b.FontStyle = new Font() or in this example canvas.InkThickness = 4:
public int InkThickness
{
get { return (int)GetValue(InkThicknessProperty); }
set { SetValue(InkThicknessProperty, value); }
}
use the snippet "propdp" and most of the magic will be taken care of for you.
attached properties
attached properties are a special type of dependency property that allow a child element to set a property value that its parent reads.
as an example of why this is useful, think of how in WinForms every UI component derives from “Control”, and “Control” has properties like “Left” and “Top”. when a container goes to layout its children, it uses Control.Left. this means that the container has to have hard-coded logic that only something that derives from “Control” can be one of its children. this works out ok for core properties like Left and Top, but if you want to add another property that some UI components need, you either need to derive from Control and then have your custom controls derive from that derivation, or you need to edit the source for Control (if you have it) and add the property there. the problem is that the new property may or may not be relevant to all derived classes, and it may even interfere with a property that the derived class has added to itself.
attached properties let the container specify “i have these properties that are impt to me but may or may not be of interest to you”, and then the child can optionally “attach” a value to them. for example, to specify that a textbox in a canvas should have a left of 40, you write:
<TextBox Canvas.Left=”40” />
and to specify the row an element should be in inside a grid, you write:
<TextBox Grid.Row=”1” />
this allows a container to contain any type of child, not just those that derive from an expected type.
use the snippet “propa” and most of the magic will be taken care of for you.
routed events
this is just an elegant way of having Preview and non-Preview events. Preview events go top-down (they “tunnel”), and allow a parent to handle the event before it gets to a child. non-Preview events (they “bubble”) go from the child up. you register your events with the EventManager in a similar way that you do with dependency properties and the PropertyManager.
commands
these are WPF-only (i.e. they don’t exist in Silverlight 2 Beta 1). commands enable a MVC-type of design pattern, where the view (xaml) just asks the Controller (who implements ICommand) to perform an action or if an action is performable. josh smith has a good article on using commands here: http://www.codeproject.com/KB/WPF/MVCtoUnitTestinWPF.aspx.
triggers
another WPF-only feature, triggers do what you’d imagine: they let you specify a condition that causes an action. these are used extensively in styles when you want to have the style change on some event, for example:
<Style x:Key="MyContainer" TargetType="{x:Type ListViewItem}">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="Blue" />
<Setter Property="Cursor" Value="Hand"/>
</Trigger>
</Style.Triggers>
</Style>
Wednesday, March 26, 2008
silverlight 2 and IIS
if you want to access your silverlight 2 app from IIS, make sure you add a mime type in IIS for “.xap”:
Extension: .xap
MIME Type: application/x-msdownload
took me forever to figure out why it was working fine when running via the development server but not via IIS…
Friday, March 7, 2008
Mix08 days 2 and 3
http://msstudios.vo.llnwd.net/o21/mix08/08_WMVs/UX09.wmv
the ASP.NET MVC talk was also very interesting. MVC will live side-by-side with WebForms, and it gives a really clean (java) way to build test-driven web sites. it definitely has a future with us (it's in somewhat early beta now). you can watch or see slidedecks of it and others here:
-----
What's New in .NET 3.5, Rob Reylea, MSFT
- hardware-accelerated bitmap effects
- performance improvements
o cold-startup speed improvements of 15-40%
- easier install process
AOL Silverlight Mail Client Lessons Learner, AOL
- poorly attended, bad speakers, AOL irrelevant to this crowd even with ~50 million users
Silverlight 2.0, Karen Corby, MSFT
- design-ability improvements from 1.0
o user controls (encapsulation, re-use)
- derive from UserControl
o events at element level, as opposed to application level
o tabbing works automatically (like it does in html)
- custom controls - derive from Control
o use generic.xaml to specify style and template
- Parts Model for template support (override visual tree) - easy way for template designer t o say "these are the parts i'm expecting"
o ElementParts
§ Named elements in template
o StatesParts
§ Storyboard that controls the parts
o specify [TemplatePart()] attributes for each parts element
- Blend 2.5 has built-in support to build UserControls from selected set of controls
Steve Ballmer Keynote
- he's crazy and he loves developers
- silverlight is part of msft's long-term vision of web/desktop fusion
o 1.5 million silverlight downloads (did he say per day? possible?)
- in response to msft's diversity of businesses: you either broaden or you become irrelevant
- heathfall -> msft investment in healthcare
Social Networks, panel with Garret Camp (msft live) Marc Canter, Allen Hurff (MySpace), David Morin (business sn), someone from Facebook
- openId - relies on URL, not consumer friendly
o major players (facebook, msft live) are watching, but not adopting
- facebook charges $.50/app install
- privacy is the biggest issue, bigger than security and pedophiles
- lack of data portability is major issue, users need to preserve anonymity at times and share data across the web at other times
- 4/10,000 click through an ad
ASP.NET MVC, Scott Hanselman, MSFT
- implemented using HttpHandlers and HttpModules
- release expected later this year/early next
- side-by-side with WebForms
o more control over <html> output
o makes possible unit testing and test-driven development
o SEO and REST friendly url structures
o ideal separation of tiers
- request engine
o "route" is determined (routes specified in Application_Start) from specified URL (by default "/Controller/Action")
§ routing engine handles friendly url parsing and is decoupled from MVC
o controller method is invoked
o controller optionally talks to model
o controller passes off something to view
o view knows what its getting and how to render it
§ view can spit out html (WebForm, xslt, etc.), rss, json, etc.
§ view engine can be replaced (e.g. NHaml)
- to test controller, use empty view engine that implement IViewEngine
The Office Ribbon, Jensen Harris, MSFT (http://blogs.msdn.com/jensenh)
- easily the best presentation of the conference
- lots of prototyping; can we buy time in the UI lab?
- small buttons close to cursor or large buttons far away
- side vs. top
o people felt more comfortable on top in testing
o fear that sidebar would devolve into scrolling list
- evaluate
o longitudinal visibility - usage over time (i.e. 2 months, not 2 hours)
o feature affinity - how people use things together
o command loops - eliminate tab switches
o get fresh eyes!
o eye tracking - heat map, gaze tracking
- ask users where they think items should go
o some features like header/footer had 50/50% split
- iterate!
o account for iteration in dev schedule
o 5 major revisions, 4 later in the cycle
- when is a ribbon appropriate?
o real estate tradeoff, so make sure to take other things out
o lots of commands
o galleries, visual representations of features
Next Gen User Interfaces with WPF, Electric Rain
- workflow, design, build
o workflow = goals, foundation
o research, prototype, functional not pretty
- avoid monolithic specs in favor of rapid prototyping
o developers ask for product design specification when needed
Thursday, March 6, 2008
Mix08 day 1 notes
Key Note Addresses
- ray ozzie spends 30 minutes describing something we've all heard before and unfortunately have to hear more about once again, aka "cloud computing"
- msft still without a legitimate strategy to transform desktop monopoly to a web one
o connected pcs/devices
o web presence
o business apps
o virtualized servers/horizontal apps is key
- scott guthrie recounts his blog postings
- dean hachamovitch (ie8 general manager) reads too much from his script
o ie8 key focus on standard compliance and interopability (as opposed to ie7's focus on security)
§ w3c spec itself is vague and open to interpretation with regard to standards
§ css 2.1 support
§ poked fun at ie7's differences from firefox and safari
o looks more or less like ie7
o ie7 "compatability mode" controlled by developers
o html5
§ back button can work as expected with ajax
§ smooth experience when connectivity is lost
o integrated developer tools similar to firebug or webdevelopmenthelper (script debugging, css inspection)
o "activities" allow in-place right-click actions on selected text (i.e. select address, right-click, view map); very cool
o subscribe to "webslices" (slices of web pages); richer content/simpler implementation than rss
o ie8 beta 1 released
- scott guthrie returns to discuss silverlight 2.0 beta 1 release
- media and advertising
o adaptive streaming
o windows media services 2008 – scalable media hosting and delivery
o bandwidth savings: iis 7 bitrate throttling allows you to specify distinct bitrates for different downloads, so you deliver initial burst, then slower follow up
o jon harris discussed rich advertising: tracking with atlas admanager, iis7 playlists to force ads before video, ad overlays with xaml
o ari paparo from doubleclick discussed doubleclick/silverlight integration vs template
o perkins miller from nbc described silverlight for 2008 Olympics (2200 live hours plus broadcast coverage)
- wpf features
o almost full wpf control library
o sockets support
o protected isolated storage
- controls shipped with OPEN source and test code; you can modify and resell
- roy ben-yoseph and eric hoffman from aol described aol’s next mail client in silverlight 2.0
Lou Carbone, UX Guru – Experience Management
- effect vs. function: manage how users feel as opposed to what you are doing for them (fedex, airlines, rotorooter, etc.)
- think about the details! users remember how they felt more than they remember what they did
Nathan Buggia, MSFT, Live Search – SEO
- 30% of all traffic to web sites is from search engines
- html tips
o <title> and <h1> tags are the 2 most heavily weighted; <h1> is actually SUPER important on live.com since it’s used to parse organization of content
o semantic html is impt (i.e. <h1>title</h1> more easily read by robots <span class=’header’>title</span>);
o make text in href tags meaningful (i.e. not ‘click here’)
o <meta>: keywords is unused, description is used for snippet
o fqdn is important (i.e. x.y.com is higher than y.com/x) since rank is aggregated at fqdn, not at folder level (although google does consider folders)
o use RIA for spice within html pages, or at the very least have distinct urls for desired search rankings
- google is only search engine of the big 3 (google/yahoo/live) that will follow javascript redirects; need to use 301 redirect if you care
- yahoo site explorer (http://siteexplorer.search.yahoo.com) : see inbound links to your page
- prefer hyphen to underscores, since search engines are likely to interpret “_” as part of word, not as word delineators
- casing matters (since 50% of since run apache). links and links distributed to other sites need to always use the same case.
- link to the root, not to a specific page (i.e. http://www.blogger.com/exchweb/bin/redir.asp?URL=http://y.com/items not http://y.com/items/default.aspx).
- http codes
o 304 – conditional get (useful for letting engines know your page hasn’t changed to save you bandwidth)
o 503 – down for maintenance
o 302 – temporary redirect (BAD! since “temporary” is ambiguous; always use 301)
- links and tools
o blogs.msdn.com/webmaster
o upcoming adcenter – msft competitor to google analytics
Silverlight 2.0, Mike Harsh, Program Manager, MSFT
- support for almost everything in WPF, plus some new controls
o MutliScaleImage – tool recursively splices a large image into 256x256 tiles, and the MutliScaleImage control automatically renders necessary tiles based on where on image the user zooms
- UserControl support!
- Local storage
o up to 1MB; if you want more, user must approve via prompt
o cross-browser “cookies on steroids”
- HTML DOM Interop
o make calls into the DOM and call javascript functions like alert()
o add items to browser’s history list
- OpenFileDialog support
