ChildWindow in Silverlight 3

SL 3 introduced the ChildWindow to allow easy creation of modal 'pop-up' windows inside our main window. Once you have added a new ChildWindow to your project you can customise its appearance & content. The example below creates a ChildWindow to be used to display simple messages to users. In a full implementation you'd probably want to customise the appearance to match the colour scheme, etc of you main app - also ensure you have scroll bars appear if there is a large amount of txt, etc.

 

 Full XAML for our message box:

<controls:ChildWindow x:Class="blog_misc_temp.CustomMessageBox"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
           Width="400" Height="300"
           Title="CustomMessageBox"
                      HasCloseButton="False">
    <Grid x:Name="LayoutRoot" Margin="2">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <TextBlock Name="txtMessage" TextWrapping="Wrap" />       
        <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" Grid.Row="1" />
    </Grid>
</controls:ChildWindow>

 

Code behind:

namespace blog_misc_temp
{
    public partial class CustomMessageBox : ChildWindow
    {
        // Simple property to allow setting of the TextBloxk text.
        // An alternative would be to bind the Text propery to this and
        // implement INotifyPropertyChanged to raise a PropertyChanged
        // event in the setter.
        public string Message
        {
            get
            {
                return txtMessage.Text;
            }
            set
            {
                txtMessage.Text = value;
            }
        }

        public CustomMessageBox()
        {
            InitializeComponent();
        }

        private void OKButton_Click(object sender, RoutedEventArgs e)
        {
            // Set the result to ok/accepted (i.e. not cancelled)
            // This will cause the ChildWindow to close.
            this.DialogResult = true;
        }
    }
}

 

To show a pop-up message from within our main form:

            CustomMessageBox msg = new CustomMessageBox();

            msg.Title = "This is a message box"; // Title is a built-in property of ChildWindow
            msg.Message = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.";

            // Show our 'modal' ChildWindow message box as we do not have a cancel
            // button we discard the returned DialogResult
            msg.Show();
 

SHARE:

Silverlight & WPF - Binding to a specific item in a collection

If you have a collection of items (for example a list of strings) that is assigned to the DataContext of a given XAML element (or parent element) you can use standard array index notation to get at a specific item in the list, just use Path=[n] where n is the item index.

For example:

<TextBlock Name="exampleBindingText" Text="{Binding Path=[3]}" />

With a DataContext set using the code:

            List<string> months = new List<string>()
            {
                "Jan", // 1st element in collection at index 0
                "Feb", // 2nd element in collection at index 1
                "Mar", // 3rd element in collection at index 2
                "Apr"  // 4th element in collection at index 3
            };

            exampleBindingText.DataContext = months;

Would result in the Text of the TextBlock outputting "Apr" as Path=[3] will get the 4th element in the collection.

SHARE:

Silverlight Open and Save Dialog Boxes

If you want your Silverlight app to be able to load and save data to the users file system in a location of their choice (such as My Documents, Desktop, etc.) you can use the SaveFileDialog and OpenFileDialog. This is different from reading and writing to Isolated Storage as it requires the user to interact with a dialog box, choose filename, etc. The user can also cancel out of the dialog box, which returns a value of false from the ShowDialog() method.

Below is a simple example of saving a hard-coded string "Test string to save." to a file as chosen by the user. In a live application you would want to think more carefully about possible problems arising from loading and saving, e.g. what if user loads a corrupt file, or a binary file where a text file was expected, etc. Also with the loading of files you should evaluate the security risks of allowing arbitrary data to be loaded into your application.

 

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = "Text Files (*.txt)|*.txt";
            dlg.DefaultExt = "*.txt";

            // if the user doesn't cancel           
            if (dlg.ShowDialog() == true)
            {
                try
                {
                    // create a StreamWriter over the base stream returned by SaveFileDialog's OpenFile() method
                    using (StreamWriter writer = new StreamWriter(dlg.OpenFile()))
                    {
                        writer.Write("Test string to save.");
                        writer.Close();
                    }
                }
                catch (Exception ex) // catch all, ideally you should catch specific exceptions in most-specific to general
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }



        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "Text Files (*.txt)|*.txt";

            // if the user doesn't cancel
            if (dlg.ShowDialog() == true)
            {
                try
                {
                    string loadedText;
                    // create a StreamReader from OpenFileDialog's OpenText() method
                    using (StreamReader reader = dlg.File.OpenText())
                    {
                        loadedText = reader.ReadToEnd();
                        reader.Close();
                    }
                    MessageBox.Show(loadedText);
                }
                catch (Exception ex) // catch all, ideally you should catch specific exceptions in most-specific to general
                {
                    MessageBox.Show(ex.ToString());
                }
            }
        }
 

SHARE:

Binary Serialisation In Silverlight

