求 wpf 仿 win8 磁贴例子
想做一个win磁贴界面,但wpf还未入门。求实例,求带!
设计方案:整个界面主要分为两块:MetroStyle和MetroButton
MetroStyle设计如下:
MetroButton设计如下:
MetroButton的主要功能是显而易见的,其中主要实现了三个依赖属性:MetroBtnForeImage(绑定Image)、MetroBtnText(绑定Text)、MetroBtnUri(点击MetroButton后跳转Uri)。
实现
MetroButton的制作上参考了烤地瓜的系列教程中ImageButton的制作,只是在其基础上添加了需要的依赖属性和动画。
布局代码:(样式代码太多就不贴了)
<grid Name="layout" RenderTransformOrigin="0.5,0.5" >
</grid><grid .RenderTransform>
<transformgroup>
<scaletransform></scaletransform>
<skewtransform></skewtransform>
<rotatetransform></rotatetransform>
<translatetransform></translatetransform>
</transformgroup>
</grid>
<button x:Name="btnMetro"
HorizontalAlignment="Center"
Style="{DynamicResource MetroButtonStyle}"
VerticalAlignment="Center"
Tag="{Binding MetroBtnText, ElementName=UserControl}" >
<image Name="ForeImage"
Source="{Binding MetroBtnForeImage, ElementName=UserControl}"
Stretch="Fill" Width="140" Height="140"
HorizontalAlignment="Center"
VerticalAlignment="Center"></image>
</button>
依赖属性定义:
/// <summary>
/// MetroButton.xaml 的交互逻辑
/// </summary>
public partial class MetroButton : UserControl
{
public MetroButton()
{
this.InitializeComponent();
}
//按钮前景图
public static readonly DependencyProperty MetroBtnForeImageProperty;
//按钮文字
public static readonly DependencyProperty MetroBtnTextProperty;
//按钮绑定页面uri
public static readonly DependencyProperty MetroBtnUriProperty;
public ImageSource MetroBtnForeImage
{
get { return (ImageSource)GetValue(MetroBtnForeImageProperty); }
set { SetValue(MetroBtnForeImageProperty, value); }
}
public string MetroBtnUri
{
get { return (string)GetValue(MetroBtnUriProperty); }
set { SetValue(MetroBtnUriProperty, value); }
}
public string MetroBtnText
{
get { return (string)GetValue(MetroBtnTextProperty); }
set { SetValue(MetroBtnTextProperty, value); }
}
static MetroButton()
{
var metadataImage = new FrameworkPropertyMetadata((ImageSource)null);
var metadataText = new FrameworkPropertyMetadata((string)null);
var metadataUri = new FrameworkPropertyMetadata((string)null);
MetroBtnForeImageProperty = DependencyProperty.RegisterAttached("MetroBtnForeImage", typeof(ImageSource), typeof(MetroButton), metadataImage);
MetroBtnTextProperty = DependencyProperty.RegisterAttached("MetroBtnText", typeof(string), typeof(MetroButton), metadataText);
MetroBtnUriProperty = DependencyProperty.RegisterAttached("MetroBtnUri", typeof(string), typeof(MetroButton), metadataUri);
}
}
MetroStyle中主要分为了2块:界面布局和页面跳转动画。
界面布局:(主要做的是针对1366*768分辨率的屏幕做的,如果需要适应各种分辨率还需修改)
<s:surfacescrollviewer x:Name="GridScrollViewer"
VerticalAlignment="Top"
HorizontalAlignment="Left"
Width="1366" Height="768"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Disabled"
PanningMode="HorizontalOnly">
<grid x:Name="OptionGrid" RenderTransformOrigin="0.5,0.5"
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="768" Width="auto" Background="#00000000" OpacityMask="Black" >
</grid><grid .RowDefinitions >
<rowdefinition Height="180"></rowdefinition>
<rowdefinition Height="152"></rowdefinition>
<rowdefinition Height="152"></rowdefinition>
<rowdefinition Height="152"></rowdefinition>
<rowdefinition Height="136"></rowdefinition>
</grid>
<grid .ColumnDefinitions >
<columndefinition Width="100"></columndefinition>
<columndefinition Width="152"></columndefinition>
</grid>
<textblock Text="开始" HorizontalAlignment="Center"
VerticalAlignment="Center" Grid.Column="1" Grid.Row="0"
FontSize="64" Foreground="White"></textblock>
</s:surfacescrollviewer>
跳转动画(布局):
<metro:loadanimationcontrol x:Name="LoadControl"
Width="1366" Height="768" Visibility="Hidden">
<grid x:Name="LayoutRoot" RenderTransformOrigin="0.5,0.5">
</grid><grid .RenderTransform>
<transformgroup>
<scaletransform></scaletransform>
<skewtransform></skewtransform>
<rotatetransform></rotatetransform>
<translatetransform></translatetransform>
</transformgroup>
</grid>
<rectangle Name="rectangle" Fill="#FF20B1C4"
Stroke="Transparent" Width="480" Height="270">
</rectangle><rectangle .RenderTransform>
<transformgroup>
<scaletransform></scaletransform>
<skewtransform></skewtransform>
<rotatetransform></rotatetransform>
<translatetransform></translatetransform>
</transformgroup>
</rectangle>
<stackpanel Width="auto" Height="auto"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<image Name="ForwardImage" HorizontalAlignment="Center"
Height="206.4" Stretch="Fill" VerticalAlignment="Center" Width="215"></image>
</stackpanel>
</metro:loadanimationcontrol>
跳转动画(动画):
<storyboard x:Key="LoadAnimation" Completed="sb_Completed">
<pointanimationusingkeyframes Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)"
Storyboard.TargetName="rectangle">
<easingpointkeyframe KeyTime="0" Value="0.5,0.5"></easingpointkeyframe>
<easingpointkeyframe KeyTime="0:0:0.3" Value="0.5,0.5"></easingpointkeyframe>
</pointanimationusingkeyframes>
<doubleanimationusingkeyframes Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetName="rectangle">
<easingdoublekeyframe KeyTime="0:0:0.3" Value="2.90"></easingdoublekeyframe>
</doubleanimationusingkeyframes>
<doubleanimationusingkeyframes Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
Storyboard.TargetName="rectangle">
<easingdoublekeyframe KeyTime="0:0:0.3" Value="2.90"></easingdoublekeyframe>
</doubleanimationusingkeyframes>
<doubleanimationusingkeyframes Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetName="rectangle">
<easingdoublekeyframe KeyTime="0:0:0.6" Value="2.90"></easingdoublekeyframe>
</doubleanimationusingkeyframes>
<doubleanimationusingkeyframes Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"
Storyboard.TargetName="rectangle">
<easingdoublekeyframe KeyTime="0:0:0.6" Value="2.90"></easingdoublekeyframe>
</doubleanimationusingkeyframes>
<doubleanimationusingkeyframes Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"
Storyboard.TargetName="LayoutRoot">
<easingdoublekeyframe KeyTime="0" Value="-1">
</easingdoublekeyframe><easingdoublekeyframe .EasingFunction>
<cubicease EasingMode="EaseOut"></cubicease>
</easingdoublekeyframe>
<easingdoublekeyframe KeyTime="0:0:0.3" Value="1">
</easingdoublekeyframe><easingdoublekeyframe .EasingFunction>
<cubicease EasingMode="EaseOut"></cubicease>
</easingdoublekeyframe>
</doubleanimationusingkeyframes>
</storyboard>
跳转动画的实现主要是对一个Rectangle进行翻转并放大,且将MetroButton中的图片置于页面中心,动画播放完后触发Completed事件,执行跳转。
界面布局动态加载MetroButton的实现:
我在项目中添加了两个文件夹:View和Image。Image用于保存页面图标,而View中则保存着相应的页面文件,并且二者中的文件通过文件名一一对应(如:View/v1/Mail.xaml代表着一个页面,相应的在Image/v1下,应存在一个名为Mail.png或Mail.jpg等类型的文件与之对应),在这两个文件夹中还存在子文件夹,在界面加载时,每一个文件夹体现为一个块。
/// <summary>
/// MetroStyle.xaml 的交互逻辑
/// </summary>
public partial class MetroStyle : Page
{
private string uri;
DirectoryInfo app = null;//页面目录 默认为Application/view
DirectoryInfo img = null;//页面图标目录 默认为Application/Image
string env;
public MetroStyle()
{
this.InitializeComponent();
env = Environment.CurrentDirectory.Replace("\\bin\\Debug", "");//获取程序根目录
LoadAllApp();
}
/// <summary>
/// 在主页面加载页面图标
/// </summary>
public void LoadAllApp()
{
defineGrid();
int row = 1;
int column = 1;
int index = 0;
img = new DirectoryInfo(env + "\\Image");
for (int i = 0; i < img.GetDirectories().Length; i++)
{
index = 0;
for (int j = 0; j < app.GetDirectories()[i].GetFiles().Length; j++)
{
string tmpex = app.GetDirectories()[i].GetFiles()[j].Extension;
if (tmpex.Contains("xaml"))
{
if (row > 3 && j >0)
column += 1;
if (row > 3 || j == 0)
{
row = 1;
}
MetroButton mb = new MetroButton();
//设置页面uri
mb.MetroBtnUri = app.GetDirectories()[i].Name + "\\" + app.GetDirectories()[i].GetFiles()[j].Name;
//设置图片
mb.MetroBtnForeImage = (ImageSource)new ImageSourceConverter().ConvertFromString(img.GetDirectories()[i].GetFiles()[index].FullName);
//设置文字
mb.MetroBtnText = img.GetDirectories()[i].GetFiles()[index].Name.Split('.')[0];
mb.SetValue(Grid.RowProperty, row);
mb.SetValue(Grid.ColumnProperty, column);
//添加点击事件
mb.PreviewMouseLeftButtonUp += MetroButton_MouseLeftButtonUp;
this.OptionGrid.Children.Add(mb);
row++;
index++;
}
}
column += 2;
}
}
/// <summary>
/// 计算Grid大小
/// </summary>
public void defineGrid()
{
app = new DirectoryInfo(env + "\\view");
int sumOfApp = 0;
int sumOfPart = app.GetDirectories().Length;
int tmp = 0;
foreach (DirectoryInfo di in app.GetDirectories())
{
sumOfApp = di.GetFiles().Length;
int numOfColunm = sumOfApp /2 / 3 + (sumOfApp % 3 > 0 ? 1 : 0);
if (tmp == 0)
numOfColunm -= 1;
for (int i = 0; i < numOfColunm; i++)
{
ColumnDefinition appColumn = new ColumnDefinition();
appColumn.Width = new GridLength(152);
this.OptionGrid.ColumnDefinitions.Add(appColumn);
}
ColumnDefinition spanColumn = new ColumnDefinition();
spanColumn.Width = new GridLength(50);
this.OptionGrid.ColumnDefinitions.Add(spanColumn);
tmp++;
}
}
/// <summary>
/// /点击MetroButton事件
///
/// <param name="sender"/>
/// <param name="e"/>
private void MetroButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
uri = (sender as MetroButton).MetroBtnUri;
this.ForwardImage.Source = (sender as MetroButton).MetroBtnForeImage;
SolidColorBrush rbrg = new SolidColorBrush(getBackgroudColor(this.ForwardImage));
this.rectangle.Fill = rbrg;
this.LoadControl.Visibility = Visibility.Visible;
Storyboard sb = (Storyboard)this.FindResource("LoadAnimation");
sb.Begin();
}
/// <summary>
/// 获取图标的背景颜色
/// </summary>
/// <param name="img"/>
/// <returns></returns>
public System.Windows.Media.Color getBackgroudColor(System.Windows.Controls.Image img)
{
string path = img.Source.ToString().Replace("file:///","");
Bitmap bmp = new Bitmap(path);
byte a = bmp.GetPixel(1, 1).A;
byte r = bmp.GetPixel(1, 1).R;
byte g = bmp.GetPixel(1, 1).G;
byte b = bmp.GetPixel(1, 1).B;
System.Windows.Media.Color color = System.Windows.Media.Color.FromArgb(a, r, g, b);
return color;
}
/// <summary>
/// /动画完成后执行跳转
/// </summary>
/// <param name="sender"/>
/// <param name="e"/>
private void sb_Completed(object sender, EventArgs e)
{
NavigationService.Navigate(new Uri(@"view\"+uri, UriKind.Relative));
}
}