Thursday, June 12, 2008
Another Radial Panel
http://jobijoy.blogspot.com/2008/04/simple-radial-panel-for-wpf-and.html
Wednesday, June 11, 2008
DR. WPF on Pixel8
http://pixel8.infragistics.com/#Episode:9035
Beta 2 and Hacking the DOM
As intensely intuitive as it seems besides using GetProperty off of an instance of ScriptObject for properties I can also use it to grab collection items so that means something like this works:
(ScriptObject)SomeChild = (ScriptObject)foobar.getProperty("0");
basically I can pass in an indexer as if it was a property and actually get a reference to that element. Personally I have mixed feelings about this but it works. And I don't have to do script injection or some other weird ness to make it work.
Monday, June 9, 2008
Tuesday, June 3, 2008
Crossfader At TechEd
check out the pictures at:
http://www.facebook.com/album.php?aid=38501&l=1b348&id=721326429
off the web:
http://www.microsoft.com/techedonline/default.aspx
Live Tech·Ed NA Developers Keynote delivered by Bill Gates Tuesday, June 3, 2008, 8:30–10:00am EST What better way to kick off this year’s first premier technical education conference, Microsoft Tech·Ed North America 2008 Developers, than with Bill Gates, Microsoft Chairman. Join us to hear and learn about the vision of the IT industry in the years to come. High Medium Low
Monday, June 2, 2008
More on Panels
double Width = 0;
double Height = 0;
Random ThisNum = new Random();
Like the Wrap Panel we still need to run through all the panel children. Our loop should have its internal code replaced with the following:
Width = element.DesiredSize.Width;
Height = element.DesiredSize.Height;
double NewX = double.Parse(ThisNum.Next(
int.Parse(this.Width.ToString())).ToString());
double NewY = double.Parse(ThisNum.Next(
int.Parse(this.Height.ToString())).ToString());
if (MyFirstTime)
{
SetElementLocation(element, new
Rect(NewX, 1500, Width, Height), false);
}
else
{
SetElementLocation(element, new Rect(NewX, NewY, Width, Height));
}
In this case we see that we are creating new Random X,Y values so that our layout is unique every single time. We then like the other panels call the SetElementLocation in like manner. Other wise this panel is much the same as the others.
This panel allows us more interesting possibilities now we will address one more common panel that you might want to use and animate
Animating Radial Panel
So starting with the radial panel we need to do a little more math then the others. Building this panel we add 3 variables to the class itself like this listing:
protected void GetListOfPoints(int pointCount, double Width)
{
double x = Width / 2;
Radius = x;
double y = 0;
double theta = (2 * Math.PI) / pointCount;
for (int i = 0; i < pointCount; i++)
{
if (i > 0)
{
x = (Radius * (Math.Cos((i) * theta)));
y = (Radius * (Math.Sin((i) * theta)));
}
XList.Add(x + Radius);
YList.Add(y + Radius);
}
}
With out getting into great detail this method basically gives the points we need to layout our children on. Now we can alter the arrange override and we are good. In the arrange we start with variables like this:
double Width = 0;
double Height = 0;
GetListOfPoints(this.Children.Count, this.Width );
int Count = 0;
Width = element.DesiredSize.Width;
Height = element.DesiredSize.Height;
if (MyFirstTime)
{
SetElementLocation(element, new
Rect(XList[Count], 1500, Width, Height), false);
}
else
{
SetElementLocation(element, new
Rect(XList[Count], YList[Count], Width, Height));
}
Count++;The rest of the method is the same once we drop out of the loop like the wrap panel. In this case the biggest difference in the loop is having to track our position so we can get the right X/Y values for the layout.
By default like the other panels we did using the animating panel base we start be animating the children from off the screen below. All of these panels are included in the panel factory download off of HackingSilverlight.net. With that you can do all the hot panels you like.
http://www.hackingsilverlight.net/samples/PanelFactory.zip
Friday, May 30, 2008
Animating Panels and the Animating Panel Base
One of the cool things that enhances UX (User Experience) with an application is to make it pleasing to look at and use. Many times people do searches and expect recordsets. Frequently these recordsets are placed in data grids of some kind. Though Silverlight does in fact support a data grid control we might also consider using a custom panel that lays out elements visually and to make it more excited we can animate children into position depending on the current state. Writing this so it animates nicely programmatically can be a lot of work not to mention a huge pain and not very reusable. But alas you are more than welcome to do all this extra work just to discover you should have used a dispatch timer and not use Silverlight animations altogether and then waste more time figuring out how to make that work. OR you can use the animating panel base that has the dispatch timer infrastructure written tested and built in. Robi wrote this control and gave it to Mike H were they both demo’d it at MIX08 in their respective presentations. Lets re do our WrapPanel to use animating Panel Base and see how cool we can make it.
If we start with the lame wrap panel from earlier we first need to change its base class so the first line should now look like this (you can download the source from the panel factory project on HackingSilverlight.net):
public class WrapPanel : AnimatingPanelBase
Now we have the dispatch timer magic infrastructure. Next we need to add a property and method to our class like this listing that gives us a completed event for animations.
private bool MyFirstTime = true;
void WrapPanel_AnimationCompleted(object sender, RoutedEventArgs e)
{
MyFirstTime = true;
}
Next we need to actually wire this event up in the object constructor. This way the event handler gets called when the first animation is complete. The code we add to a class constructor is:
AnimationCompleted += new RoutedEventHandler(WrapPanel_AnimationCompleted);
Now once complete we are done with ‘additional’ members but we still need to change the ArrangeOverride method. First where we were calling element.arrange we need to replace that code with this block:
{
SetElementLocation(element,
new Rect(Left, 1500, Width, Height), false);
}
else
{
SetElementLocation(element, new Rect(Left, Top, Width, Height));
}
In this case if we are starting from the first animation we are animating from a location way off and below the screen. This would almost complete it but we need to another block to deal with the initial run of the arrange. The following listing goes right before the return at the end of the method:
if (MyFirstTime && this.Children.Count > 0)
{
MyFirstTime = false;
this.InvalidateMeasure();
}
On first run we then start at some weird location so we need to make 2 passes to be able to properly lay out elements and then get them to animate to the correct position. In this case on first time where there is more then 0 returned we set the value to false and invalidate measure. This has the effect of allowing us to animate from a starting position.
Now that we have written an animating wrap panel we can use what we have learned to create other kinds of panels that animate. Lets start with the Stack panel. Silverlight already has one but with the animating panel base and our wrap panel we can change a few things and be good to go with some hot animation. In the case of a vertical stacking panel the code change is in the Arrange where we only need one variable:
Double top = 0;
Then when we loop through our children all we need to do is this:
if (_firstArrange)
{
SetElementLocation(e, new Rect(0, 1500,
this.DesiredSize.Width, e.DesiredSize.Height), false);
}
else
{
SetElementLocation(e, new Rect(0, top,
this.DesiredSize.Width, e.DesiredSize.Height));
}
top += e.DesiredSize.Height;
so on first arrange we set everything to some location off screen and then set to the correct location and we set the next top to the current height so things are laid out horizontally. Otherwise the panel is the same as the wrap panel.
you can download the project I have for making this panels at:
http://www.hackingsilverlight.net/samples/PanelFactory.zip
and this is on Beta 1. I'll update this download as I go including new panels and more.
What's Better, Flash or Silverlight?
Here is a good article he did on AJAX RIA Blog on What's Better, Flash or Silverlight?
http://ajax.sys-con.com/read/578783.htm
Creating and Using Panels
public class LamePanel : Panel { }
From here we need to start by overriding two base members on the Panel class ‘Measure’ and ‘Arrange’. Measure is called so that the size of everything can be calculated before things are laid out and then Arrange is called to actually do the layout. Together the methods should look like this:
protected override Size MeasureOverride(Size availableSize) { }
protected override Size ArrangeOverride(Size FinalSize) { }
These won’t compile yet as we are not returning values so lets work out what each one does to create a Wrap Panel. Lets start with the first method that gets called namely ‘MeasureOverride’. Of the two this is the simplest one. Basically we need to go through each child in the panel and ‘Measure’ it so that we know the size for sure. In the following list we can see is loop through the children calling ‘Measure’ on each child to get it as large as possible with in the size allotted it.
for (int x = 0; x < this.Children.Count; x++)
{
this.Children[x].Measure(
new Size( double.PositiveInfinity, double.PositiveInfinity));
}
return new Size();
We need to return a size so we return a new size at the end. Now once we make sure we call Measure on all the children we can then write our ArrangeOverride method. In Arrange we want to layout all the children of our Panel and in this case we want to lay them out horizontally to the end of the line or width and then wrap the children down to the next line and so forth. The first step is to declare the variables we will use like this listing:
double Top = 0;
double Left = 0;
double Width = 0;
double Height = 0;
double NextTop = 0;
All of these values are used to track the current values used to layout children elements. Next we need to run thorugh each child and do the lay out. Start that process by adding a loop like this example:
foreach (UIElement element in this.Children) { }
From here we need to start be checking each childs desired height and width. We can do that easily like this and set the Width and height values we will need:
Width = element.DesiredSize.Width;
Height = element.DesiredSize.Height;
This gives us a point to start with as we run through each child. Next we need to see if we are still on the same line and if not we need to change a few of the of the base values we are using to move us to the next line using this listing:
if ((Left + Width) > FinalSize.Width)
{
Left = 0;
Top = NextTop;
NextTop = 0;
}
At this point we have our basic values we need to layout the current child so we need to actually do that like this:
element.Arrange(new Rect(Left, Top, Width, Height));
Using the values we calculated we create a new Rectangle and pass this into the element Arrange member. Before being entirely complete with this method we do need to do a little bit more calculation. We need to get the next Left value and the next top value like this listing:
Left = Left + Width;
NextTop = Math.Max(NextTop, Top + Height);
Now we just need to return the Size value that we passed in and our panel is complete. Run it and you can see it wrap and stack the panel children that you add in xaml.
I could show you a few more panels but the key take away is how easy it is to creating layout panels like this.
Wednesday, May 28, 2008
Animation in-depth with Silverlight 2.0 Beta
http://dotnetslackers.com/articles/silverlight/AnimationInDepthWithSilverlight20Beta1.aspx
Thursday, April 3, 2008
Actually Using Multi Scale Images in Silverlight - DeepZoom and Mouse Wheel Support with only Silverlight Code...
<MultiScaleImage x:Name="SilverdragonImage" Source="/collection/info.bin" Height="400" Width="400"/>
With just this, when we run our project the MultiScaleImage will animate the zoom of our collection up to the point of being constrained by either the height or width whichever occurs first. Using our collection we created in DeepZoom we then using a default empty solution with only the MultiScaleImage added we will get this figure on the screen.
At this point we can bind events to our MultiScaleImage. The mouse events are typical but we might want to use some of the additional events such as ImageOpenSucceeded, where we can fix up the UI as needed relevant to the image. Once everything is wired up our Xaml.
<MultiScaleImage x:Name="MyFirstMultiScaleImage" Height="400" Width="400"
MouseLeftButtonDown="MyFirstMultiScaleImage_MouseLeftButtonDown" MouseLeftButtonUp="MyFirstMultiScaleImage_MouseLeftButtonUp" MouseMove="MyFirstMultiScaleImage_MouseMove" MouseLeave="MyFirstMultiScaleImage_MouseLeave"
ImageOpenFailed="MyFirstMultiScaleImage_ImageOpenFailed"
ImageOpenSucceeded="MyFirstMultiScaleImage_ImageOpenSucceeded" />
This shows the key events on the MultiScaleImage element we might want to wire up but for zooming in and out we might want to consider using the scroll events, for the mouse wheel off of the window object to give the control rich functionality for users. This will require a bit of hacking in our object so we don't have to use JavaScript in our page. Then we will actually build our class such that it will all be Silverlight code, which by design doesn't support the mouse wheel events. This primarily has to do with the fact, that different browsers expose it differently where we can overcome this in using client side ECMA code, that will be generated in our Silverlight application. Let us start with the click related functionality. For some of the functionality we are going to do, we will need to include another 'using' reference at the top of our application source or C# user control page. The using needs to look like this:
using System.Windows.Browser;
This gives us access to the DOM bridge we will use. To build out all functionality we will use we will need to add some private members and flags for state tacking and references. The initial values we need include the following listing:
public string Source = "SilverDragon/source images/OutputSdi/collection/info.bin";
private bool _IsMouseDown = false;
private bool _IsDragging = false;
private Point _LastImagePoint = new Point(0, 0);
private bool _ErrorState = false;
The first one is used as our Source for MultiScaleImage, the next two are obvious flags for conditions in our application and a point object to show us what the last 'point' was, and the last one is if the class is in an error state and broken. This all need to be members of our user control, and you can tell that is the case by the use of the key word 'private' in front of the declaration. Next we need to make sure the constructor has what it needs to set up the application into the state we will need: The constructor should have the following code listing:
if (Source.IndexOf("http") < 0)
{
string URL = System.Windows.Browser.HtmlPage.Document.DocumentUri.AbsoluteUri;
Source = URL.Substring(0, URL.LastIndexOf('/')) + "/" + Source;
}
MyFirstMultiScaleImage.Source = new Uri(Source);
HtmlPage.RegisterScriptableObject("MySilverlightObject", this);
Here we will make sure the source has a hard URL and if not we will complete it assuming the relative path is relative to our execution location on the server via http. With this we can now look at the actual binding events we use.
void MyFirstMultiScaleImage_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!_ErrorState)
{ MyFirstMultiScaleImage.CaptureMouse();
_IsMouseDown = true; _IsDragging = false;
_LastImagePoint = MyFirstMultiScaleImage.ElementToLogicalPoint(e.GetPosition(MyFirstMultiScaleImage));
}
}
Here we check to see if the application is in its error state and if not we can perform the event. First we capture the mouse in case we are going to do any panning and we test our event flags for mouse down and dragging. Then we get the last point and save it if we are panning and/or zooming in or out. Next let's do our Mouse up with this listing:
void MyFirstMultiScaleImage_MouseLeftButtonUp(object sender, MouseButtonEventArgs e){
if(_IsMouseDown && !_ErrorState)
{
if(!_IsDragging)
{
Point MyPoint = MyFirstMultiScaleImage.ElementToLogicalPoint(e.GetPosition(MyFirstMultiScaleImage));
double ThisFactor = (Keyboard.Modifiers == ModifierKeys.Alt) ? 0.5 : 2;
MyFirstMultiScaleImage.ZoomAboutLogicalPoint(ThisFactor, MyPoint.X, MyPoint.Y);
}
MyFirstMultiScaleImage.ReleaseMouseCapture();
}
_IsMouseDown = false;
}
In this case we can see we checked that the mouse down flag is set and the error state is not true. If those are correct we also check to see if we have been 'dragging,' and if so we grab the current zoom point, calculate a factor based on the alt key, then perform a zoom operation, release the mouse capture and set the mouse down flag to false. This method then deals with either what was the mouse down event or if there was the drag operation or scroll operation. Next we will actually do our mouse move event with this listing.
void MyFirstMultiScaleImage_MouseMove(object sender, MouseEventArgs e)
{
if (_IsMouseDown && !_ErrorState)
{
_IsDragging = true;
Point p = MyFirstMultiScaleImage.ElementToLogicalPoint(e.GetPosition(MyFirstMultiScaleImage));
Point delta = new Point(p.X - _LastImagePoint.X, p.Y - _LastImagePoint.Y);
MyFirstMultiScaleImage.ViewportOrigin = new Point(MyFirstMultiScaleImage.ViewportOrigin.X - delta.X, MyFirstMultiScaleImage.ViewportOrigin.Y - delta.Y);
}
}
Here we first test for the mouse down and error state flags. If they are correct we start our drag operation by setting the value to true. Next we then grab the current point and calculate the delta point, from the last point and then set the viewport origin on our MultScaleImage. Nice and simple right? Now lets add a few methods to help deal with error conditions. First the ImageOpenFailed event that fires if something goes wrong with the source using this listing:
private void MyFirstMultiScaleImage_ImageOpenFailed(object sender, ExceptionRoutedEventArgs e){ _ErrorState = true; }
All it needs to do is set the error state flag if there is a source failure, which will basically set the application into an error state. We could add more code here to do things like switch sources, or something else if we wanted to. Next on the off chance that we are in an error state and the image open succeeds then this method will set the application back into a good state with this listing of the Image Open Succeeded event:
private void MyFirstMultiScaleImage_ImageOpenSucceeded(object sender, RoutedEventArgs e){ _ErrorState = false; }
This sets our application back into a happy state where we can perform deep zoom operations, but next we need to deal with the mouse leave event so we don't leave our MultiScaleImage in a weird state. We do this by using the mouse leave event like this listing:
private void MyFirstMultiScaleImage_MouseLeave(object sender, MouseEventArgs e)
{
_IsDragging = false;
_IsMouseDown = false;
MyFirstMultiScaleImage.ReleaseMouseCapture();
}
Here we reset both; the dragging and mouse down flags and release the mouse capture if it is captured, so we can move on. This basically completes the functionality that Silverlight 2 supports, but we can build mouse wheel support with the following section
HACK - Mouse Wheel Events in SL and with the MultiScaleImage
The 'Mouse Wheel Events' are not really supported. This is in large part due to disparity between how the different browsers support getting this event into a plug in. That however being the case also makes it worth our while to look at the fact that the mouse wheel support inside the context of the scripting engine for browsers is fairly well built out such that we can build a client side solution that feeds into our Silverlight application. However this approach feels like to much of a hack, and we can build out this same hack and make it all in our Silverlight. This still however is a hack, but it really is a lot more pleasant when the Silverlight class can wire all this on its won without us having to build out anything special in our web page (html, asp or whatever). Remember we already added the using statement so we could use the DOM bridge? Now let us start by adding a couple more properties at the top of our class with this listing.
private static string _MOUSEWHEELHANDLER_JS = "function OnMouseWheel() { ($get('Xaml1')).content.MySilverlightObject.MouseWheel(window.event.clientX, window.event.clientY, window.event.wheelDelta); } ";
private static string _MOUSEWHEELEVENT_JS = "window.onmousewheel = document.onmousewheel = OnMouseWheel; if(window.addEventListener) { window.addEventListener('DOMMouseScroll', OnMouseWheel, false); }";
Gasp, I know many of you will note that these two values contain ECMA script. Since Silverlight supports what we need and scripting does, but we don't want to be writing everything in the client, this approach allows all to be built out in our Silverlight code and it makes the class more easily reused. Next we need to add a little private method that does our black magic here with this listing:
private void InsertECMAScript(string JavaScript)
{
HtmlElement Script = HtmlPage.Document.CreateElement("script");
Script.SetAttribute("type", "text/javascript");
Script.SetProperty("text", JavaScript);
HtmlPage.Document.DocumentElement.AppendChild(script);
}
I know this really might give some people heart burn, but it really makes our DeepZoom class more portable. In this case anything we pass into this element will get tacked onto the end of our web page HTML DOM and since it is script up front it gets executed. We use this function in our object constructor like this:
InsertECMAScript(_MOUSEWHEELHANDLER_JS);
InsertECMAScript(_MOUSEWHEELEVENT_JS);
Again, this is really giving some people heart burn, but I think it is cool and much less hassle. One thing to note though is we still didn't add our Mouse Wheel event in our code. Todo this we can add this event handler as in this listing:
[ScriptableMember]
public void MouseWheel(double x, double y, int delta)
{
if (!_ErrorState && !_IsDragging)
{
double ZoomMultiple = (delta < 0) ? 1 / 1.33 : 1.33;
Point p = MyFirstMultiScaleImage.ElementToLogicalPoint(new Point(x, y));
MyFirstMultiScaleImage.ZoomAboutLogicalPoint(ZoomMultiple, p.X, p.Y);
}
}
When we compile it and run it, we now get the click zoom in and out behavior. We can use the alt key when we zoom out on click, and the mouse wheel event is tied into our MultiScaleZoom and it is a reusable class.
Tuesday, April 1, 2008
WCF and Silverligth 2 - Beta 1 and automated builds
We are doing this pretty big silverlight application that is pretty much a shrink wrapped quality solution. Part of the implementation of this is a complete automated build system for QA and part of that was the fact that the production environment is a huge hands off big no touching sort thing.
In this particular application we have a number of WCF services that we are talking to, that are local in the web solution along with the silverlight application. When you run this in Visual Studio it works well. When we deployed it we noticed we had to deploy the solution, re do the references to the deployed WCF service and then deploy again. a bit of a pain but in and automated scenerio using msbuild and the like and you have no idea what the url will be, this is extremely problematic.
We also found a nice service client config file with the url settings for the server etc in the compiled xap but when changed this didn't seem to do anything. Much to our sadness we found out that we might look for this in the next version and the file though created was ignored. The solution that hopefully will go away in Beta 2 is to over-right all our constructors and pass in a value we configure in the web.config... Basically something like this:
ServiceClient MyClient = new ServiceClient( new BasicHttpBinding(), new EndpointAddress( new Uri(SomeConfigValueAsString)));
basically overright which constructor is used and pass in the value that would normally be compiled directly into the dll. A hack I know but it works until we get that beta 2 and we can still use our WCF service.
New Look and Feel
Wednesday, March 26, 2008
Silverlight Spy
"Silverlight Spy provides detailed XAML inspection of any Silverlight application. Use the built-in browser to navigate to a web page. Silverlight Spy will automatically pick up any Silverlight application embedded in the page and display..."
http://www.silverlightspy.com/silverlightspy/
Tuesday, March 25, 2008
Foundation Blend 2 - Building Applications
http://windowspresentationfoundation.com/index.html
Thursday, March 20, 2008
Full Screen Silverlight 2
private void TopElement_OnFullScreenChanged(object sender, EventArgs e)
{
SizeUI();
}
right now this calls a method that mucks up my UI depending on control size so when it is in full screen it just uses all the realestate. In the class constructor I bind this method to the host like this:
Application.Current.Host.Content.FullScreenChanged += new EventHandler(TopElement_OnFullScreenChanged);
I then create a bit of xaml that points at this method:
private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if( SLHost.Content.IsFullScreen )
{
SLHost.Content.IsFullScreen = false;
}
else
{
SLHost.Content.IsFullScreen = true;
}
}
which that actually is dependent on this being a private member:
private SilverlightHost SLHost = new SilverlightHost();
with that nice a simple bit of code I have full screen mode :)
Thursday, March 13, 2008
Using Expression DeepZoom
The key tool for building out MultiScaleImages we will use in Silverlight is Expression DeepZoom. DeepZoom is a Simple tool like Encoder for example that allows you to import images and produce the multi-layer image collections and tile structure used by DeepZoom (MultiScaleImages) in Silverlight to produce the coolness we are looking for.
DeepZoom (talk about double entendre) then creates a DeepZoom Project lets you import all the high resolution images you want to use. Then you can compose your collection of images and then it will export and build all of your multilayer image collections, tiles and other bits as configured. With that then we can embed these into Silverlight work with multilayered images.
We learn how to use the application by opening Expression DeepZoom and getting familiar with the user interface.
Currently the interface is pretty simple. We have our splash screen that pops up. That shows existing projects or lets you open new ones etc. We also can see the tabs which are basically the 3 steps to building a Multi layered image collection and getting it ready for Silverlight. From the top file menu we can open the project dialog.
Once we give our project a name and select the type (Seadragon Project) we then can start adding images to our multi-layered image collection. On the import tab in the UI we can see we have a view area and then a scrolllist of our images. At first this will be blank and at the bottom we have a button called 'Add Image.' If you click the 'Add Image' button you can use the standard windows API file dialog to find a cool high resolution image that you want to multi layer. If you add several you will see them on the design surface.
Now that we have added some images we can start arranging them in our collection. Start by click on the tab '2. Compose' at the top of the interface. Then you can drag the images from the right on to our design surface.
Let us take a look at the interface. At the top of the UI we can see a tool bar at the top and there are 5 tools which by default will have the first one selected. The first three icons represent the cursor state on the compose view of the application. The default is for dragging our icons onto the surface. Selecting second icon you can drag the design surface.
You can see how the map in the lower left of the composition surface has moved showing what the pan functionality looks like and this map shows you where on the surface that you are. The third icon on the compose tool bar is for zooming. This allows you to drill into any given location on the composition surface.
Looking closely we can see the drop down menus for the last two icons on the composition tool bar. You can see the second icon from the right is alignment items (i.e. left, right, top, bottom etc). if you select one then all your images get laid out in the collection accordingly. The menu for the last button that distributes images horizontally or vertically.
Once we get all our images on our composition surface we are ready to export our collection. There are a number of settings but for DeepZoom in Silverlight we are good with just having a location and exporting. We do this by clicking the export button.
DeepZoom then builds our Silver Dragon (SDI) file and builds out all over tiled images. If we are just going to use it for Silverlight and are using one image we can just grab its corresponding structure including the .bin, xml and the tile jpg's. Now we are ready to actually do Seadragon, er I mean SilverDragon, er I mean DeepZoom(MultiScaleImages).
Tuesday, March 11, 2008
ItemsControl, ListBox and DataGrid's, oh my
using System.ComponentModel;
using System.Collections.ObjectModel;
This gives us access to ObservableCollection and INotifyPropertyChanged so we can build out our data. We will create a method that create our collection but first we need a base classes for our data. To start with we need to create the Data class first like this:
public class Data : INotifyPropertyChanged
{
private object _value;
public event PropertyChangedEventHandler PropertyChanged;
public Data(object val) { _value = val; }
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
This inherits from INotifPropertyChanged and we create our NotifyPropertyChanged method along with a constructor so we can pass our value in when we create instances of the class. Since we have a private value we need to expose it publicly so we can then bind our templates to it as used in the items control. So then we add the following code to the above class:
public object Value
{
get { return _value; }
set
{
if (value != _value)
{
_value = value;
NotifyPropertyChanged("Value");
}
}
}
This 'Value' public property is what we will actually bind to. Then we can create our DataCollection that is an ObservableCollection of our Data Class like this:
public class DataCollection : ObservableCollection<Data> { }
Now we have an ObservableCollection that we can bind to. Next we need to create a method that creates or gets the data. Here we will hard code the data into this simple example:
private object GetData()
{
DataCollection MyCollection = new DataCollection();
MyCollection.Add(new Data("One"));
MyCollection.Add(new Data("Two"));
return MyCollection;
}
Let us now look at our Xaml, now that we have our collection and something to create it or fill it with data we need an items control and template to do something with. First we build our template for each item that will be listed in the items control.
<UserControl.Resources> <DataTemplate x:Name="MyDataTemplate" > <TextBlock Text="{Binding Value}" ></TextBlock> </DataTemplate> </UserControl.Resources>
This will bind to the public value of 'Value' as created in our data class earlier. Next we need to actually create the items control. An Items control can be as simple as this:
<ItemsControl x:Name="itemsControl" ItemsSource="{Binding}" ItemTemplate="{StaticResource MyDataTemplate}" >
</ItemsControl>
In this case we set our ItemSource to be Binding and then we use a static resource namely our template. Back to our code we now need to point the items control to the method that creates our collection using code like this:
this.itemsControl.DataContext = GetData();
This can be in our page's or user controls constructor and sets the data context to be the collection of objects as an observable collection that we are building and returning. When we run this we will get a list of items as created in the GetData method much like a stack panel would lay out its children where in this case the default is vertically.
Not terribly impressive but under the covers very cool. What is most cool about it is the key functionality this provides. This can be used for everything from dynamically build menus and other dynamic lists of different kinds and more. To move beyond that we can also use the new control Listbox.
Using the Listbox control
The Listbox control is much like the ItemsControl but we are adding functionality including scrolling and selection rollover functionality. We can style it and using databinding and the like just the same. So using the code from the last section we can change out our Xaml and be ready. To start with add additional elements in the collection in our source this way we have 20 or so elements so we can see the scroll functionality. Then we can remove the ItemsControl and add a Listbox like this example:
<ListBox x:Name="itemsControl" Grid.Row="1"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource MyDataTemplate}" />
So by adding all the extra items to our collection we can really see the big difference between ItemsControl and Listbox control.
With the Listbox control it is easier to implement functionality like select or drop down functionality that users see in other technologies. Now to take this even one step further lets look at DataGrid.
Using the Datagrid Control
The Datagrid is used much like the list and items controls but the datagrid is targeted towards result set functionality. In this case we need to make sure we specify the name space in the xaml. At the top if you use Visual Studio and start to create a name space it will give you a list and you want to select the 'System.Windows.Control.Data'. You can give your 'namespace' any name you want but since it's a Datagrid we are talking about I'm partial to 'Data' as a matter of course. So lets assume the same code base as the Listbox we did earlier, then rip out our 'ListBox' and then add this bit of Xaml
<Data:DataGrid x:Name="itemsControl" AutoGenerateColumns="True" ItemsSource="{Binding}" />
When we run this we get a nice data grid like the ListBox but we get column names. We can of course re-template this to look pretty much any way we like but default will look pretty much like any data grid control you might see in winforms.
As you can see its pretty much the same as the ListControl and ItemsControl but Columns are added and we have set it to auto-generate the columns.
Monday, March 10, 2008
Getting the Beta for Silverlight 2
http://www.microsoft.com/downloads/details.aspx?FamilyId=E0BAE58E-9C0B-4090-A1DB-F134D9F095FD&displaylang=en
Wednesday, March 5, 2008
Download links from MIX 08 - Silverlight
http://blogs.msdn.com/tims/archive/2008/03/05/download-links-for-mix08-announcements.aspx
Silverlight MIX Announcement(s)
* support for Silverlight on MAC, Windows, Linux and Mobile devices
* improved preformance especially dynamic adaptive streaming and bit rate throttling, including IIS features to support to provide bit rate throttling.
* Silverlight Add templates in visual studio
* Burning Silverlight right into video using ecoder 2
* Multi-language including Silverlight in Python
* Rich WPF UI framework (layout, databinding, skinning and styling system)
* Robust networking (post, SOAP, WCF, sockets etc.)
* LINQ and Databinding
* Local Store and cache between browser sessions
* Controls include: data grids, list box, sliders, radios, buttons calender and date picker controls, checkboxs etc.
* all controls are being shipped with open source license.
* test framework for silveright.
* control templating stucture including the abilty to change animations, and restructure the visual tree
* full intellisense and design experience in VS
* DeepZoom.... formerly Silverdragon formerly SeaDragon taking smut to the next level allowing arbitrary zooming to any resolution smoothly.
* Silverlight Sharepoint bits to make it easier to put silverlight web parts in sharepoint
SeaDragon (DeepZoom) really is cool with the 2billion pixel size images... :)
IE 8.0 first impressions
beta 1 is available at:
http://www.microsoft.com/ie/ie8/
MIX 08 - Silverlight - Wish you were here...
Monday, March 3, 2008
No Soap for you! - The No Silverlight Experience
On my HackingSilverlight.net (the domain not the feed site), I did not have time to worry about the non-silverlight user and in fact chose to be a bit over-the-top towards them. Personally I find it funny, but I know many people think its just plain mean... but really what is someone doing at a Silverlight site if they don't have silverlight? So to save me from work, here is my on-load function...
function OnLoad()
{
Resize();
try
{
if( !Silverlight.isInstalled("1.0") )
{
var parentElement = document.getElementById("BlogContent");
parentElement.innerHTML = "";
}
}
catch(Exception)
{
alert('NO SOUP FOR YOU!...');
}
}
Note the 'innerHTML' which would normally contain the entire HTML block that makes up all the visible content on the page except the install badge... again I found this extremely funny, but alas, with the book coming, I will probably make it play nice.