Thursday, November 10, 2016

PanoramaControl


This is Windows 8 Style based window.

This is the Main Page content:
<Controls:MetroWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="WpfApplication1.MainWindow"
    xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
    xmlns:pan="clr-namespace:PanoramaControl;assembly=PanoramaControl"
    xmlns:local="clr-namespace:WpfApplication1"
    x:Name="Window"
Title="MainWindow"
    ShowTitleBar="True"
    ShowIconOnTitleBar="false"
    ResizeMode="NoResize"
    Width="960" MinWidth="960" Height="540">
  <Window.Resources>



        <DataTemplate DataType="{x:Type local:PanoramaTileViewModel}">
            <Border x:Name="bord"
                    BorderThickness="2"
                    BorderBrush="{Binding RelativeSource={RelativeSource Mode=Self},
                        Path=Background}"
                    Background="{Binding RelativeSource={RelativeSource
                        AncestorType={x:Type pan:Panorama},
                        Mode=FindAncestor},
                        Path=TileColorPair[0]}"
                    Width="120" Height="120" Margin="0">
                <StackPanel Orientation="Horizontal">

                    <Button Command="{Binding TileClickedCommand}">
                        <Button.Template>
                            <ControlTemplate>
                                <Image x:Name="img"
                                    Source="{Binding ImageUrl}"
                                    Width="100"
                                    Height="100"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center"
                                    ToolTip="{Binding Text}" >
                                </Image>
                                <ControlTemplate.Triggers>
                                    <DataTrigger Binding="{Binding IsDoubleWidth}" Value="True">
                                        <Setter TargetName="img"
                                            Property="HorizontalAlignment"
                                            Value="Left" />
                                        <Setter TargetName="img"
                                            Property="Margin"
                                            Value="10,0,0,0" />
                                    </DataTrigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Button.Template>
                    </Button>
                   

                    <Grid  Margin="30,0,0,0"
                            HorizontalAlignment="Left"
                            VerticalAlignment="Center">
                       
                    <Ellipse Stroke="White"
                                StrokeThickness="2"
                                Width="50"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Height="50" Fill="Transparent"/>
                   
                        <Label x:Name="liveUpdate"
                            Content="{Binding Counter}"
                            Visibility="Collapsed"
                            HorizontalAlignment="Center"
                            HorizontalContentAlignment="Center"
                            VerticalAlignment="Center"
                            VerticalContentAlignment="Center"
                            Foreground="White"
                            FontFamily="Segoe UI"
                            FontSize="30"
                            FontWeight="DemiBold"/>
                    </Grid>

                </StackPanel>

            </Border>
            <DataTemplate.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource
                                AncestorType={x:Type ListBoxItem}, Mode=FindAncestor},
                                Path=IsSelected}"
                                Value="True">
                    <Setter TargetName="bord"
                            Property="BorderBrush"
                            Value="{Binding RelativeSource={RelativeSource
                                AncestorType={x:Type pan:Panorama}, Mode=FindAncestor},
                                Path=TileColorPair[1]}"/>
                </DataTrigger>
                <DataTrigger Binding="{Binding IsDoubleWidth}"
                                Value="True">
                    <Setter TargetName="bord"
                            Property="Width"
                            Value="240" />
                    <Setter TargetName="liveUpdate"
                            Property="Visibility"
                            Value="Visible" />
                </DataTrigger>
            </DataTemplate.Triggers>
        </DataTemplate>      
       
    </Window.Resources>
<Grid x:Name="LayoutRoot" Background="CornflowerBlue" Width="960" >
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>


        <CheckBox x:Name="chkUseSNapBackScrolling"
                    Foreground="White"
                    Content="Use Snap Back Scrolling"
                    Margin="20,10,0,10"
                    IsChecked="True"
                    VerticalAlignment="Center"
                    VerticalContentAlignment="Center"
                    HorizontalAlignment="Left"
                    HorizontalContentAlignment="Left" />

        <pan:Panorama Grid.Row="1" x:Name="pan"
                      UseSnapBackScrolling="{Binding ElementName=chkUseSNapBackScrolling, Path=IsChecked, Mode=OneWay}"
                      ItemsSource="{Binding PanoramaItems}"
                      ItemBox="120"
                      GroupHeight="360"
                      Background="Transparent" />
</Grid>
</Controls:MetroWindow>


You have to Add the images in your folder under the solution


Scroll Viewer Template Class

[TemplatePart(Name = "PART_ScrollViewer", Type = typeof(ScrollViewer))]
    public class Panorama : ItemsControl
    {
        #region Data
        private ScrollViewer sv;
        private Point scrollTarget;
        private Point scrollStartPoint;
        private Point scrollStartOffset;
        private Point previousPoint;
        private Vector velocity;
        private double friction;
        private DispatcherTimer animationTimer = new DispatcherTimer(DispatcherPriority.DataBind);
        private static int PixelsToMoveToBeConsideredScroll = 5;
        private static int PixelsToMoveToBeConsideredClick = 2;
        private Random rand = new Random(DateTime.Now.Millisecond);
        private bool _mouseDownFlag;
        private Cursor _savedCursor;
        #endregion

        #region Ctor
        public Panorama()
        {
            friction = 0.85;

            animationTimer.Interval = new TimeSpan(0, 0, 0, 0, 20);
            animationTimer.Tick += new EventHandler(HandleWorldTimerTick);
            animationTimer.Start();

            TileColors = new Brush[] {
                new SolidColorBrush(Color.FromRgb((byte)111,(byte)189,(byte)69)),
                new SolidColorBrush(Color.FromRgb((byte)75,(byte)179,(byte)221)),
                new SolidColorBrush(Color.FromRgb((byte)65,(byte)100,(byte)165)),
                new SolidColorBrush(Color.FromRgb((byte)225,(byte)32,(byte)38)),
                new SolidColorBrush(Color.FromRgb((byte)128,(byte)0,(byte)128)),
                new SolidColorBrush(Color.FromRgb((byte)0,(byte)128,(byte)64)),
                new SolidColorBrush(Color.FromRgb((byte)0,(byte)148,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)0,(byte)199)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)135,(byte)15)),
                new SolidColorBrush(Color.FromRgb((byte)45,(byte)255,(byte)87)),
                new SolidColorBrush(Color.FromRgb((byte)127,(byte)0,(byte)55))
   
            };

            ComplimentaryTileColors = new Brush[] {
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255)),
                new SolidColorBrush(Color.FromRgb((byte)255,(byte)255,(byte)255))
            };

        }

        static Panorama()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(Panorama), new FrameworkPropertyMetadata(typeof(Panorama)));
        }
        #endregion

        #region Properties
        public double Friction
        {
            get { return 1.0 - friction; }
            set { friction = Math.Min(Math.Max(1.0 - value, 0), 1.0); }
        }

        public List<Brush> TileColorPair
        {
            get
            {
                int idx = rand.Next(TileColors.Length);
                return new List<Brush>() { TileColors[idx], ComplimentaryTileColors[idx] };
            }
        }

        #region DPs


        #region ItemBox

        public static readonly DependencyProperty ItemBoxProperty =
            DependencyProperty.Register("ItemBox", typeof(double), typeof(Panorama),
                new FrameworkPropertyMetadata((double)120.0));


        public double ItemBox
        {
            get { return (double)GetValue(ItemBoxProperty); }
            set { SetValue(ItemBoxProperty, value); }
        }

        #endregion

        #region GroupHeight

        public static readonly DependencyProperty GroupHeightProperty =
            DependencyProperty.Register("GroupHeight", typeof(double), typeof(Panorama),
                new FrameworkPropertyMetadata((double)640.0));


        public double GroupHeight
        {
            get { return (double)GetValue(GroupHeightProperty); }
            set { SetValue(GroupHeightProperty, value); }
        }

        #endregion



        #region HeaderFontSize

        public static readonly DependencyProperty HeaderFontSizeProperty =
            DependencyProperty.Register("HeaderFontSize", typeof(double), typeof(Panorama),
                new FrameworkPropertyMetadata((double)30.0));

        public double HeaderFontSize
        {
            get { return (double)GetValue(HeaderFontSizeProperty); }
            set { SetValue(HeaderFontSizeProperty, value); }
        }

        #endregion



        #region HeaderFontColor

        public static readonly DependencyProperty HeaderFontColorProperty =
            DependencyProperty.Register("HeaderFontColor", typeof(Brush), typeof(Panorama),
                new FrameworkPropertyMetadata((Brush)Brushes.White));

        public Brush HeaderFontColor
        {
            get { return (Brush)GetValue(HeaderFontColorProperty); }
            set { SetValue(HeaderFontColorProperty, value); }
        }

        #endregion

        #region HeaderFontFamily

        public static readonly DependencyProperty HeaderFontFamilyProperty =
            DependencyProperty.Register("HeaderFontFamily", typeof(FontFamily), typeof(Panorama),
                new FrameworkPropertyMetadata((FontFamily)new FontFamily("Segoe UI")));

        public FontFamily HeaderFontFamily
        {
            get { return (FontFamily)GetValue(HeaderFontFamilyProperty); }
            set { SetValue(HeaderFontFamilyProperty, value); }
        }

        #endregion

        #region TileColors

        public static readonly DependencyProperty TileColorsProperty =
            DependencyProperty.Register("TileColors", typeof(Brush[]), typeof(Panorama),
                new FrameworkPropertyMetadata((Brush[])null));

        public Brush[] TileColors
        {
            get { return (Brush[])GetValue(TileColorsProperty); }
            set { SetValue(TileColorsProperty, value); }
        }

        #endregion

        #region ComplimentaryTileColors

        public static readonly DependencyProperty ComplimentaryTileColorsProperty =
            DependencyProperty.Register("ComplimentaryTileColors", typeof(Brush[]), typeof(Panorama),
                new FrameworkPropertyMetadata((Brush[])null));

        public Brush[] ComplimentaryTileColors
        {
            get { return (Brush[])GetValue(ComplimentaryTileColorsProperty); }
            set { SetValue(ComplimentaryTileColorsProperty, value); }
        }

        #endregion

        #region UseSnapBackScrolling

        public static readonly DependencyProperty UseSnapBackScrollingProperty =
            DependencyProperty.Register("UseSnapBackScrolling", typeof(bool), typeof(Panorama),
                new FrameworkPropertyMetadata((bool)true));

        public bool UseSnapBackScrolling
        {
            get { return (bool)GetValue(UseSnapBackScrollingProperty); }
            set { SetValue(UseSnapBackScrollingProperty, value); }
        }

        #endregion

        #endregion

        #endregion

        #region Private Methods

        private void DoStandardScrolling()
        {
            sv.ScrollToHorizontalOffset(scrollTarget.X);
            sv.ScrollToVerticalOffset(scrollTarget.Y);
            scrollTarget.X += velocity.X;
            scrollTarget.Y += velocity.Y;
            velocity *= friction;
        }


        private void HandleWorldTimerTick(object sender, EventArgs e)
        {
            var prop = DesignerProperties.IsInDesignModeProperty;
            bool isInDesignMode = (bool)DependencyPropertyDescriptor.FromProperty(prop,
                typeof(FrameworkElement)).Metadata.DefaultValue;

            if (isInDesignMode)
                return;


            if (IsMouseCaptured)
            {
                Point currentPoint = Mouse.GetPosition(this);
                velocity = previousPoint - currentPoint;
                previousPoint = currentPoint;
            }
            else
            {
                if (velocity.Length > 1)
                {
                    DoStandardScrolling();
                }
                else
                {
                    if (UseSnapBackScrolling)
                    {
                        int mx = (int)sv.HorizontalOffset % (int)ActualWidth;
                        if (mx == 0)
                            return;
                        int ix = (int)sv.HorizontalOffset / (int)ActualWidth;
                        double snapBackX = mx > ActualWidth / 2 ? (ix + 1) * ActualWidth : ix * ActualWidth;
                        sv.ScrollToHorizontalOffset(sv.HorizontalOffset + (snapBackX - sv.HorizontalOffset) / 4.0);
                    }
                    else
                    {
                        DoStandardScrolling();
                    }
                }
            }
        }
        #endregion

        #region Overrides


        public override void OnApplyTemplate()
        {
            sv = (ScrollViewer)Template.FindName("PART_ScrollViewer", this);
            base.OnApplyTemplate();
        }


        protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (sv.IsMouseOver)
            {
                _mouseDownFlag = true;

                // Save starting point, used later when determining how much to scroll.
                scrollStartPoint = e.GetPosition(this);
                scrollStartOffset.X = sv.HorizontalOffset;
                scrollStartOffset.Y = sv.VerticalOffset;
            }

            base.OnPreviewMouseLeftButtonDown(e);
        }

        protected override void OnPreviewMouseMove(MouseEventArgs e)
        {
            if (_mouseDownFlag)
            {
                Point currentPoint = e.GetPosition(this);

                // Determine the new amount to scroll.
                Point delta = new Point(scrollStartPoint.X - currentPoint.X, scrollStartPoint.Y - currentPoint.Y);

                if (Math.Abs(delta.X) > PixelsToMoveToBeConsideredScroll ||
                    Math.Abs(delta.Y) > PixelsToMoveToBeConsideredScroll)
                {
                    scrollTarget.X = scrollStartOffset.X + delta.X;
                    scrollTarget.Y = scrollStartOffset.Y + delta.Y;

                    // Scroll to the new position.
                    sv.ScrollToHorizontalOffset(scrollTarget.X);
                    sv.ScrollToVerticalOffset(scrollTarget.Y);

                    if (!this.IsMouseCaptured)
                    {
                        if ((sv.ExtentWidth > sv.ViewportWidth) ||
                            (sv.ExtentHeight > sv.ViewportHeight))
                        {
                            _savedCursor = this.Cursor;
                            this.Cursor = Cursors.ScrollWE;
                        }

                        this.CaptureMouse();
                    }
                }
            }

            base.OnPreviewMouseMove(e);
        }

        protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            bool mouseDownFlag = _mouseDownFlag;
            // mouse move events may trigger while inside this handler.
            _mouseDownFlag = false;

            if (this.IsMouseCaptured)
            {
                // scroll action stopped
                this.Cursor = _savedCursor;
                this.ReleaseMouseCapture();
            }
            else if (mouseDownFlag)
            {
                // click action stopped
            }

            _savedCursor = null;

            base.OnPreviewMouseLeftButtonUp(e);
        }
        #endregion

    }


Panorama Group Control

public class PanoramaGroup
    {
        public PanoramaGroup(string header, ICollectionView tiles)
        {
            this.Header = header;
            this.Tiles = tiles;
        }

        public string Header { get; private set; }
        public ICollectionView Tiles { get; private set; }
    }

Group With Converter Class

 public class PanoramaGroupWidthConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            double itemBox = double.Parse(values[0].ToString());
            double groupHeight = double.Parse(values[1].ToString());

            double ratio = groupHeight / itemBox;
            ListBox list = (ListBox)values[2];


            double width = Math.Ceiling(list.Items.Count / ratio);
            width *= itemBox;
            if (width < itemBox)
                return itemBox;
            else
                return width;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Simple Commad Class

public class SimpleCommand<T1, T2> : ICommand
    {
        private Func<T1, bool> canExecuteMethod;
        private Action<T2> executeMethod;

        public SimpleCommand(Func<T1, bool> canExecuteMethod, Action<T2> executeMethod)
        {
            this.executeMethod = executeMethod;
            this.canExecuteMethod = canExecuteMethod;
        }

        public SimpleCommand(Action<T2> executeMethod)
        {
            this.executeMethod = executeMethod;
            this.canExecuteMethod = (x) => { return true; };
        }


        public bool CanExecute(T1 parameter)
        {
            if (canExecuteMethod == null) return true;
            return canExecuteMethod(parameter);
        }

        public void Execute(T2 parameter)
        {
            if (executeMethod != null)
            {
                executeMethod(parameter);
            }
        }

        public bool CanExecute(object parameter)
        {
            return CanExecute((T1)parameter);
        }

        public void Execute(object parameter)
        {
            Execute((T2)parameter);
        }

#if SILVERLIGHT
        /// <summary>
        /// Occurs when changes occur that affect whether the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged;
#else
        /// <summary>
        /// Occurs when changes occur that affect whether the command should execute.
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (canExecuteMethod != null)
                {
                    CommandManager.RequerySuggested += value;
                }
            }

            remove
            {
                if (canExecuteMethod != null)
                {
                    CommandManager.RequerySuggested -= value;
                }
            }
        }
#endif



        /// <summary>
        /// Raises the <see cref="CanExecuteChanged" /> event.
        /// </summary>
        [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",
            Justification = "The this keyword is used in the Silverlight version")]
        [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate",
            Justification = "This cannot be an event")]
        public void RaiseCanExecuteChanged()
        {
#if SILVERLIGHT
            var handler = CanExecuteChanged;
            if (handler != null)
            {
                handler(this, EventArgs.Empty);
            }
#else
            CommandManager.InvalidateRequerySuggested();
#endif
        }
    }
}

Message Box Service and Interface calsss

  public interface IMessageBoxService
    {
        void ShowMessage(string message);
    }

    public class MessageBoxService : IMessageBoxService
    {
        public void ShowMessage(string message)
        {
            MessageBox.Show(message);
        }
    }

Notification Changed Class

  #region INPC

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }

        #endregion


Main View Model Class

 public class MainWindowViewModel : INPCBase
    {
        private Random rand = new Random(DateTime.Now.Millisecond);
        private List<DummyTileData> dummyData = new List<DummyTileData>();
        private IMessageBoxService messageBoxService;



        public MainWindowViewModel(IMessageBoxService messageBoxService)
        {
            this.messageBoxService = messageBoxService;

            //create some dummy data
            dummyData.Add(new DummyTileData("Add", @"Images/Add.png"));
            dummyData.Add(new DummyTileData("Adobe", @"Images/Adobe.png"));
            dummyData.Add(new DummyTileData("Android", @"Images/Android.png"));
            dummyData.Add(new DummyTileData("Author", @"Images/Author.png"));
            dummyData.Add(new DummyTileData("Blogger", @"Images/Blogger.png"));
            dummyData.Add(new DummyTileData("Copy", @"Images/Copy.png"));
            dummyData.Add(new DummyTileData("Delete", @"Images/Delete.png"));
            dummyData.Add(new DummyTileData("Digg", @"Images/Digg.png"));
            dummyData.Add(new DummyTileData("Edit", @"Images/Edit.png"));
            dummyData.Add(new DummyTileData("Facebook", @"Images/Facebook.png"));
            dummyData.Add(new DummyTileData("GMail", @"Images/GMail.png"));
            dummyData.Add(new DummyTileData("RSS", @"Images/RSS.png"));
            dummyData.Add(new DummyTileData("Save", @"Images/Save.png"));
            dummyData.Add(new DummyTileData("Search", @"Images/Search.png"));
            dummyData.Add(new DummyTileData("Trash", @"Images/Trash.png"));
            dummyData.Add(new DummyTileData("Twitter", @"Images/Twitter.png"));
            dummyData.Add(new DummyTileData("VisualStudio", @"Images/VisualStudio.png"));
            dummyData.Add(new DummyTileData("Wordpress", @"Images/Wordpress.png"));
            dummyData.Add(new DummyTileData("Yahoo", @"Images/Yahoo.png"));
            dummyData.Add(new DummyTileData("YouTube", @"Images/YouTube.png"));

            //Great some dummy groups
            List<PanoramaGroup> data = new List<PanoramaGroup>();
            List<PanoramaTileViewModel> tiles = new List<PanoramaTileViewModel>();

            for (int i = 0; i < 4; i++)
            {
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(true));

                tiles.Add(CreateTile(true));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));

                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));

                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
                tiles.Add(CreateTile(false));
            }

            data.Add(new PanoramaGroup("Settings",
                CollectionViewSource.GetDefaultView(tiles)));

            PanoramaItems = data;

        }


        private PanoramaTileViewModel CreateTile(bool isDoubleWidth)
        {
            DummyTileData dummyTileData = dummyData[rand.Next(dummyData.Count)];
            return new PanoramaTileViewModel(messageBoxService,
                dummyTileData.Text, dummyTileData.ImageUrl, isDoubleWidth);
        }


        private IEnumerable<PanoramaGroup> panoramaItems;

        public IEnumerable<PanoramaGroup> PanoramaItems
        {
            get { return this.panoramaItems; }

            set
            {
                if (value != this.panoramaItems)
                {
                    this.panoramaItems = value;
                    NotifyPropertyChanged("CompanyName");
                }
            }
        }
    }




    public class DummyTileData
    {
        public string Text { get; private set; }
        public string ImageUrl { get; private set; }

        public DummyTileData(string text, string imageUrl)
        {
            this.Text = text;
            this.ImageUrl = imageUrl;
        }
    }


