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));
}
}
No comments:
Post a Comment