Just a quick update. Previously I posted a workaround for the disappearing row problem with the Silverlight datagrid. Well, if you update to the latest Silverlight datagrid (http://silverlight.net/forums/t/59990.aspx) you will no longer need this workaround. Thank you Microsoft!!!!
Friday, December 19, 2008
How to get the Mouse Position in a Silverlight Application
Silverlight provides several Mouse events that can be used to determine the position of the mouse. These include
- MouseMove
- MouseEnter
- MouseLeave
- MouseLeftButtonDown
- MouseLeftButtonUp
Depending on the event that is fired, you have access to either an object of type MouseEventArgs or MouseButtonEventArgs. This object inside your event handler contains the information you need to determine the current mouse position. In the event handler, call the GetPosition method to retrieve the current mouse position. If you pass in an object, you will get the mouse position relative to that object. If you pass in Null, you will get the mouse position relative to the Silverlight plugin on the page.
Here is a quick example of how to do this.
LayoutRoot.MouseMove += new MouseEventHandler(LayoutRoot_MouseMove);
void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
{
Point position = e.GetPosition(null);
}
Netflix on Silverlight!
YEAH!!!! Netflix has started a rollout of their new movie player. The new player is now built on Silverlight. If you want to get the new player before it is rolled out to everyone, go to http://www.netflix.com/silverlightoptin This will take you to the following screen showing the system requirements.
When you are done you'll get a confirmation that the new player has been enabled... that's it!
Here is what the player looks like.... When you scrub the video you get a nice timeline showing you where you are scrubbing to on the movie... Very cool!
You still have the fullscreen support.
So checkout the new Silverlight movie player on Netflix. I'm very pleased with it.
Friday, December 12, 2008
Why Not User Your Own Technology?
Seriously?!?!?!? Why does the Surface website (www.microsoft.com/surface) use Adobe Flash? Isn't Silverlight just as good (If not better)? I'm using the technology and telling others that it is a better technology (younger... and therefore not as robust in some areas, but none the less better), yet Microsoft decides to go with Flash in sites like this one. Really? Practice what you preach Microsoft!
Tuesday, December 9, 2008
Data Grid Disappearing Line Trick/Bug
I've been working with the Silverlight Datagrid for a while now. Nifty control. But it has caused me a great deal of frustration! One bug I have run across (on the 2.0 bits) is the occasional disappearing of rows. After a lot of debugging, yelling at my computer, and many, many Google searches, I was able to figure it out.
It seems this problem occurs whenever a control inside the datagrid has focus and the ItemsSource is modified. I have seen this when I add, update or delete items in the ItemsSource. Ahhh! Very annoying bug! The easiest work around.... make sure no controls inside the datagrid have focus prior to messing with the ItemsSource. In my application, I have several checkboxes and buttons in every row of the datagrid. In the event handlers for the click events or checked/unchecked events, I simply set focus to the entire datagrid (myGrid.Focus()), before I run any of the code that modifies that row. That seemed to take care of the situation.
From other posts I have read out there, a different way to do this is to remove the datagrid from the visual tree and replace it every time you modify the ItemsSource... but that seems a bit drastic. Hopefully this post will become obsolete very soon. (Hint hint. Microsoft... Please fix this soon!)
Monday, December 8, 2008
Java FX?
So, Java has their own version of Silverlight/Flash now called JavaFx. I spent some time looking at it today and have mixed emotions. On the one hand, they are advertising that this works on "All the Screens of Your Life." You should be able to write JavaFx applications that run on your pc, your mobile device, or your tv if you would like. Two points Java. I'm still not sold on the technology though. I took a look at some of the sample applications. They did look cool (Flash/Silverlight like), but the install experience was not as smooth. Check it out for yourself and see what you think. One downer... The way in which UI's are created. They are going with a declarative model much like silverlight and Adobe Flex. So far so good, but the language is.... not very elegant in my opinion. It makes sense to declare it in an xml language, not this...
Ok, not a huge deal. I could probably get used to it. The second, and I think biggest thing that Silverlight has going for it over this and any other technology out there is its templating capabilities. It's one thing to skin a control, its a totally different thing to be able to create a lookless control.
Friday, December 5, 2008
How to Make a Silverlight Image Slide Show
There's a lot of websites out there with some very cool image slideshows. I figured I would take the time to write a short tutorial on how to make a basic image slideshow with fade in/out transitions between images.
First things first... The xaml...
<UserControl x:Class="ImageSlideshow.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Resources>
<Storyboard x:Name="FadeOutAnimation">
<DoubleAnimation Duration="00:00:00.50" From="1" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="theImage" />
</Storyboard>
<Storyboard x:Name="FadeInAnimation">
<DoubleAnimation Duration="00:00:00.50" From="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="theImage" />
</Storyboard>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="Black">
<Image x:Name="theImage" Stretch="Uniform"/>
</Grid>
</UserControl>
This is all the xaml it takes to make a very basic slide show. The application itself consists of a Grid and an image inside the grid. I have set the Stretch property to Uniform so the image will take up the entire screen or as much of it as the aspect ratio of the image will allow. The other important piece here is the Resources section. The FadeInAnimation and FadeOutAnimation modify the image's Opacity property from 0 to 1 or 1 to 0 respectively.
On to the code behind.
Now, create a timer which will be used to transition between images. To initialize the timer, create a new event handler for the tick. Set the value of 'INTERVAL' to the number of seconds you wish to display each image.
timer.Interval = new TimeSpan(0, 0, 0, INTERVAL, 0);
timer.Tick += new EventHandler(timer_Tick);
timer.Start();
Now create an ObservableCollection of strings to hold the names of the images. Also create an integer to indicate which image is currently displayed.
private ObservableCollection<string> _images;
private int _currentIndex = 0;
To initialize the _images collection I created a separate method (good programming practice!)
private void InitializeImages()
{
_images = new ObservableCollection<string>()
{
"Autumn Leaves.jpg",
"Creek.jpg",
"Desert Landscape.jpg",
"Dock.jpg",
"Forest Flowers.jpg",
"Forest.jpg"
};
SetImageSource(_images[_currentIndex]);
}
These strings correspond to the names of the images I placed in a new directory I created in the solution named Images. Next, create a method named SetSource (which is the method I call at the end of the InitializeImages method). I separated this into a separate method because the code inside the method will be run over and over.
private void SetImageSource(string imageName)
{
string name = "Images/" + imageName;
BitmapImage bmi = new BitmapImage(new Uri(name, UriKind.Relative));
theImage.Source = bmi;
}
All this method does is set the source of the image object to the image that has the name that is passed in as the input parameter. You cannot just set the images.Source property to the string passed in, you need to set it to a BitmapImage object which we can create based on the string passed in.
We're getting close! Now implement the timer's tick event handler
void timer_Tick(object sender, EventArgs e)
{
_currentIndex++;
if (_currentIndex == _images.Count)
{
_currentIndex = 0;
}
FadeOutAnimation.Begin();
}
Here, you increment the _currentIndex. If the index reaches the end of the list, simply set it back to zero. Once the index has been updated, fade out the image. Do this by calling the Begin method of the FadeOutAnimation defined in the xaml. The last thing that needs to be done is to define an even handler (in the class constructor) for the Completed event of the FadeOutAnimation. When the animation is finished, set the image source to the next image and fade the image back in by calling the FadeInAnimation's Begin method.
void FadeOutAnimation_Completed(object sender, EventArgs e)
{
SetImageSource(_images[_currentIndex]);
FadeInAnimation.Begin();
}
That's it! Not a lot of code! This could easily be modified to add some play, stop, pause, next, previous controls. It would also not take a lot of work to add different animations to change the transitions between the images.
Good luck and have fun with this one!
Monday, December 1, 2008
Help! I Can't Access Anything Inside My Silverlight Viewbox!
The much anticipated Viewbox control is finally here. I have been waiting patiently for this control for a while now. It behaves the same way the Viewbox in WPF does. It takes its content and allows it to stretch and contract to fill the desired space... Very handy!
One small issue... a bug. As of the latest release (11/29/08), you cannot directly access any object you place inside the Viewbox. For example, you can have a viewbox that contains a Button named myButton.
<controls:Viewbox x:Name="vBox">
<Button x:Name="myButton"/>
</controls:Viewbox>
In your code behind, if you try to access myButton, it will always return null. This is a known issue that the Silverlight team working on the toolkit has promised to fix. For now, here is the workaround. Simply access myButton by looking at the Child property of the Viewbox.
((Button)vBox.Child).Text = "myButton Text";
Tuesday, November 4, 2008
Help! My ComboBox Does Not Render Properly
When I ran the application, however, I realized that all was not well. The ComboBox control in Silverlight 2.0 has a very annoying bug. Now, the folks in the Silverlight team are aware of this bug and are working on a solution, so for the time being we are stuck with having to come up with a workaround. So here is the bug...
The Bug:
If you have a dynamically populated ComboBox, the height of the actual drop down is calculated only once. The very first time the drop down is displayed, it is measured and displayed properly. If the contents of that ComboBox change, however, the drop down is not remeasured. You are stuck with the same size drop down. This becomes a real problem with the first time the dropdown is shown there is only one item in the list and the second time there are 50! You are stuck with a very short dropdown and a scroll bar.
The Workaround:
Whenever you have to change the collection of items in a ComboBox, you need to rip that original ComboBox out of it's container, create a new one with all the same properties, add the appropriate items to the new ComboBox, and insert it back in the appropriate container.
I typically write a CloneComboBox method. Here is a sample:
This is the method I call imediately before I say cboMovies.ItemsSource = "myNewItemsSource".
It first removes the ComboBox form it's parent container (LayoutRoot in this case). Then I make a new ComboBox and I copy all of it's original properties. The easiest way to do this is copy the xaml which creates the original ComboBox, and make sure all of it's properties are being copied over to the new one. Here is my orinial xaml for that ComboBox:
<ComboBox x:Name="cboMovies" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Row="1" Margin="74,9,0,0" Width="206.333"> <ComboBox.ItemTemplate> ....</ComboBox.ItemTemplate> </ComboBox>
After this method is finished executing, I can give the ComboBox a new ItemsSource and the new drop down is rendered in the appropriate size.
Give it a shot and good luck. Hopefully this post will become obselete soon (I'm hoping for a fix from Microsoft soon!)
Wednesday, July 16, 2008
How Do You Change the Cursor of a WPF App?
this.Cursor = Cursors.None;
There are several built in cursors such as a pen, cross, scroll, etc.
You can also use a custom cursor as follows:
this.Cursor = new Cursor("CustomCursorImage.jpg");
Because Cursor is a dependency property, it can also be used in XAML. Here are two examples on how to use custom cursors via XAML:
<Button Content="Wait" Cursor="Wait"/>
<Button Content="CustomCursorImage.jpg"/>
What timer to use for WPF and Silverlight Applications
//------------------------------------------
//DispatcherTimer code snippet
//------------------------------------------
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(100);
timer.Tick += timerOnTick;
timer.Start();
void timerOnTick(object sender, EventArgs args)
{
//do something
}
Very Cool Silverlight Example
With Silverlight, I can keep developing in C#! (I also think XAML is more powerful than MXML)
Check out the link above to see an example of what can be done with the current Silverlight bits.
WPF and Silverlight Best Practice: Event Handlers
When developing WPF and Silverlight applications, developers and designers can create a clean line of separation between the look and feel of the application and its functionality. This is possible because of XAML. Although it is possible to create WPF or Silverlight applications entirely of procedural code (VB or C#), it is highly unlikely you would see such an application. Typically, designers work on the XAML files while developers work on the code behind files. In the XAML files, designers can specify what the UI looks like, while developers deal with the behavior. It is possible, however, for designers to embed some basic functionality within the XAML itself. One example is in defining event handlers. In the following code snippet I am defining a button.
<Button x:Name="btnSave" Content="Save" Width="90" Height="25" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="118,0,0,11.33899974823" Click="MyClickHandler"/>
This button has various properties that define its look and feel including Content, Width, Height, etc. I have also specified an event handler for the button's Click event. The body of this even handler is found in the code behind file of my Silverlight or WPF control. This code is perfectly legitimate. In fact, it can clean up your code behind files significantly. If you have 50 buttons, each of which need to point to this event handler, it removes a lot of these statements.
btnSave.Click += new RoutedEventHandler(MyClickHandler);
This was my reasoning when I first started writing WPF apps. I thought I would clean up my .cs files as much as possible. If I could write it in XAML, I would. There is a small problem with this approach. Lets say the XAML snipped above was found in a xaml file that was then handed off to a designer. The designer opens it up in a design tool like Expression Blend and decides the button looks terrible with all those attributes. Instead, he/she wants the button to look a lot different, so he/she decides to completely wipe out that button and start from scratch. As long as there is a button named btnSave, the application should build. So, he/she ends up with this
<Button x:Name="btnSave" Content="Click to Save" Style="{StaticResource SaveButtonStyle}" Margin="0,4.5,2,0" VerticalAlignment="Top" d:LayoutOverrides="Height"/>
This button now has a completely different look and feel. It points to a style resource which may drastically change the appearance of the button. At this point the designer builds the application and there are no errors, so he/she is happy. There have been no breaking changes and the button looks great…. WRONG! Although the application builds and it looks great, there has been a major change in the behavior of the button. With the following code, there is no handler for the click event. The designer accidentally wiped out the old XAML not realizing that a little bit of functionality had been defined there. This is the problem with defining event handlers inside XAML code.
As a best practice… Always assign your event handlers in your procedural code. Here is what I do… Inside the constructor of all my WPF and Silverlight controls, I add a method called AddEventHandlers(). Inside this method, I take care of adding the event handler to all my controls defined in my XAML. The code looks something like this:
public MyControl()
{
InitializeComponent();
AddEventHandlers();
}
private void AddEventHandlers()
{
btnSave.Click += new RoutedEventHandler(MySaveClickHandler);
btnExit.Click += new RoutedEventHandler(MyExitClickHandler);
btnOk.Click += new RoutedEventHandler(MyOkClickHandler);
}