Jan 312010
 

Recently someone asked me to write a TicTacToe game. So I worked out a rough logic for it. Heres the code. The idea is that the computer first scans through the tic-tac-toe board for any winning positions available. If none are available, then it looks for the manual user’s winning positions. If its able to find them, it blocks it. If not the next available position is filled. The game can be played by clicking any of the squares below.

Here is the code for the game as a silverlight application. The complete project can be downloaded here.

The XAML is quite simple. Just a grid with three rows and three columns

    <grid x:Name="gridGame" Background="White" Width="300" Height="300" HorizontalAlignment="Center" VerticalAlignment="Center">
        </grid><grid .RowDefinitions>
            <rowdefinition Height="100" />
            <rowdefinition Height="100" />
            <rowdefinition Height="100" />
        </grid>
        <grid .ColumnDefinitions>
            <columndefinition Width="100" />
            <columndefinition Width="100" />
            <columndefinition Width="100" />
        </grid>

It is then filled with the buttons in the Code Behind. I have hardcoded the grid size of three but this will work with any size.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 public MainPage()
        {
            InitializeComponent();
            InitializeGameLogic(true);
        }
 
        private void InitializeGameLogic(bool _fromConstructor)
        {
            if (!_fromConstructor)
            {
                gridGame.Children.Clear();
            }
            _logic = new TicTacLogic();
            for (int i = 0; i < 3; i++)
                for (int j = 0; j < 3; j++)
                {
                    Button _btnGrid = new Button();
                    _btnGrid.Name = "btn" + i.ToString() + j.ToString();
                    gridGame.Children.Add(_btnGrid);
                    Grid.SetRow(_btnGrid, j);
                    Grid.SetColumn(_btnGrid, i);
                    _btnGrid.Height = 80;
                    _btnGrid.Width = 80;
                    _btnGrid.Click += new RoutedEventHandler(_btnGrid_Click);
                }
            _logic.StartGame();
        }

All the dynamically generated buttons have a single event handler. The idea is to identify the button which sent the event from the name. Once we have the position of the button, the content has to be changed with an X. After the user marks, the computer does its stuff and makes its move. After every marking, a check is done if someone has won or the board is full.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
void _btnGrid_Click(object sender, RoutedEventArgs e)
        {
            Button _userClicked = sender as Button;
            int _xPos = Convert.ToInt32(_userClicked.Name.Substring(3,1));
            int _yPos = Convert.ToInt32(_userClicked.Name.Substring(4,1));
            _userClicked.Content = GetMarking("X");
            _logic.ClickUser(_xPos, _yPos);
            if (!(_logic.CheckIfSomeoneWon() || _logic.CheckIfBoardFull()))
            {
                int _xCom = 0;
                int _yCom = 0;
                _logic.MoveComputer(ref _xCom, ref _yCom);
                foreach (UIElement _tempElem in gridGame.Children)
                {
                    Button _comBtn = _tempElem as Button;
                    if (_comBtn != null && _comBtn.Name == "btn" + _xCom + _yCom)
                    {
                        _comBtn.Content = GetMarking("O");
                        break;
                    }
                }
                if (_logic.CheckIfSomeoneWon() || _logic.CheckIfBoardFull())
                    InitializeGameLogic(false);
            }
            else
                InitializeGameLogic(false);
 
        }
 
        private TextBlock GetMarking(string _mark)
        {
            TextBlock _t = new TextBlock();
            _t.Text = _mark;
            _t.FontSize = 25;
            _t.FontWeight = FontWeights.Bold;
            return _t;
        }

The Board class maintains two important things. The position of all the squares and which player has it marked. The Board doesnt depend on the Player objects. It has an object of the WinningPositions object which calculates the winning positions which can be compared with later. This object makes it possible to play with larger grids.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
public class Board
{
    readonly int MAXSIZE;
    List<positionmarking> _boardState = new List</positionmarking><positionmarking>();
    List<position []> _allWinningPositions;
 
    public List<positionmarking> BoardState { get { return _boardState; } }
    public List<position []> AllWinningPositions { get { return _allWinningPositions; } }
    public int MaxSize { get { return MAXSIZE; } }
 
    public Board()
    {
        this.MAXSIZE = 3;
        Initialize();
    }
 