One problem with the Silverlight DataContractSerializer is that it does not maintain reference links to objects. For example: if you had a customer object "Mr Green" and 2 order objects "Cooker" & "Fire" that both held references to the (single) "Mr Green", when serialised and then deserialised using DataContractSerializer the "Cooker" would point to a different "Mr Green" than the "Fire", i.e. they are not reference equal. If this is an undesirable scenario we can choose to serialise in a binary, reference-equal way so that when we deserialise there will still only be 'one' "Mr Green".

One option is to make use of a 3rd party library such as CSLA Light. You can use CSLA Light just to enable binary serialization or you could embrace the whole CSLA architecture. Either way you will probably need to change the inheritance structure of your objects and replace any properties with CSLA properties. You can find out more about CSLA Light at http://www.lhotka.net/weblog/UsingCSLALightPart1.aspx

Example of simple CSLA

 For our Customer objects to be CSLA binary serializable we would modify the class to look something like:

    [Serializable]
    public class Customer : BusinessBase<Customer>
    {

        private static PropertyInfo<string> CustomerNameProperty = RegisterProperty<string>(new PropertyInfo<string>("CustomerName", "CustomerName", string.Empty));

        public string
CustomerName
        {
            get
            {
                return GetProperty(CustomerNameProperty);   
            }
            set
            {
                
             SetProperty(CustomerNameProperty, value);   
            }
        }

We would follow a similar pattern for out order class. We could then use CSLA's MobileFormatter to serialise/deserialise (the example below defines generic methods but non-generic/typed methods could also be used):

        public static T Load<T>(Stream stream)
        {
            T m = default(T);

            Csla.Serialization.Mobile.MobileFormatter f = new Csla.Serialization.Mobile.MobileFormatter();
            m = (T) f.Deserialize(stream);

            return m;
        }


        public static void Save<T>(T obj, Stream stream)
        {
            Csla.Serialization.Mobile.MobileFormatter m = new Csla.Serialization.Mobile.MobileFormatter();
            m.Serialize(stream, obj);
        }

 

There are alternatives to CSLA Light for getting binary serialisation such as http://slserializelzo.codeplex.com/ although I've not investigated them as yet. (Hopefully a future version of Silverlight will allow the DataContractSerializer to output XML (albeit 'non standard') with referential links.

SHARE:

Detecting when a Silverlight app enters full screen mode

Obviously you know when a users clicks your full screen button but a the user can press escape to exit full screen mode at any time, an alternative is to respond to the FullScreenChanged event.

For example:

     public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            App.Current.Host.Content.FullScreenChanged += new EventHandler(FullScreenChanged);
        }

        void FullScreenChanged(object sender, EventArgs e)
        {
            if (App.Current.Host.Content.IsFullScreen)
                txtFullScreen.Text = "Running in full screen.";
            else
                txtFullScreen.Text = "Not running in full screen.";
        }


        private void btnFullScreen_Click(object sender, RoutedEventArgs e)
        {
            App.Current.Host.Content.IsFullScreen = true;
        }
    }

The above assumes a button to enable the user to select full screen and a textblock:

 

<UserControl x:Class="blog_misc_temp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
  <Grid x:Name="LayoutRoot">
        <StackPanel>
            <TextBlock Name="txtFullScreen" Text="Not running in full screen."/>
            <Button Click="btnFullScreen_Click" Content="Enter Full Screen"></Button>
        </StackPanel>
    </Grid>
</UserControl>

 

SHARE:

Free Xaml drawing tool

I stumbled upon a nice (free) open source drawing application (a la Adobe Illustrator) which allows saving in SVG but also XAML! So if you don't want to/cannot afford to use Blend this could be a nice alternative, you can download from http://www.inkscape.org - should also mention you can get a 60-day evaluation copy of Blend 3 from Microsoft.

SHARE:

Thunder (beta)

I've been working on a Silverlight 3 drum machine/sequencer called Thunder, the first (beta) version is now available at:

http://www.dontcodetired.com/live/thunder/

 

It's a fully working version but the code base requires some re-factoring. Playback smoothness varies depending on the machine specs and how many instruments are playing at the same time.

Future improvements include the addition of more than 2 drum kits, the ability to use your own drum samples and attempting to improve the performance (although this seems to be limited by having to use a MediaElement to play a stream rather than an immediate .Play() method - hopefully in Silverlight 4 a lower latency sound playback mechanism will be introduced).

SHARE:

Quickly Take Down an ASP.NET Web Site

If you need to temporarily take down an ASP.NET (2.0+) web site you can simply add a file called app_offline.htm to the root of the site. The content of the app_offline.htm could contain a message such as "Site currently undergoing maintenance" or similar.

When you add the file to the root, the server unloads the app domain, when the file is remove (or renamed for example) the next request that comes in will restart the app domain, etc...

SHARE:

Countdown To Christmas 2009 Silverlight 3 app

For a bit of Silverlight 3 fun:

 



Use\install at: http://www.dontcodetired.com/live/christmascountdownbeta/

There are some things which need improving such as resizing when run out of browser, abilty to sort/hide/filter data etc.

SHARE: