Wednesday, December 17, 2008
Xaml Guidelines, Part 1
http://channel9.msdn.com/shows/Continuum/XAML-Guidelines-Part-1/Default.aspx?wa=wsignin1.0
Tuesday, December 16, 2008
Scrubbing Timeline MediaElement
anyway I got the code out and walked through it since actually I'm checking all the samples currenty for the final review so I had todo it. In any case I was suprised to find that it works, Yes granted the in the article and post a year ago didn't expressly bind the events but seeing as the audience is developers and this is a blog called 'hacking' silverlight so I'm assuming that most of the readers are trained developers and in fact many are probably smarter then me so I would think they would be able to figure out what it means to add the events. The only other issue I found with the code was in fact when I wrote the article the play and pause methods were abstracted in the original which again was a simple thing but anyway I found the remark mean. and here is the same code recompiled on RTM SL 2.0 and it seems to work:
http://www.hackingsilverlight.net/samples/ScrubbingTimeline.zip
Silverlight Trigonometry
a cool post on stuff that makes my head hurt in Silverlight no less :)
http://channel9.msdn.com/continuum/tutorials/Trigonometry/
check it out.
Wednesday, December 10, 2008
Silverlight 2 Performance Best Practices
Here is some more 'content' summary info from my Architectural Best Practices presentation at DevTeach.
As to performance best practices… use the following as a good starting place:
· Don’t stretch things including Images, videos, or paths. Stretching things is going to cause more processing. Create assets at the size that they will be used and life will be much easier.
· Don’t use ECMA Script or the Anti-Pattern Silverlight 1.0.
· Don’t use windowless mode.
· Remove event handlers and set them to null before removing the element from the visual tree.
· Set MediaElement sources to null before removing them from the tree.
· Don’t use opacity if you just need to make things disappear, instead use the visibility property.
· Do use ‘IsHitTest’ and set it to false when doing drag and drop do hit testing only happens on the elements that are drag targets. This also allows you to keep visual elements from interfering with role over related events such as Mouse Enter and Mouse Exit events.
· Don’t have 1000 thousand elements in the same Visual Tree…
· If something is going to take a while tell the user or show the user that we are waiting.
· Don’t use ‘findName’ if you don’t have too as this causes a walk through the visual tree.
At least following these rules for Architecture and Performance your application won’t fall on its face.
SCRUM in 10minutes
http://www.youtube.com/watch?v=Q5k7a9YEoUI&fmt=22
Tuesday, December 9, 2008
Architectural Best Practices for Silverlight 2.0
Underlying Silverlight architecture helps us abstracted UI from logic and we need to take into account this toolability story that Silverlight enables as this can provide more ROI and shorter time to market for application development if designers and developers can work at the same time without the whole ‘through it over the fence’ approach. From a design pattern standpoint I recommend pMVP or Proxy Model View Presenter as the ‘better’ design patterns I know of require more upfront development as Silverlight doesn’t support the underlying infrastructure for these patterns. pMVP keeps it simple and the simplest solution is usually the best.
For Architectural best practices lets bullet out our best practices:
· Design Pattern pMVP (Proxy Model View Presenter) which is a clean, simple design pattern to implement that gives better abstraction.
· Make use of designer developer workflow enabled by Xaml UI separation.
· Don’t impose artificial Xaml coding conventions on designers or yourself as this slows productivity. Just let Blend go with it.
· Agree on Naming conventions, coding conventions (maybe standard WPF conventions might be a good place to start) and the like as you like but be consistent so that it is easier to support and pick up again later. This improves readability and helps the whole designer developer interaction.
· For the most part doing event bindings in Xaml, the more in Xaml the better however use common sense. If the designers are using Photoshop and converting the Xaml maybe just do the bindings in code so that you can have the designer just do a new conversion to generate new Xaml if they might make changes.
· Build at lest the Presenter logic in a separate Silverlight library.
· Build generic custom controls in a library.
· Consider putting the presenter code in a separate library or at least its own folder.
· Build Views with Blendablity in mind. Break up complex user controls that build the View into its component parts so that the elements can be more easily worked with in Blend.
· Use Gobal Styles and Templates and other resources in the App.xaml only when they are truly global in the application. Don’t clutter up the global resources with elements that are not really global.
· Use best practices with other connected technologies such as WCF or SQL or IIS/ASP.NET. Best practices in Silverlight wont’ do you much good if everything else is a mess.
· IF you build controls that rely on the DOM bridge encapsulate the ECMA related resources either in a Xap or right into the control so the ‘user’ as the simplest method to use the control.
· Consider the install experience to encourage users to install Silverlight so they can use your Silverlight application. Just using the default badge is boring.
· Consider Search Engine Optimization if it is a public site, such as control element names and the HTML on the Silverlight page etc. event the names of Xaml elements as a lot of this will be in the Xap that will at some point be parsed by search engine spiders.
That gives us a nice list of best architectural best practices. Following these simple rules lets you approach Silverlight architecture and application design with ease. Now we didn’t go into a lot of the application ‘Design’ aspects of ‘Designing’ applications such as UML etc but the focus here is strictly on Silverlight.
Monday, December 8, 2008
DevTeach Conference Content - Best Practices, Hacking Silverlight, Controls
enough air???
Anyway ignoring that little episode it was great. Here are the links to session material and content (mosting slide decks and sample code and some talk track notes I used to memorize content)
http://www.hackingsilverlight.net/samples/SLV421.SLArchitecture.zip
http://www.hackingsilverlight.net/samples/SLV467.SilverlightControls.zip
http://www.hackingsilverlight.net/samples/SLV469.HackingSilverlight.zip
Netflix Layoff Blamed on Silverlight
http://blog.netflix.com/2008/12/changes-in-customer-service.html
sad for those guys but cool for Silverlight... hmm.. will the dow go up or down?
Wednesday, November 26, 2008
Silverlight Threading and Events
then I make the text block have a keydown event so I can capture returns and send them along their way... if it is a return I just call the other event handler...
and one does a call to system which blows up. so the event in the key up looks like this:
private void SearchBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
SearchBtn_Click(sender, null);
}
}
but in the search btn we are trying todo an alert as I'm in a hurry and don't feel like making a nice silverlight message thingy so I just want todo this:
private void SearchBtn_Click(object sender, RoutedEventArgs e)
{
string SearchValue = SearchBox.Text.ToString();
if (SearchValue != "" && SearchValue.Length > 2)
{
DataBindMe.DataContext = CrossfaderUsers.RetrieveSearchUserList(SearchValue);
}
else
{
System.Windows.Browser.HtmlPage.Window.Alert(App.SEARCHTEXTINVALID);
}
SearchMessageBox.Visibility = Visibility.Collapsed;
}
this blows up from the keydown event apperently as it is not on the UI thread??? WT...? I mean really the 'click' event is on the UI thread but keydown is not? the error message is something to effect of namespace 'System' is not accessable due to the context? As far as I can tell by 30 minutes of googling is that this event some how is magically not on the UI thread so when I add this:
Dispatcher.BeginInvoke(delegate()
{
System.Windows.Browser.HtmlPage.Window.Alert(App.SEARCHTEXTINVALID);
});
it magically works???
Monday, November 24, 2008
Silverlight 2 Event bindings
checkout my post on dotnetslackers and let me know:
http://dotnetslackers.com/Community/forums/silverlight-architectural-best-pratices/t/2609.aspx
Friday, November 21, 2008
Silverlight 2 Architecture and CodeCamp
Anyway one guy emailed me about getting that content available. of course this stuff will be in my book and I'm doing the presentations at DevTeach etc. but up front I'd like to point out a few things that might help get people going in the right direction.
So from a design pattern stand point the entire discussion frequently has more in comon with Hell Fire and brime stone religous discussions then real logical 'Useful' disuccusions that are actually helpful. It really is all kind of esoteric mumbo jumbo at some level.
In an effort not to get sucked into a religous war I'm going to go WAYYYY out of a limb and say the best design pattern is in fact MVP (model view presentor) as discribed in the following posts by others:
Phil Haack
http://haacked.com/archive/2006/08/09/ASP.NETSupervisingControllerModelViewPresenterFromSchematicToUnitTestsToCode.aspx
Tim Ross
http://timross.wordpress.com/2008/03/16/implementing-the-mvp-pattern-in-silverlight/
There are several ways todo it and I'm not even saying that this one is correct just it happens to be my choice for no other reason then it helps get back to some nice old CS101 ideas like 'gasp' OBJECT ORIENTED or Encapsulation sorts of things.
my code behinds are simple may data model objects are clean and my Xaml is Zen with the universe.
lets just say for the sake of moving foward that I'm going with the MVP design pattern as my prescribed method. Alot of what you do on top of that is more or less common sense. Follow stand coding conventions as they apply, following Preformance best practices where they apply, and most of all consistency.
do it, all do it and do it the same...
I really don't care which way but really I should never be able to tell who did and I should seem lots of oh yea that is logical and is the best way.
really thats is the bottom line. More to come as I work out a detailed talk track for the SLV421 presentation in case I want to give it to say my friend John todo the same presentation at another conference... ;)
Thursday, November 20, 2008
Tired of Customers dissing your work?
http://dotnetpays.computerinnovationsny.com/dotnetpays/Home.aspx
very very cool. My kind of hack. not really 'Silverlight' strickly speacking but a good thing to be aware of.
Seattle Developer / Designer Interactive Group
Next month we will focus on mobile devices and we are hoping to get some cool people in this space to talk about their work. Be cool too and show up. :)
Monday, November 17, 2008
CodeMash and DevTeach
DevTeach is giving a bunch of cool stuff to attendee's and I'm planning on having lots of swag to give out too. Now also at Codemash I get todo the same thing. Codemash is in Ohio at this cool resort and I'm doing a presentation on Silverlight 2 Arctectural Best Practices which will probably include some great 'Anti-Patterns' with the ubber Silverlight app Crossfader. If you can come check it out. :)
http://www.codemash.org/
and of
http://www.devteach.com/
both awesome conferences. :)
Friday, November 7, 2008
Crossfader Goes Live
As to Silverlight I went through the application and counted 54 distinct screens, dialogs and views currently in the system. Some of these are amagalmations but remember the whole things is one xap. I'm impressed it runs. :) 10 years ago a web application like this even if it wasn't all together was more likely then not going to lock up your computer. Crossfader certainly is next gen stuff and about the experience. Remember this is still just a beta but facebook will have some catching up todo :)
http://www.crossfader.com/
Wednesday, November 5, 2008
Centering Content in Xaml
<usercontrol class="www.hackingsilverlight.net.Page" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" x="http://schemas.microsoft.com/winfx/2006/xaml" uc="clr-namespace:www.hackingsilverlight.net" >
<grid name="LayoutRoot" >
<grid name="ContentArea" verticalalignment="Center" horizontalalignment="Center" >
<canvas width="660" height="300" >
etc...
nice and simple and clean and you don't even have to have a clue what size your UI is. :)
Local Events about Silverlight
SEAFLEX MEETING Thu Nov 13 6:30pm – Thu Nov 13 8pm http://www.seaflexug.org/ 701 N 34th St, Seattle WA 98103 Created By Seattle Flex User Group (SeaFlex) Description Ryan Stewart, RIA Evangelist will present to us about the new FXG format that will be available with Flex 4. The Intro to Flex portion will cover the Food Drive Resource Locator project developed during the Flex Code Jam at the 2008 Flex360 conference. This is the 2nd anniversary of the Seattle Flex User Group, so we'll be having cake and prizes! Meeting starts at 6:30 pm (for real now) with the Intro to Flex portion, followed by introductions and the main presentation. If you'd like to network or just chit chat, show up a little early ~6:00. _____________________________ PDXUX (Portland User eXperience group) http://pdxux.net/ Next Meeting: "Silverlight 2 Launch Party"
WHEN: Tuesday 11/11/20086:30 p.m. Pizza Dinner (by Microsoft)7:00 p.m. Presentation1515 NW 19th AvePortland, OR 97209
For this month's PDXUX meeting we are celebrating the recent release of Silverlight 2 with a launch party hosted by the folks at North.
Our featured presenter is Tim Heuer, who is a Senior Program Manager for Microsoft Silverlight. He helps build the worldwide Silverlight community and is very passionate about the platform and technology in general. Having over 13 years of experience with Microsoft web technologies, Tim is excited about the opportunities that Silverlight brings for developers and designers and wants to ensure that everyone has the best information and tools available to them for success. Tim can be found online at http://timheuer.com/blog.
Along with Tim's presentation, we'll have several demo stations featuring Silverlight locals Erik Mork, Kelly White, and Jason Mauer. Learn more about Silverlight 2 features and how you can utilize them in your own web applications.
We'll also be talking about BizSpark, Microsoft's brand new program for supporting startups, and how you can get involved.
Tuesday, November 4, 2008
Seattle Code Camp
https://seattle.codecamp.us/sessions.aspx#HACKING+SILVERLIGHT+2+
Come check it out and help me get ready for DevTeach.
Friday, October 31, 2008
Silverlight Tour
http://silverlight-tour.com/
Sparkling Client
his site is:
http://www.sparklingclient.com/
Thursday, October 30, 2008
Dr. WPF Sighted at PDC
http://wpfwonderland.wordpress.com/2008/10/29/dinner-with-dr-wpf/
Tuesday, October 28, 2008
Search Engine Optimization for Silverlight
http://silverlight.net/learn/whitepapers/seo.aspx
Silverlight 2 URL Redirection
System.Windows.Browser.HtmlPage.Window.Navigate(new Uri("foobar.com"), "_blank");
well this is all good and works but in some cases in IE when redirecting to a url that is not a page but a binary of some kind there seems to be an issue with opening the file and the browser window closes. ???
since I don't have time to work out if this is a bug or not or some 'feature'... Here is my cheater method that seems to work fine...
so I added this to the App:
public static void InsertECMAScript(string JavaScript)
{
HtmlElement Script = HtmlPage.Document.CreateElement("script");
Script.SetAttribute("type", "text/javascript");
Script.SetProperty("text", JavaScript);
HtmlPage.Document.DocumentElement.AppendChild(Script);
}
and then from my user control I added this:
App.InsertECMAScript("ProcessWindowOpen(\"" + URL + "\");");
and poof it goes away....??? not sure what is up with that but works.
Wednesday, October 22, 2008
Breaking Changes Between Silverlight 1 and Silverlight 2
http://blogs.msdn.com/webnext/archive/2008/10/21/ensuring-that-your-javascript-silverlight-applications-work-with-silverlight-2.aspx
if your board there is also this article on msdn:
http://msdn.microsoft.com/en-us/library/cc645049(VS.95).aspx
and also this one:
http://blogs.msdn.com/silverlight_sdk/pages/silverlight-bugs-and-workarounds.aspx
Thursday, October 16, 2008
RPS in Silverlight
That being said at times this has been a requirement. As far as using RPS it is not that difficult once you get past configuration and fairly straight forward to use in Silverlight. In my case I'm currentlying working on a project that shall rename unnamed where it was a requirement to use RPS.
RPS has this thing called a ticket that we pass around to make sure a user is logged in. We had this WCF services we needed to secure as well that the Silverlight application is talking to so we needed to get the ticket up on the client Silverlight app so it can be passed on the WCF calls todo authenication with live id. So once it was working ASP side all we needed todo was seriealize the ticket by using its token or RPS Token value and passing that as a parameter into our Silverlight application.
Then on the root of the app we save this RPS Token value to be used in authentication on the WCF calls.
Great. right?
Wrong...
this all worked fine and about a week in we the ticket type in test changed. one would think ok waht did we do wrong. apparent now we had to authenticate using type 2 in stead of type 3... WT...??? Some time later it changed to 4 and now we have to use 3 again. oh but we have changed anything about around the RPS Tickets? so what is up?
granted this was also a developement system and not hitting the 'live' live id system but still and another guy I know was working on a different project and they hit the same problem. As a joke I finally added this block of code:
StringBuilder WTFErrorList = new StringBuilder();
RPSTicket MyTicket = null;
for (int x = 1; x < 11; x++)
{
try
{
MyTicket= MyAuth.Authenticate(m_RPS_AppName, rpsTicket, (uint)x, propBag); // !!! WTF???
break;
}
catch (Exception E)
{
string WTFErrorMessage = x.ToString() + " WTF Error[RPSSupport::ValidateTicket] " + E.Message;
WTFErrorList.AppendLine(WTFErrorMessage);
WTFErrorList.AppendLine("m_RPS_AppName: " + m_RPS_AppName);
WTFErrorList.AppendLine("rpsTicket: " + rpsTicket);
WTFErrorList.AppendLine("");
Debug.WriteLine(WTFErrorMessage);
}
}
MyTicket.Validate( propBag );
The down side is this will never fly in production with all the code reviews but in got me over the humpe of figuring out what ticket type to use...
Wednesday, October 15, 2008
No Silverlight for iPhone
"Microsoft said it was probably not going to be putting its Flash competitor Silverlight on Apple's iPhone 3G, but said it was keeping a watchful eye on Google's Android platform, and said Silverlight might get onto T-Mobile's G1. "
http://www.fiercewireless.com/story/microsoft-no-silverlight-iphone-maybe-g1/2008-10-14
Monday, October 13, 2008
Silverlight 2 Release
http://www.microsoft.com/presspass/press/2008/oct08/10-13Silverlight2PR.mspx
Looking forward to seeing this final drop as opposed to RC0. :)
Eclipse for Silverlight or is it the other way around?
http://www.eclipse4sl.org/
Friday, October 3, 2008
Seattle Developer / Designer Interactive Group
http://www.seattled2ig.org/
Wednesday, October 1, 2008
Silverlight 3D...
http://www.innoveware.com/
speacking of 3d silverlight there are also a couple of related projects on codeplex. Faisal Khan a friend sent me a mini me version that does a puesdo 3d layout based on x, y and z. I'm playin with a wrapper class that will allow more complicated 3d effects but his View3D panel works well and we'll drop it into the hackingsilverlight library for our own little mini me 3d engine for Silverlight that not only for the book but we will use it for the project george that I'll talk about at some later point after the book is finished, completely.
Tuesday, September 30, 2008
Kuler Colerful Expression Blend Add-in
'Colorful Expression is an add-in for Expression Blend and Expression Design that brings you the Adobe Kuler community directly into your toolbox. It adds a new palette to your design environment, making it easy to leverage the community to find the perfect color theme for your application or design. The add-in also available as a standalone application, making it useful for web developers working in Visual Studio or Expression Web to select colors for your CSS style sheets.' ~www.codeplex.com/colorful (30 SEP 08)
http://jonas.follesoe.no/AnnouncingColorfulExpressionStudioAddIn.aspx
and of course the codeplex project is:
http://www.codeplex.com/colorful
very cool stuff
Thursday, September 18, 2008
Silverlight 2 RTM Controls Leaked...
DockPanel
WrapPanel
ViewBox
Label
HeaderedContentControl
Expander
TreeView
NumericUpDown
AutoComplete
Accordion
and of course the leak:
http://visualstudiomagazine.com/columns/article.aspx?editorialsid=2789
and a discusion on topic
http://silverlight.net/forums/p/27906/93454.aspx
Sunday, September 14, 2008
Free Book???
http://dotnetslackers.com/projects/Data-Structures-And-Algorithms/
Tuesday, September 9, 2008
IBC Conference - Silverlight
http://www.microsoft.com/presspass/features/2008/sep08/09-09silverlight.mspx
Monday, September 8, 2008
Silverlight - Rossetta Stone?
However names aside I think this site is worth watching...:
http://www.projectrosetta.com/
Friday, September 5, 2008
VS Power Commands
http://code.msdn.microsoft.com/PowerCommands
very cool stuff.
Silverlight 2 Custom Cursors
http://blog.dobaginski.com/josh/?p=38
Wednesday, September 3, 2008
Hug a developer...
http://develop-one.net/blog/2008/08/27/HugADeveloper.aspx
Blenables Labs
http://blendables.com/labs/default.aspx
Desklighter Live
http://blendables.com/labs/Desklighter/Default.aspx
Thursday, August 21, 2008
Whats Next for DeepZoom
http://www.informationweek.com/news/personal_tech/cameras/showArticle.jhtml?articleID=210102274
mixed into some deepzoom. maybe in Silverlight 2.5? or 3.0?
Tuesday, August 19, 2008
IntelliSense for Expression Blend
http://blogs.telerik.com/StefanDobrev/Posts/08-08-04/IntelliSense_for_Expression_Blend.aspx
alittle bit of Kaxaml and mix in some Addin and ICodeEditor goes a long way :)
Crossfader Demo at TechEd
http://msstudios.vo.llnwd.net/o21/presspass/zune/Silverlight_2_Zune.wmv
Monday, August 18, 2008
Dynamics Duo talk about CRM and Silverlight
http://channel9.msdn.com/posts/benriga/The-Dynamics-Duo-talk-about-CRM-and-Silverlight/
Friday, August 15, 2008
Dev Teach 2008 Toronto Canada
Building Silverlight Controls
David J Kelley - SLV467
Designed primarily for Developers. This technical presentation walks through a number of senerios for building Silverlight Controls including user controls and custom panels. The usage of properties, dependency properties, events, reusability, and encapsulated control architecture is reviewed in detail. In the presentation we will build a custom chart control based on a user control and built custom panels and review dispatch timer and multi threading in the context of controls.
Hacking Silverlight 2 - For Designers and Developers
David J Kelley - SLV469
Designed for Designers and Developers. This engaging presentation gets the audience involved in bridging the gap between design teams and software development using Silverlight and the Silverlight toolablity story. The presentation is full of audience participation and skits that get audience members up out of their seats and excited about Silverlight. The basics of team work using Microsoft tools for design and development are used and the audience is shown some of the coolest Silverlight hacks that can make Silverlight applications really shine. With the “Coming out of the closet” skit the audience is shown sexy UI using Silverlight, learning about speed of development and why we care about Sexy engaging Web 2.0 experiences.
SilverLight 2.0 Achitectural Best Practices
David J Kelley - SLV421
Designed Developers and Architects or people wanting to understand Silverlight archtecture. This presentation startings with a detailed technical review of Silverlight control, application architecture and design patterns. Design patterns as applied to Silverlight application development and general best practices are reviewed in detail. The presentation includes learning from the trenchs of building Silverlight apps on a large scale including horror stories and ‘Anti-Patterns’ or things ‘not to do’ are reviewed.
check out http://www.devteach.com/Session.aspx for more information
Tuesday, August 12, 2008
IntelliSense for Expression Blend
http://blogs.telerik.com/StefanDobrev/Posts/08-08-04/IntelliSense_for_Expression_Blend.aspx
Dynamic Images in Silverlight
http://michaelsync.net/2008/06/29/silverlight-2-beta1-best-of-silverlightcream
and
http://blogs.msdn.com/jstegman/archive/2008/06/08/sample-updates-for-beta-2.aspx
and
http://blogs.msdn.com/jstegman/archive/2008/04/21/dynamic-image-generation-in-silverlight.aspx
Monday, August 11, 2008
Thursday, August 7, 2008
Robby's New Blog Face
http://nerdplusart.com/
Friday, August 1, 2008
Spherical Microsoft Surface
http://blog.seattlepi.nwsource.com/microsoft/archives/144629.asp
Thursday, July 31, 2008
Kaxaml Now Supports Silverlight2 Beta2
http://blog.nerdplusart.com/archives/kaxaml-now-supports-silverlight2-beta2
Friday, July 25, 2008
BG's Keynote on Pixel8 Interview at TechEd 08
http://pixel8.infragistics.com/shows/teched08.aspx#Episode:9581
Check it out and other cool shows he has done.
Wednesday, July 23, 2008
Hacking Expression Blend
Adding Features and Plug-ins to Blend
To start with you will need to make sure Expression Blend is installed and we get a copy of the ‘Microsoft.Expression.Framework.dll’ which will be installed in the Microsoft Expression directory under program files or other location depending on how you installed. If you can’t find this directory you can do a global search on ‘Microsoft.Expression.Framework.dll’ and you will find it.
Now that you have the DLL we can now open Visual Studio and start a new project. For really hacking into Expression Blend so that our application or whatever it is you want to do in Blend we should use the WPF Custom Control Library project type found under the language of your choice (C# or VB.NET) and then under windows. Once the project is created drag a copy of the dll into the solution explorer and into the project. This DLL contains all the base class types used to wiring things into the Expression Blend infrastructure. Granted much of the stuff in Blend is sealed or closed there is enough available to us to be able to hack. You might ask since at the time of writing this the info was not publicly available or even privately available and since I’m not a Microsoftee how did I find this out…? Wel I want to thank a friend named Karim Hernandez with a little too much time on his hands and a nifty tool called ‘Reflector’ for finding this stuff out.
.NET Reflection and Probing the guts of .NET Binaries
A bit of topic but a critical skill to really pushing the limits to .NET programming in general is the albity to look into DLL’s and see what is there even if you are not provided documentation about what is in a binary. With .NET we have a built in technology for reading binary .NET content called reflection and through tools like ‘Reflector’ you can probe into the guts of things even if your not supposed to and using reflection or just referencing the DLL’s you can create instances of class’s you might not supposed to have. Case in point is sinsce Blend is a WPF application its DLL’s and binaries can be ‘probed’ and explored as it were and since this infrastructure is or will be probably available to control vendors at some point for extending blend we can go ahead and use it. However that being the case they could change and since we all know about .NET Reflection we can work it out.
Back to hacking Blend…
Now we need to create a reference to Blends Framework DLL so we can start implementing things we might want. Right click on our controls project and select ‘Add Reference’. You will need to select the Browse tab from the Reference dialog and then find the DLL we added to our project. Select it and click ‘OK’ which will not allow us to include references in the specific class’s. Start by renaming our ‘CustomControl1’ class to OurFirstBlendHack more for our own entertainment value. Visual Studio will ask about renaming all the references and you want to select yes so that the name change is clean and won’t break anything. Then at the top of the source fille add this line at the top:
using Microsoft.Expression.Framework.AddIn;
using Microsoft.Expression.Framework;
Now we have the ablity to start using the DLL content in our OWN classes how ever we want. We will start by making our Class a Blend Adding and in heriting from IaddIn which is the base class for Blends Framwork if you want to extend the functionality or add your own stuff into blend or whatever cool Silverlight tools you can think of. A real live use might be to integrate group Xaml/Silverlight editing tools like KaXaml or adding your own code formating or even a custom Silverlight control library. But first we need to make our first class definition look like this:
public class OurFirstBlendHack : IAddIn
And then add the detail meta data for Blend right before this first line like this:
[AddInDescription("OurFirstBlendHack", AddInCategory.Tool)]
With that we need to add a several methods to start mucking around with to deal with the StartUp event, Intialization, Dispose and the ShuttingDown event in Blend. The three events actually look like this:
public void Initialize(IApplicationService applicationService) { }
public void StartupComplete() { }
public void ShuttingDown() { }
public void Dispose() { }
Before we compile we also need also to remove the constructor or at least remove the line of code for setting the defaultKeySetter which will normally be added ‘for’ you as Visual Studio assumed this was inheriting from Control by default. Once the constructor is dealt with we then compile. Do this to make sure you have not made any errors but currently the class is valid but is not going todo anything. Our next step is to add some code and run it from Blend to see if we can make our ‘Addin’ work. Add the following line to our method StartupComplete.
MessageBox.Show("Blend is Hacked!");
Again this is not going todo anything until we run it from blend but if it is done then we should get a default windows dialog poping up with the label from our code. Todo this we need to make sure our code is compiled and then we need to open a command prompt test our code. Copy the DLL into the Blend directory and use the following at the command prompt:
Blend.exe /addin:HackingBlend.dll
This will start blend and blend will run the class we created and you will get the popup dialog ‘Blend is Hacked!’. If you really want to-do something as part of blend though, we might want to start with a menu. A custom menu in Blend is straight forward enough, but first let us build out what the menu will do. We can start this by making a command class. First create a new class in our project called HackCmd. Add the following includes at the top:
using Microsoft.Expression.Framework.AddIn;
using Microsoft.Expression.Framework;
using Microsoft.Expression.Framework.Commands;
Then we need to make the class inherit from the base command object like this:
internal class HackCmd : Command
To make the object actually do something we still need to add internal code to the class as well as the required API needs implemented to support usage. The main thing we want to implement then is the method Execute and our constructor. In this case this should look like the following Listing:
private IApplicationService _ApplicationService;
public HackCmd(IApplicationService ApplicationService)
{
_ ApplicationService = ApplicationService;
}
public override void Execute() { }
Now that we can Hack Blend lets close out the chapter summarizing what we learned. Next for testing lets add a line to Execute to actually do something like this:
MessageBox.Show("Blend is Hacked even more!");
This gives us something to call from our menu and from here we can open additional dialogs or WPF windows etc to perform whatever task we want to do. Remember then if you want a window for example to open you put it into the execute method of your command objects. To really make the menu work we still need one other class and that is a command target that receives menu events and routes them to the command class. Add a new class to your project called HackCmdTarget and add the additional using statements to top that you added to the HackCmd class. Then make sure we have our inheritance correct by making the class declaration look like:
internal class HackCmdTarget : CommandTarget
Now we need to fill out the guts of the class. In the case of the Target we are only adding a constructor and the references to the HackCmd class that we add to Blends command collection. The internal code then for our HackCmdTarget should be like the following listing:
internal static string HackCmdCommandName = "HackCmd_Command";
public HackCmdTarget(IApplicationService ApplicationService)
{
base.AddCommand(HackCmdTarget.HackCmdCommandName, new HackCmd(ApplicationService));
}
Now we can go back to the first class we created called OurFirstBlendHack and build out our Blend menu structure. Add the following line to add our command to blend when our class is loaded on Initialize to our class’s Initialize method:
ApplicationService.CommandService.AddTarget(new HackCmdTarget(ApplicationService));
Now Blend can see the target command and we can add a menu to call it. To create an instance of Blends menu we need to add a using statement to the top like this:
using Microsoft.Expression.Framework.UserInterface;
Then we can create an instance of the menu bar in blend and can add elements to the menu. Add the following line of code to the Initialization menu to create an instance of the menu like this:
ICommandBarMenu menu = ApplicationService.CommandBarService.CommandBars[0].Items.AddMenu("HackBlend", "HackBlend");
Now to add elements to our new menu we can call methods on our menu instance. In this case we can use ‘AddButton’ and ‘AddSeparator’ to build a little menu. Use these lines of code to add our elements and route our commands:
menu.Items.AddButton(HackCmdTarget.HackCmdCommandName, "alert us");
menu.Items.AddSeparator();
menu.Items.AddButton(HackCmdTarget.HackCmdCommandName, "another alert");
Now we can compile and then copy our DLL to the blend folder and run from the console the following line:
Blend.exe /addin:HackingBlend.dll
This will run Blend and run our little class in the context of Blend including our menu. If you try this you can see we have ‘hacked’ Blend or at least used its plug in framework to allow us to ‘extend’ Blend to do new and better stuff with our Silverlight Xaml. Now let us summarize what we have learned.
Wednesday, July 9, 2008
Silverlight - Animating Wrap Panel
"Panels, as we know, are pretty much the basis of building any Silverlight application. They help arrange the other Silverlight controls in specific manner like Stack allowing you to stack controls either horizontally or vertically, Grid allowing you to position controls in rows an columns and Canvas giving you a free flow behavior. This blog however isn't however a primer on panels and you can..."
http://infosysblogs.com/microsoft/2008/07/silverlight_animating_wrap_pan.html
Friday, June 27, 2008
Making Silverlight Run As an EXE
So I've seen a few things like this: http://www.codeplex.com/SilverlightDesktop and thought I would see how easy it was... turns out to be 'super' simple...
Silverlight is designed to work inside a web browser. That being the case it is also not a ‘desktop’ or exe application. This ‘hack’ then allows us to take Silverlight applications and make them into exe’s. It works great however there are a few issues to keep in mind. One issue is that as shown here the exe won’t run on a 64 bit machine unless you get the 32bit IE engine running in the context of the control we will show. Also Silverlight still needs to be installed on the box and the one small detail about this only working on a windows machine but otherwise works well. The other major down sides is that a lot of things dependent on script injection or cross domain issues will in fact be ‘issues’ but you can work around that.
To start we just need to create a new project in Visual Studio. From the new project window we want to select a Windows Forms Application under windows (under the language of your choice). Once we do this we should get a blank Form 1. You can change the setting or set other values as you like. To get our Silverlight application running we need to add a folder that contains an HTML page and XAP that works from any local path. For example in our first project we could copy the output from our debug folder and call it good.
Once you drag a Silverlight application folder into our project we need to select on each item such as the HTML page and XAP files. In the properties pain of Visual Studio for each item there is a setting called ‘Copy to Output Directory.’ We need to change this setting for everything our Silverlight application depends on to ‘Copy always’.
Now that all the resources are present we need to start adding to the ‘Form’. Basically what we are going to do is add a web browser control that hosts the IE rendering engine that will load our Silverlight application in a web page running locally in an exe. In the tool box on the left side of visual studio under the tap ‘Common Controls’ drag the control onto the form on the design surface. Then resize the form and set any other properties you might want to set (ie: add an icon, or change title etc).
Right click on the form and select ‘View Code’ and add the following code:
string MyPath = Application.StartupPath + "\\[folder of Silverlight App]\\[Some Page].html";
webBrowser1.Navigate(MyPath);
The first line gets the path to our page that has the code to load the XAP for our application. Now then we pass this value into a call to the Navigate method on the web browser control. If you rename it the control name will be different but the sample above is the default. Compile and run the application and you will get your Silverlight application running in a win 32 window. If you wanted to be industrious you get build this in a VB 6 or C++ app doing the same kind of thing and even embed all the resources into the exe or build a custom installer etc and have this running on just about any windows platform with Silverlight even without .NET.
Thursday, June 26, 2008
Control Library on Codeplex
http://www.codeplex.com/HackingSilverlight
Wednesday, June 18, 2008
google command line...
http://goosh.org/
Tuesday, June 17, 2008
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.