    public Board(int _maxSize)
    {
        MAXSIZE = _maxSize;
        Initialize();
    }
 
    private void Initialize()
    {
        _allWinningPositions = (new WinningPositions(MAXSIZE)).AllWinningPositions;
        for(int _xPos=0;_xPos<maxsize ;_xPos++)
            for (int _yPos = 0; _yPos < MAXSIZE; _yPos++)
            {
                _boardState.Add(new PositionMarking(_xPos,_yPos));
            }
    }
 
    internal void MarkPosition(int _xUser, int _yUser, bool _userMarked)
    {
        foreach (PositionMarking _tempPos in _boardState)
        {
            if (_tempPos.BoardPosition.X == _xUser && _tempPos.BoardPosition.Y == _yUser)
            {
                _tempPos.MarkPosition(_userMarked);
                break;
            }
        }
#if DEBUG
        PrintBoardState();
#endif
    }
 
    internal bool? MarkedByUser(Position _tempPos)
    {
        foreach (PositionMarking _tempMark in _boardState)
        {
            if (_tempPos.X == _tempMark.BoardPosition.X && _tempPos.Y == _tempMark.BoardPosition.Y)
                return _tempMark.IsUserMarked;
 
        }
        throw new Exception("Position Not found on Board");
    }
 
    #if DEBUG
    internal void PrintBoardState()
    {
        string _userMarked = "";
        string _compMarked = "";
        foreach (PositionMarking _tempMark in _boardState)
        {
 
            if (_tempMark.IsUserMarked == true)
                _userMarked += "("+ _tempMark.BoardPosition.X + "," + _tempMark.BoardPosition.Y + ") ";
            else if (_tempMark.IsUserMarked == false)
                _compMarked += "(" + _tempMark.BoardPosition.X + "," + _tempMark.BoardPosition.Y + ") ";
        }
        Debug.WriteLine("USER: " + _userMarked);
        Debug.WriteLine("COMP: " + _compMarked);
        Debug.WriteLine("________________________________________");
    }
#endif
    internal bool IsBoardFull()
    {
        foreach (PositionMarking _tempMark in _boardState)
        {
            if (_tempMark.IsUserMarked == null)
                return false;
 
        }
        MessageBox.Show("Board Full");
        return true;
    }
}

The Winning Position class is given below and all positions are calculated at initialization. First the horizontal ones are considered and then the vertical ones. The remaining diagonal positons are taken care later. Each winning position is stored in an array of the position object which just holds the value of the Squares. These arrays are stored in a generic List.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public class WinningPositions
{
    List<position []> _allWinningPositions = new List</position><position []>();
    Position[] _winPos1;
    Position[] _winPos2;
 
    public List</position><position []> AllWinningPositions
    {
        get { return _allWinningPositions; }
    }
 
    public WinningPositions(int _maxSize)
    {
        _winPos1 = new Position[_maxSize];
        _winPos2 = new Position[_maxSize];
        PopulateWinningPositions();
    }
 
    private void PopulateWinningPositions()
    {
        int _iCounter=0;
        int _xPos = 0;
        int _yPos = 0;
        for (_xPos = 0; _xPos < _winPos2.Length; _xPos++)
        {
            for (_yPos = 0; _yPos < _winPos2.Length; _yPos++)
            {
                _winPos1[_iCounter] = new Position(_xPos, _yPos);
                _winPos2[_iCounter] = new Position(_yPos, _xPos);
                _iCounter++;
            }
            _allWinningPositions.Add(_winPos1);
            _allWinningPositions.Add(_winPos2);
            _winPos1 = new Position[_winPos1.Length];
            _winPos2 = new Position[_winPos2.Length];
            _iCounter = 0;
        }
        _iCounter = 0;
        for (_xPos = 0, _yPos = 0;_xPos < _winPos1.Length; _xPos++, _yPos++)
        {
            _winPos1[_iCounter] = new Position(_xPos, _yPos);
 
            _iCounter++;
        }
        _allWinningPositions.Add(_winPos1);
        _iCounter = 0;
        for (_xPos = 0, _yPos = _winPos1.Length - 1; _xPos < _winPos1.Length; _xPos++, _yPos--)
        {
            _winPos2[_iCounter] = new Position(_xPos, _yPos);
            _iCounter++;
        }
        _allWinningPositions.Add(_winPos2);
    }
}