Panorama Tile View Model Class

public class PanoramaTileViewModel : INPCBase
    {
        private IMessageBoxService messageBoxService;
        private Timer liveUpdateTileTimer = new Timer();

        public PanoramaTileViewModel(IMessageBoxService messageBoxService, string text, string imageUrl, bool isDoubleWidth)
        {
            if (isDoubleWidth)
            {
                liveUpdateTileTimer.Interval = 1000;
                liveUpdateTileTimer.Elapsed += new ElapsedEventHandler(LiveUpdateTileTimer_Elapsed);
                liveUpdateTileTimer.Start();
            }


            this.messageBoxService = messageBoxService;
            this.Text = text;
            this.ImageUrl = imageUrl;
            this.IsDoubleWidth = isDoubleWidth;
            this.TileClickedCommand = new SimpleCommand<object, object>(ExecuteTileClickedCommand);
        }

        void LiveUpdateTileTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (Counter < 10)
                Counter++;
            else
                Counter = 0;
            NotifyPropertyChanged("Counter");
        }

        public int Counter { get; set; }
        public string Text { get; private set; }
        public string ImageUrl { get; private set; }
        public bool IsDoubleWidth { get; private set; }
        public ICommand TileClickedCommand { get; private set; }

        public void ExecuteTileClickedCommand(object parameter)
        {
            messageBoxService.ShowMessage(string.Format("you clicked {0}", this.Text));
        }
    }