My Master's Thesis Problems and solutions encountered…

10May/100

Linking from User Control to User Control

As I showed in a recent post, it is possible to link from a Silverlight User Control to a Silverlight page using the Silverlight Navigation Framework. But at times you will need to link from a User Control to another User Control, and there you won't be able to use it.

In my case, I encoutered this situation because my application has three different user types, who each have their own Navigation Framework. They have this because they each have vastly different tasks to perform, and thus there's need of different menus to access different pages. But there is one task that they must all carry out: Before any user can access the application, they must log in. Of course, the login page is a User Control, so I needed to link the Login page to one of the Navigation Framework user pages, which are also User Controls.

Basically, you will need too add a small code snippet outside the Grid on the page you wish to link from (in my case, the login-page), and an event EventHandler to a button. In the EventHandler you specify which grids are visible, and which are not.

Below, I have posted a very simplified version of my MainPage.xaml, that I use for the login. Notice that there are two grids at the top, and that we have named the inner grid Login, and its Visibility is set to Visible:


<UserControl x:Class="QM_v1.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" mc:Ignorable="d"
xmlns:local="clr-namespace:QM_v1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="437" d:DesignWidth="947">
<!--Background layout-->
<Grid x:Name="LayoutRoot">

   <Grid x:Name="Login" Background="White" Width="Auto" Height="auto" ShowGridLines="False" Visibility="Visible">

  <!-- Focus on the 'Enter' button -->

           <TextBox x:Name="Mail">
           <PasswordBox x:Name="Pass" >

            <StackPanel Grid.Row="2" Grid.Column="2" Orientation="Horizontal">
                <Button Content="Cancel" Click="Cancel_button"/>
                <Button Content="Enter" Click="Enter_button"/>


            </StackPanel>

   </Grid>

<!-- Important bit: -->
<local:Customer x:Name="Customer" Visibility="Collapsed"/>
<local:Supplier x:Name="Supplier" Visibility="Collapsed"/>
<local:ETS x:Name="ETS" Visibility="Collapsed"/>
</Grid>
</UserControl>

Notice that the local:Customer bit is outside the second grid. In here you specify the name of the .xaml pages that you wish to link to, depending on which user logs in. Here I have just specified that I have three .xaml pages (Customer, supplier and ETS), and that each of these pages at this point in time are collapsed, ie. not visible/active.

When the user presses the Enter_Button you want your EventHandler to check who the user is, and depending on the outcome they should be directed to either customer.xaml, supplier.xaml or ETS.xaml. For simplicity, I have hardcoded the user name and password, but they should of course be gathered from a database.


private void Enter_button(object sender, RoutedEventArgs e)
{

   if (Mail.Text != "" && Pass.Password != "")//there is some content.
   {

     if (Mail.Text == "customer@gmail.com" && Pass.Password == "customer")
     {
        Customer.Visibility = System.Windows.Visibility.Visible; //customer = Name of .xaml page
         Login.Visibility = System.Windows.Visibility.Collapsed; //Login = inner grid at MainPage.xaml
     }
     else if (Mail.Text == "supplier@gmail.com" && Pass.Password == "supplier")
     {
      Supplier.Visibility = System.Windows.Visibility.Visible;
      Login.Visibility = System.Windows.Visibility.Collapsed;
     }
     else if (Mail.Text == "ets@gmail.com" && Pass.Password == "ets")
     {
     ETS.Visibility = System.Windows.Visibility.Visible;
     Login.Visibility = System.Windows.Visibility.Collapsed;
     }
     else
     {
     MessageBox.Show("Please enter correct e-mail and password.");
     }
  }
  else
  {
  MessageBox.Show("Please type your e-mail and password.", "Error", MessageBoxButton.OK);
  }
}

Notice that the two things happen: 1) The users' own page is set to visible (Customer.Visibility = System.Windows.Visibility.Visible;) and the current page, the MainPages' Login-grid, is closed/collapsed (Login.Visibility = System.Windows.Visibility.Collapsed;).

VoilĂ !

Filed under: C#, Silverlight, XAML No Comments
5May/101

Views – Navigation Framework

When developing your Silverlight application you will almost always need to create several pages and subpages. Thus, you will need a navigation framework. Silverlight allows you to browse between different pages while enabling forward and backward navigation through the history using the browser's back and forward buttons.