Then there is the Player class of which we create two objects. The user takes care of his own moving logic, all we need to do is to change the state of the square for him. But the computer has its method called the SmartMove. Here we first move through the winning positions to identify any open squares that can be marked. If there are no squares, then we look to block the opponent’s winning. If even this opportunity is not found, we mark an available open square.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
public class Player
{
    Board _currentBoardPosition;
    bool _isComputer;
    List<position> _allMarkedPositions;
 
    public Player(bool _isComputer,Board _currentBoardPos)
    {
        this._isComputer = _isComputer;
        _allMarkedPositions = new List</position><position>();
        _currentBoardPosition = _currentBoardPos;
    }
 
    internal void SmartMove(ref int _xCom, ref int _yCom)
    {
        bool _markingDone = false;
        bool _blockUser = false;
        Position _userBlock = new Position();
        foreach (Position[] _winPos in _currentBoardPosition.AllWinningPositions)
        {
            int _userMarked = 0;
            int _computerMarked = 0;
            int _nullMarked=0;
 
            Position _openPos= new Position();
            foreach (Position _tempPos in _winPos)
            {
                bool? isUserMarked = _currentBoardPosition.MarkedByUser(_tempPos);
                if (isUserMarked==true)
                    _userMarked++;
                else if (isUserMarked == false)
                    _computerMarked++;
                else
                {
                    _openPos = _tempPos;
                    _nullMarked++;
                }
 
            }
            if (_computerMarked == 2 && _nullMarked == 1)
            {
                Debug.WriteLine("Wining block: " + _openPos.X + "," + _openPos.Y);
                _currentBoardPosition.MarkPosition(_openPos.X, _openPos.Y, false);
                _xCom = _openPos.X;
                _yCom = _openPos.Y;
                _markingDone = true;
                break;
            }
            else if (_userMarked == 2 && _nullMarked == 1)
            {
                _userBlock = _openPos;
                _blockUser = true;
            }
 
        }
        if (_blockUser && !_markingDone)
        {
            _currentBoardPosition.MarkPosition(_userBlock.X, _userBlock.Y, false);
            _xCom = _userBlock.X;
            _yCom = _userBlock.Y;
            _markingDone = true;
        }
 
        if (!_markingDone)
        {
 
            //No Winning Position Found or not able to block;
            foreach (PositionMarking _posMark in _currentBoardPosition.BoardState)
            {
                if (_posMark.IsUserMarked == null)
                {
                    _markingDone = true;
                    _currentBoardPosition.MarkPosition(_posMark.BoardPosition.X, _posMark.BoardPosition.Y,false);
                    _xCom = _posMark.BoardPosition.X;
                    _yCom = _posMark.BoardPosition.Y;
                    break;
                }
            }
 
        }
    }
}
</position>

Since the Board needs to maintain the state of each and every position on itself, we have another object for it, which maintains a position object and a nullable boolean. If the boolean is true, then the square is marked by the user, if false – then by the computer. If its still null – its open and can be marked. The marking is done by the object’s method which makes a check to make sure no players marking is overwritten by another.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class PositionMarking
{
    Position _boardPos;
    bool? _isUserMarked;
 
    public Position BoardPosition { get { return _boardPos; } }
    public bool? IsUserMarked { get { return _isUserMarked; } }
 
    public PositionMarking(int _xPos,int _yPos)
    {
        _isUserMarked = null;
        _boardPos = new Position(_xPos, _yPos);
    }
 
    public void MarkPosition(bool _markedByUser)
    {
        if(_isUserMarked == null)
        _isUserMarked = _markedByUser;
        else
        throw new Exception("Position already taken");
    }
}

Then there is the rest of the code including our business logic layer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
public class TicTacLogic
{
    bool _userToMove;
    bool _resultHasCome;
    Player _user;
    Player _computer;
    Board _gameBoard;
 
    public TicTacLogic()
    {
        _userToMove = true;
        _resultHasCome = false;
    }
 
    internal void StartGame()
    {
        Initialize();
    }
 
    internal bool ClickUser(int _xUser, int _yUser)
    {
        return _gameBoard.MarkPosition(_xUser, _yUser, true);
    }
 
    internal void MoveComputer(ref int _xCom, ref int _yCom)
    {
        _computer.SmartMove(ref _xCom, ref _yCom);
    }
 
    internal void Initialize()
    {
        _gameBoard = new Board(3);
        _user = new Player(false,_gameBoard);
        _computer = new Player(true,_gameBoard);
 
    }
 
    public bool CheckIfSomeoneWon()
    {
        foreach (Position[] _tempWin in _gameBoard.AllWinningPositions)
        {
            int _userWon=0;
            int _compWon=0;
            foreach (Position _p in _tempWin)
            {
                bool? isUserMarked = _gameBoard.MarkedByUser(_p);
                if (isUserMarked == null)
                    break;
                else if (isUserMarked == true)
                    _userWon++;
                else
                    _compWon++;
 
            }
            if (_userWon == _gameBoard.MaxSize)
            {
                MessageBox.Show("User Won");
                return true;
            }
            else if (_compWon == _gameBoard.MaxSize)
            {
                MessageBox.Show("Computer Won");
                return true;
            }
 
        }
        return false;
    }
 
    internal bool CheckIfBoardFull()
    {
        return _gameBoard.IsBoardFull();
    }
}
 
public class Position
{
    int _xPos;
    int _yPos;
 
    public Position()
    {
    }
 
    public int X { get { return _xPos; } }
    public int Y { get { return _yPos; } }
 
    public Position(int xPos, int yPos)
    {
        this._xPos = xPos;
        this._yPos = yPos;
    }
}

Nov 252009
 

In my previous blog, I wrote about the simplest form of animation in Silverlight – the FromTo animation, which allows you to modify the value of Control properties thus giving animation effects like Fading in-out, movement and many more. KeyFrame animation is different as in it gives you more control in defining both the duration and the value of the property in each animation.

Like in the FromTo animation, you can set the Target, AutoReverse, BeginTime and RepeatBehavior for KeyFrame as well. Lets look at a simpleKeyFrame animation. In this we manipulate both the Color and the FontSize property. The SplineDoubleKeyFrame property has a key and value pair which allows us to specify the value at that exact point of time.

Here is the markup.

<Grid x:Name="LayoutRoot" Height="Auto" Width="300">
       <Grid.Triggers>
           <EventTrigger RoutedEvent="Grid.Loaded">
               <TriggerActionCollection>
                   <BeginStoryboard>
                       <Storyboard>
                           <DoubleAnimationUsingKeyFrames
               Storyboard.TargetName="AnimateText"
               Storyboard.TargetProperty="FontSize"
               BeginTime="00:00:00"
               RepeatBehavior="Forever"
                               AutoReverse="True">
                               <SplineDoubleKeyFrame KeyTime="00:00:02" Value="50" />
                               <SplineDoubleKeyFrame KeyTime="00:00:06" Value="75" />
                               <SplineDoubleKeyFrame KeyTime="00:00:08" Value="90" />
                               <SplineDoubleKeyFrame KeyTime="00:00:10" Value="80" />
                               <SplineDoubleKeyFrame KeyTime="00:00:14" Value="35" />
                           </DoubleAnimationUsingKeyFrames>
                           <ColorAnimationUsingKeyFrames
                               Storyboard.TargetName="solidBrush"
                               Storyboard.TargetProperty="Color"
                               BeginTime="00:00:00"
                               RepeatBehavior="Forever"
                               AutoReverse="True">
                               <SplineColorKeyFrame KeyTime="00:00:02" Value="Red" />
                               <SplineColorKeyFrame KeyTime="00:00:04" Value="Blue" />
                               <SplineColorKeyFrame KeyTime="00:00:06" Value="Black" />
                               <SplineColorKeyFrame KeyTime="00:00:08" Value="Beige" />
                               <SplineColorKeyFrame KeyTime="00:00:10" Value= "DarkGreen" />
                           </ColorAnimationUsingKeyFrames>
                       </Storyboard>
                   </BeginStoryboard>
               </TriggerActionCollection>
           </EventTrigger> 
       </Grid.Triggers>
       <TextBlock x:Name="AnimateText" 
                  FontSize="35" 
                  Text="Hello World"
                  TextWrapping="Wrap"
                  >
           <TextBlock.Foreground>
               <SolidColorBrush x:Name="solidBrush"
                                Color="Black" />
           </TextBlock.Foreground>
       </TextBlock>
      
   </Grid>