This post provides a complete walk trough on how to implement a menu in your Silverlight application, and how to create and access subpages. You will end up with something like the application showed below (but without the formatting):

Navigation Framework - Silverlight - Menu

The working application is temporarily hosted here.

Step 1: Add support for the Navigation Framework by adding a reference to System.Windows.Controls.Navigation.dll by right clicking on the References folder in your Silverlight Project, and choosing Add reference.

Reference

Step 2: Go to the .Net tab, and select the System.Windows.Controls.Navigation, as seen below:

Add Reference

Notice that it says "Filtered to: Silverlight 4" at the top. If you happen to have converted your Silverlight application from Silverlight 3, then it will say "Filtered to: Silverlight 3", and you will need to update this by right-clicking on you project >> Properties >> and set Target Silverlight Application to "Silverlight 4".

Step 3: You will need to add System.Windows.Controls.Navigations to your UserControl definition. Insert the following code at the top of your MainPage.xaml:


    xmlns:navigation ="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"

Step 4: Create a StackPanel within your Grid in your MainPage.xaml, and insert HyperlinkButtons, that will be used as the menu. Something like this:

<!--Menu -->
            <StackPanel Orientation="Horizontal"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Bottom"
                            Grid.Column="1"
                            Grid.Row="0">

                <HyperlinkButton Content="Home"
                                 Click="LinkClick"
                                 Tag="/Home.xaml"
                                 Padding="5"/>
                <HyperlinkButton Content="Find supplier"
                                 Click="LinkClick"
                                 Tag="/Find_Supplier.xaml"
                                 Padding="5"/>
                <HyperlinkButton Content="Questionnaire data"
                                 Click="LinkClick"
                                 Tag="/Options.xaml"
                                 Padding="5"/>
            </StackPanel>
<!--Navigation Frame -->
            <navigation:Frame x:Name="ContentFrame"
                              Margin="10"
                              Grid.Row="1"
                              Grid.Column="1"
                              BorderBrush="Black"
                              BorderThickness="2"
                              Source="/Home.xaml"
                              />

Note:
Lines 2-6 define how the menu will look like, so you can of course change this as you please.
Line 10, 14, and 18: You will create each of these pages in the next step. Change the Tag so it matches the name of your subpages.
Line 9, 13, 17: The LinkClick-method is created later.
Line 28: The Source states the opening page, ie. the frontpage of your application.

The above code basically just creates the menu that the user will click on to navigate through the application. The XAML page you insert this into will not ever be shown: It is merely used to define the framework and the links to subpages. What you need to do next is actually create all the subpages, that will hold all content.

Step 5: Add a new page by right-clicking on your Project >> Add >> New Item >> New Page. It looks like this:

Add page

Remember to name the pages like you stated in the HypperlinkButton above.

Step 6: Open your new subpages and add simple Textblocks, preferably including the name of the page, so you can identify it when you run the program.

Step 7: The last step is to add a LinkClick method in your MainPage.xaml.cs.


 private void LinkClick(object sender, RoutedEventArgs e)
        {
            HyperlinkButton button = (HyperlinkButton)sender;
            string viewSource = button.Tag.ToString();
            ContentFrame.Navigate(new Uri(viewSource, UriKind.Relative));

        }

And that's it!

Inner Views

If you need to create a new page that is not one of the 'main' pages shown in the menu, you need to create an InnerView. You just do like shown above (you create a button with a Click property, but without the Tag property, and you create a new page). The main difference lies in step 7. You have to insert the code below instead:


 private void LinkClick(object sender, RoutedEventArgs e)
        {
           NavigationService.Navigate(new Uri ("/InnerView.xaml", Uri.Kind.Relative));

        }

Enjoy!

22Apr/100

External Links

Here is just a quick and small code snippet for linking to external pages from your Silverlight application.

I found quite a few potential solutions to the problem, but the first 2 or 3 just didn't compile. Most people recommended the Hyperlink with some sort of System.Diagnostics.Process.Start("http://www.link.com");attached, but I simply couldn't make it work. But finally I found a solution:

Insert a TextBlock like the one below. Notice the MouseLeftButtonDown.


            <TextBlock Grid.Column="2" Grid.Row="0"
                       VerticalAlignment="Top"
                       Text="www.aook.dk/blog"
                       TextDecorations="Underline"
                       MouseLeftButtonDown="TextBlock_MouseEnter"
                       HorizontalAlignment="Right"
             />

Next, you just need to create an EventHandler like the one below, but make sure to first add an using System.Windows.Browser; at the top.

        private void TextBlock_MouseEnter(object sender, MouseButtonEventArgs e)
        {
            HtmlPage.Window.Navigate(new Uri("http://www.aook.dk/blog"));

        }

Enjoy!

Filed under: C#, Silverlight, XAML No Comments
19Apr/100

Input validation

I needed to create a login feature, so only registered users could gain access to the Silverlight application, and I wanted to create a data validator, that would check the users' input. In the this example I just check if the user has entered an e-mail address.

Red lineError messageNo error
In the first image to the left, I have just entered my name in the E-mail address field, and entered my password. The textbox is marked with red, because there has not been registered an "@" in the field (of course, this is a very simple example. One could easily find more thorough ways of validating an e-mail address, which I will probably make a blog post about some time soon).

In the second image, the user has selected the textbox, and immediately an error message appears, explaining the user why there is a problem.

In the third image, the user has inserted a valid e-mail address and can proceed with the login feature.

So, the way to implement this feature is pretty straight-forward, especially since there is a brilliant video tutorial showing exactly how to do it. I just followed the steps on the tutorial, but I will nonetheless quickly go through the code here.

The first thing you need to know is that - as brilliant as the tutorial mentioned above may be - the code will not compile if you have the default settings on Visual Studio 2008. The tutorial does not explain that you need to make one quick settings change in order to avoid an "Arguement Exception was unhandled by User"-error message, that prevents the code from compiling.

You need to the following: Go to Visual Studio Options and then Debugging/General, and just uncheck the 'Enable Just my Code'. And that's it.

The tutorial also fails to mention a small piece of code necessary to compile, but Visual Studio helps by telling you where you need to insert the following code:

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

We'll come back to this.

How to implement the input validation:

Open your MainPage.xaml, and find the textbox whose input you want to validate. Then insert Binding statements into TextBox.Text like shown below. Notice the Path called Mail. We will use this name later.


  <TextBox width = "390" >
           <TextBox.Text>
                <Binding Mode="TwoWay"
                        Path="Mail"
                        ValidatesOnExceptions="True"
                        NotifyOnValidationError="True"
                />
          </TextBox.Text>
 </TextBox>

So, we now have a textbox that needs to be binded to a data object, so we can check when there are any changes made to it. We do this by creating a new class: Right click on your application name in the Solutions Explorer, choose Add and Class. I named my class validation.cs.

The first thing to do is to insert using System.ComponentModel; at the top, and you can delete all others system statements except the using System;. This supports the INotifyPropertyChanged, that ensures two-way binding, that is, checks if any changes are made to the object, and if there is, then the UI is updated accordingly.

Insert the following code into your validation.cs:

using System;
using System.ComponentModel;

namespace QM_v1
{
    public class validation : INotifyPropertyChanged
    {
        private string mail;

        public string Mail
        {
            get { return mail; }
            set {
                if (value.IndexOf('@') == -1)
                {
                    throw new ArgumentException("This is not a valid email address");
                }
                NotifyPropertyChanged("Mail"); // The code crashes here, if you don't change your settings, as described above.


                mail = value; }
        }

        public event PropertyChangedEventHandler propertyChanged; //mandatory event for this class. Checks the object for changes.

        private void NotifyPropertyChanged(string propertyName)
        {
                if (propertyChanged != null)
                {
                    propertyChanged(this, new PropertyChangedEventArgs(propertyName));
                }
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion
    }
}

Notice lines 33-37: This code snippet is needed for the program to compile, but is not mentioned in the tutorial mentioned above.
Lastly, open your MainPage.xaml.cs and enter the following code in your class:

  public MainPage()
        {
            InitializeComponent();


            var m = new validation();
            LayoutRoot.DataContext = m;  //LayoutRoot = name of your Grid.

        }

And that's it!

See the working example here.

Filed under: C#, Silverlight, XAML No Comments