Here is the sample:-


Get Microsoft Silverlight

Nov 232009
 

Few days ago I blogged about the Silverlight TransitionContent control. In this post we will see the Accordion Control in the Silverlight Control Toolkit. The Accordion is a very common control which we use in a lot of places. For e.g. the Outlook List of mails is an accordion. As you would have guessed it, it is very helpful in displaying a lot of data in a concise way.

So like the previous post, we need to create a new application and add a reference to the the Controls.Layout.Toolkit dll. The Page markup is slightly complicated this time, mainly because I used nested grids for alignment. I posted the relevant parts here.

<layout:Accordion x:Name="photoDetails"
                           Grid.Column="0"
                           Grid.Row="0"
                           HorizontalAlignment="Stretch"
                           VerticalAlignment="Top"
                           Margin="10"
                           Height="Auto"
                           SelectionMode="ZeroOrOne"
                           SelectionSequence="CollapseBeforeExpand">
             <layout:Accordion.ItemContainerStyle>
                 <Style x:Name="accordionitemstyle1" TargetType="layout:AccordionItem">
                     <Setter Property="HeaderTemplate">
                         <Setter.Value>
                             <DataTemplate>
                                 <TextBlock Text="{Binding Name}" />
                             </DataTemplate>
                         </Setter.Value>
                     </Setter>
                 </Style>
             </layout:Accordion.ItemContainerStyle>
             <layout:Accordion.ContentTemplate>
                     <DataTemplate>
                         <StackPanel Height="200" Width="Auto" VerticalAlignment="Stretch">
                         <TextBlock
                             Text="{Binding Path=Location}"
                             HorizontalAlignment="Center"
                             FontFamily="Verdana"
                             FontSize="20"/>
                         <Image Source="{Binding Path=ImageSource}" />
                         </StackPanel>
                     </DataTemplate>
                 </layout:Accordion.ContentTemplate>
             </layout:Accordion>

The accordion control is an Item Control and consists of a collection of AccordionItem controls. It has most of the Control properties along with few of its own. Two important properties are SelectionMode and SelectionSequence. The SelectionMode property sets the number of AccordionItems that can be opened Simultaneously and the SelectionSequence property controls how the Items behave when open and closed.

The Accordion has a header Template and Content Template as well, which helps us to bind it to an Enumerable object which can generate the Headers and AccordionItems at runtime. Note that in the markup I bound the HeaderTemplate to the Name property and For the ContentTemplate bound a TextBlock and an Image Source property. This is where the Content property is so useful, that it can be set to virtually anything.

Now the code behind which we use to bind to our XAML. The class here is a simple class with just three public properties.

public class Photography
{
    //bound to header
    public string Name { get; set; }

    //Both of these are bound to content
    public string Location { get; set; }
    public ImageSource ImageSource { get; set; }
}

The BindData method creates an IEnumerable object which is an array of objects of the Photography class and assigns it to the ItemsSource property of the Accordion. It then iterates through the array and searches for objects with public properties that are bound to the controls, in our case – Name,Location and ImageSource. When it finds these public properties it takes the value and assigns it to the Bound control.

private void BindData()
 {
     photoDetails.ItemsSource = new[]{
         GetPhotographDetails("Stone Henge", "England", "A.jpg"),
     GetPhotographDetails("Colloseum", "Rome",  "B.jpg"),
     GetPhotographDetails("Taj Mahal", "India",  "C.jpg"),
     GetPhotographDetails("Chitchen Itza", "Middle Of Nowhere","D.jpg"),
     GetPhotographDetails("Great Wall", "China",  "E.jpg"),
    GetPhotographDetails("The Pyramids", "Giza", "F.jpg"),
     GetPhotographDetails("Christ Redeemer", "Brazil", "G.jpg")};
 }

The next two methods are almost same as the ones I used in the previous example, so I will skip them. There is also a button in the XAML file which I didn’t paste because of its length. The Button Next is for collapsing the currently open AccordionItem and opening the next. Lets see the Event Handler for it. Its just a simple method for cycling through the Items of the Accordion

private void Button_Click(object sender, RoutedEventArgs e)
{
    int selectedIndex = photoDetails.SelectedIndex;
    if ((selectedIndex+1) >= photoDetails.Items.Count)
       selectedIndex=0;
    else
        selectedIndex++;

    photoDetails.SelectedIndex = selectedIndex;
}

Our Work is done. Below is the sample of the control. If you want to download the whole sample, Click here.

Get Microsoft Silverlight

Nov 212009
 

Displaying a slideshow of various images is a very common requirement these days. It can be done very easily using the Transtion Control in Silverlight Control Toolkit. Lets see how.

First create a Silverlight Application using Visual Web Developer.
newProject

The Transition Control is a part of the Toolkit, which we need to add a reference to. Right click References, Click Add Reference and choose  System.Windows.Controls.Layout.Toolkit.

addRef

Now that we added the reference, we also need to add the namespace in the XAML page.

xmlns:transition="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"

Now comes the page markup, This page contains a grid separated into two columns. One with the Transition Control and one with the Button to make the switch.

<UserControl x:Class="SLTransition.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"
    xmlns:transition="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit"
   Height="360"  Width="460" >
  <Grid x:Name="LayoutRoot" Height="300" Width="400" Margin="30">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="325" />
            <ColumnDefinition Width="75" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
        <transition:TransitioningContentControl
            Name="imageTransition"
            Grid.Column="0"
            Grid.Row="1"
            HorizontalAlignment="Stretch"
            VerticalAlignment="Stretch"
            Transition="DownTransition" />
        <Button x:Name="Next"
              Width="50"
              Height="30"
              HorizontalAlignment="Center"
              VerticalAlignment="Center"
              Grid.Row="0"
              Grid.Column="1"
              Content="Next"/>
    </Grid>
</UserControl>

Now the code to make the transition work. There are two class level variables in the MainPage.xaml.cs page. One is the counter to iterate through the pictures and another a string array containing the names of the image files. I didn’t give the extension here and gave it later, but you can do it in the array as well, which would be needed if you are going to use images of different formats.

int _counter = 0;
string[] _picNames = { "A", "B","C","D","E","F","G" };

Now the constructor and the Next Button Click event handler. In the constructor the click event handler is added for the next button and then the Silverlight transition control is populated with the first image in the string array. The counter is then incremented. In the next button click handler, we populate the Silverlight transition control with the image of the current counter value and increment the counter value again.

public MainPage()
{
    InitializeComponent();
    Next.Click += new RoutedEventHandler(Next_Click);
    imageTransition.Content = GetImage(0);
    _counter++;
}

void Next_Click(object sender, RoutedEventArgs e)
{
    imageTransition.Content = GetImage(_counter);
    _counter++;
}

Now the code to retrieve the image from the string array. First if the counter has reached the limit of the string array, then we reset it to 0. Then the path is constructed from the string array and set as an Image and returned to the calling function which sets the Silverlight Transition Control’s Content Property. Since the image class inherits from FrameworkElement, it can be set as the Content.

Image GetImage(int _counter)
{
    if (_counter >= _picNames.Length)
        this._counter = 0;
    Image _image = new Image();
    Uri _uri = new Uri(_picNames[this._counter] + ".jpg", UriKind.Relative);
    ImageSource _imgSource = new BitmapImage(_uri);
    _image.SetValue(Image.SourceProperty, _imgSource);
    return _image;
}

Also the images must be copied to the Silverlight project for it to find. Thats it, the image transition control will work perfectly. See it in action below. I used some pics of the Wonders of the World. Click the next button to view the transition. This is the DownTransition, the other values for this control are UpTransition, DefaultTransition and Normal.


Get Microsoft Silverlight

Nov 122009
 

The audience which the web was catering to, has drastically changed in the last 10 years. From primary being a one way of source of information for its users, the web has evolved into a massive aggregator with which users can both create and consume information. This meant a sea change for web developers and application designers where they had to make their User interface much more interactive and closer to windows applications.

Adobe Flash and Microsoft Silverlight are a step in that direction. Groundbreaking animation is possible with these technologies. We will take a look at some simple animation in Silverlight today. First the simplest animation possible. The Double animation works by moifying a double property of the application in a time bound way. Suppose we want to create a rectangle that disappears and reappears every second. Lets take a look at the XAML.

<UserControl x:Class="SLAnimation.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 >
            <StackPanel.Resources>
                <Storyboard x:Name="AppStoryBoard">
                    <DoubleAnimation x:Name="clickAnim"
                                     Storyboard.TargetName="animRectangle"
                                     Storyboard.TargetProperty="Opacity"
                                     From="1.0" To="0.0" Duration="0:0:1"
                                     AutoReverse="True"
                                     RepeatBehavior="Forever" />
                </Storyboard>
            </StackPanel.Resources>
            <TextBlock TextAlignment="Center" FontSize="30" FontFamily="Verdana">Double Animation in Silverlight</TextBlock>
            <Rectangle x:Name="animRectangle" MouseLeftButtonDown="animRectangle_MouseLeftButtonDown"
                       Width="200" Height="100" Fill="Red" ></Rectangle>
        </StackPanel>
    </Grid>
</UserControl>

If you see this code, the animation is defined in the Storyboard tag which contains the code of how exactly the animation will behave. It specifies the target control and also the property which has to be altered. Then we give the for loop for changing the transparency along with the step property. Once the story board is done, you need to write the control which is the target of the StoryBoard, a simple rectangle. However, a presence of a storyboard is not enough to start the animation. This is done in the code behind.

        public MainPage()
        {
            InitializeComponent();
        }
 
        private void animRectangle_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            AppStoryBoard.Begin();
        }

Even this can be achieved through XAML alone as we will see in the next example. In this looping animation two rectangles will move to the opposite ends of the canvas before returning. The best part is there is no code behind involved. The Storyboard is triggered by the EventTriggers tag in Silverlight. This time the property that is modified is the Canvas.Left. One rectangle already has this property set to 0 and one has it to 280. And in the storyboard, there are respective DoubleAnimation tags added. One of them increases the first rectangle’s Canvas.Left property from 0 to 280 and the other vice versa. Since the RepeatBehavior is set to Forever, it seems like an endless loop.

<Canvas>
<Canvas.Triggers>
<EventTrigger RoutedEvent="Canvas.Loaded" >
<EventTrigger.Actions>
    <BeginStoryboard>
        <Storyboard x:Name="animRectangle1"
                    Storyboard.TargetName="Rectangle1"
                    Storyboard.TargetProperty="(Canvas.Left)" RepeatBehavior="Forever">
            <DoubleAnimation To="280" Duration="0:0:15"></DoubleAnimation>
            <DoubleAnimation To="0" Storyboard.TargetName="Rectangle2" Duration="0:0:15"></DoubleAnimation>
        </Storyboard>
    </BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Canvas.Triggers>
<TextBlock TextAlignment="Center" FontSize="30" FontFamily="Verdana">Moving Animation in Silverlight</TextBlock>

<Rectangle x:Name="Rectangle1" Canvas.Left="0" Canvas.Top="40" Width="20" Height="20" Fill="red"></Rectangle>
<Rectangle x:Name="Rectangle2" Canvas.Left="280" Width="20" Canvas.Top="40" Height="20" Fill="Blue"></Rectangle>
</Canvas>

So we saw how easy it is to create simple animation with Silverlight. Below is a simple preview of the application. And as one more demonstration of the platform independent nature of Silverlight, I just wrote the object tag for the Silverlight .xap file and thats it, it works in WordPress’s PHP without any hiccups.

Get Microsoft Silverlight

Nov 092009
 

Silverlight 3.0 finally got over the beta stage in July. Here are the most exciting features of Silverlight 3

H.264 video support:

This was a long standing demand since 2.0.  H.264 is the industry standard and not everyone wanted to encode their existing video to VC-1. And since customers had a ready alternative in Adobe Flash 9 which supported this format, Microsoft decided to incorporate this suppport along with Windows media and Vc-1 support. More choice is always better!!

Smooth Streaming:

The sales pitch for this technology sounds promising, especially in India where connections are dead slow not that fast, and it is quite common to experience variable data transfer rates within short times. Smooth Stream implies that the client communicates with the Streaming server to stream data depending on the transfer rate. i.e. the video adapts itself in real time without pauses for buffering data. SmoothStream ships with the IIS7 media pack. It doesn’t require the files to be split in small chunks.

Better Graphics:

Unlike previous versions of Silverlight, which utilized the CPU for graphics, Silverlight 3 transfers the graphics rendering to the GPU making use of its accelaration. This improves application graphics and also reduces the load on the CPU.

Out of Browser Support:

This enables Silverlight applications to be run offline without the client browser. Once this is enabled in the Silverlight project settings page, we can right click on the Page and click “Install Out of Browser” and thats it, the application “installs” itself to the Start menu and desktop and is able to run offline without the net connection. In reality the .xap file for the silverlight application is copied to the client and run in a light browser client. The xap file is actually just a compressed archive of the application dlls and the xaml files. Microsoft also provides a sync api to properly sync the application once the user comes back online.

SEO capability:

Many customers don’t go for applications which are completely written in Silverlight and Adobe Flash mainly because they arent search engine friendly. GoogleBot or MSN Bot while crawling their site would only see an Object tag which wont be indexed no matter how many backlinks to that page exist. Silverlight has improved this by giving the option of giving Alternate HTML tags inside the Silverlight Object tags which are Search friendly.

Apart from these star attractions in Silverlight 3, there are tons of new features like Better controls, Better accessibility, support for vector graphics and many more. Go Check it out!!!

Nov 082009
 

Microsoft Silverlight 3 includes support for creating Rich Internet Applications with virtually no code at all. In this article, I will create a simple RIA application which displays data from the SQL Server 2005 AdventureWorks database. For those who are wondering what RIA services are? Its a pattern which integrates ASP.NET with Silverlight and provides a simple way to write n-tier applications. What I admired about RIA services applications are it brings your database logic to your business layer. What that means is that your database and Data access layer virtually contains no application specific code at all. In future, upgrading, migrating to any other database is amazingly simple. There is the element of a performance implication while using Linq though, which needs to be taken into consideration. Thanks to Sachin Rathi from Microsoft for his session in TechDays where he taught about this new topic.

So lets jump into it. First the tools, which can be downloaded from here. The fifth point in the list is the RIA kit. Once thats done, you would have a new template – Silverlight Business Application.

newProject

So like we saw in the previous blog, there are two applications created – one for our Silverlight application and one for the ASP.NET application. The basic application is already created with a decent theme.

businessApp

Lets create a new xaml page for displaying our data created by the RIA applications. Right click on the Views folder and add a new Silverlight page.

addnewPage

addnewItem

Now that the new Silverlight page is created, lets add a link to it from the main page. Add this markup after the link to the about page.

<Rectangle x:Name=”Divider2″ Style=”{StaticResource DividerStyle}”/>
<HyperlinkButton x:Name=”Link3″ Style=”{StaticResource LinkStyle}”
NavigateUri=”/EmployeesPage” TargetName=”ContentFrame” Content=”Employees”/>
Once thats done, we need to add any database from which to retrieve data from. I will use the sample AdventureWorks database. Copy the database file to the App_Data folder. Now what is needed is a Entity Data model. The Entity data model generates a ER data model by analyzing the database. Right click on the web project and add a new item – AdventureWorks.edmx. In the next screen click on Generate from database. The ED model automatically detects the database files and generates the connection string. Click next and select the employee table alone in the next screen.
edmxModel
edmodel
This step generates the entity relationship model for the database, and make the code “aware” of the underlying database. In later steps we could write Linq queries against the database. The next step would be to add a new domain service class, the item template for which has been installed already.
domainService
domainServiceOpts
To the domain service class that was automatically generated, add a new method GetSalariedEmployees.
public IQueryable<Employee> GetEmployees()
{
return this.Context.Employee;
}
public IQueryable<Employee> GetSalariedEmployees()
{
return this.Context.Employee
.Where(emp => emp.SalariedFlag == true);
}
Then add a new datagrid to the EmployeesPage.xaml. A reference needs to be added to the Windows.Controls.Data assembly. Also a namespace is added to the datagrid. The markup is as below.
employeeMarkup
Now that the datagrid is loaded, lets add the namespace for the Application in the xaml page. Here is the finished xaml file.
finishedXaml
It can also be done through code like this.
employees _eObj = new employees();
public EmployeesPage()
{
InitializeComponent();
this.dataGrid.ItemsSource = _eObj.Employees;
_eObj.Load(_eObj.GetEmployeeQuery());
}

This application is by no means over, we can add sorting, filtering, updating rows to this with as little code as possible. More about it in future posts.