ListBox是一个很有用的控件,其功能直逼Asp.Net中的Repeater,它能实现自定义数据项模板,纵向/横向排列Item(如果扩展一下实现自行折行,几乎就是SL版的Repeater了--实际上WrapPanel已经实现了,不过没有默认集成在SL3中).
这里推荐一个老外的文章 http://blogs.msdn.com/delay/archive/2008/03/05/lb-sv-faq-examples-notes-tips-and-more-for-silverlight-2-beta-1-s-listbox-and-scrollviewer-controls.aspx 基本上ListBox的各种用法和注意点都在里面了(E文的,只看代码就行了)
另外关于Style,这个东西刚开始学习时,还以为自己能靠死记硬背掌握绝大多数控件的模板,后来发现这是徒劳!每个控件的默认样式/模板,都有N长,全凭记忆不太现实,我的经验是如果需要定义某一个控件的样式,直接用Blend先编辑副本,得到完整的"样本",然后在此基础上做些修改或删减,这样更可行。
Xaml中的资源是个很庞大的概念:样式,模板,动画,触发器,甚至数据集(引用)...都可以称之为Resource.这一点与web开发中的css完全不同。
在学习Style的过程中,经常会遇到另外一个概念:模板(Template),初期经常被他们搞混淆,其实这二者有明显的区别:Style影响外观,而Template影响内容,它们之间通过绑定联系起来(它们之间的联系也可以这样理解:如果不进行数据绑定,即使定义了模板,最终也不会有内容,既然连内容都没有了,所以也谈不上外观--即所谓的数据驱动UI)
这里举一个ListBox的例子:
xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x ="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class ="ListBoxSilde.UserControl1" >
< UserControl.Resources >
<!-- 整体样式 -->
< Style x:Key ="ListStyle" TargetType ="ListBox" >
< Setter Property ="Padding" Value ="1" />
< Setter Property ="Margin" Value ="0" />
< Setter Property ="BorderThickness" Value ="0" />
< Setter Property ="Background" Value =" {x:Null} " />
</ Style >
<!-- 排列布局(横向) -->
< ItemsPanelTemplate x:Key ="HorizontalItemPanel" >
< StackPanel Orientation ="Horizontal" />
</ ItemsPanelTemplate >
<!-- 数据项模板(内容) -->
< DataTemplate x:Key ="DataTemplate" >
< TextBlock Text =" {Binding Index} " Padding ="0" Margin ="2" ></ TextBlock >
</ DataTemplate >
<!-- 数据项样式(外观) -->
< Style x:Key ="ItemStyle" TargetType ="ListBoxItem" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate >
< Grid Cursor ="Hand" >
< VisualStateManager.VisualStateGroups >
< VisualStateGroup x:Name ="SelectionStates" >
< VisualState x:Name ="Unselected" />
< VisualState x:Name ="Selected" >
< Storyboard >
< DoubleAnimationUsingKeyFrames Storyboard.TargetName ="fillColor2" Storyboard.TargetProperty ="Opacity" >
< SplineDoubleKeyFrame KeyTime ="0" Value ="0.75" />
</ DoubleAnimationUsingKeyFrames >
</ Storyboard >
</ VisualState >
</ VisualStateGroup >
</ VisualStateManager.VisualStateGroups >
< Rectangle Fill ="#99FFFFFF" IsHitTestVisible ="False" Margin ="1" />
< Rectangle x:Name ="fillColor2" Fill ="#FFBADDE9" RadiusX ="0" RadiusY ="0" IsHitTestVisible ="False" Opacity ="0" Margin ="1" />
< ContentPresenter x:Name ="contentPresenter" Content =" {TemplateBinding Content} " Margin ="2" />
</ Grid >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
</ UserControl.Resources >
< StackPanel Background ="DarkBlue" >
< ListBox x:Name ="lst" HorizontalAlignment ="Center" VerticalAlignment ="Center" Style =" {StaticResource ListStyle} " ItemsPanel =" {StaticResource HorizontalItemPanel} " ItemTemplate =" {StaticResource DataTemplate} " ItemContainerStyle =" {StaticResource ItemStyle} " >
</ ListBox >
</ StackPanel >
</ UserControl >
这段代码中,ListBox本身空空如也(除了几个样式和模板的应用),最终的呈现内容和外观,全部在UserControl.Resource中定义了,运行后界面肯定是空的,因为没有数据绑定,我们给它加上后端代码:
using System.Reflection;
using System.Collections.Generic;
namespace ListBoxSilde
{
public partial class UserControl1 : UserControl
{
Test t;
public UserControl1()
{
InitializeComponent();
List < Test > lst = new List < Test > (){
new Test(){ Index = " 1 " },
new Test(){ Index = " 2 " },
new Test(){ Index = " 3 " },
new Test(){ Index = " 4 " },
new Test(){ Index = " 5 " }
};
this .lst.ItemsSource = lst;
}
}
public class Test { public string Index { set ; get ; } }
}
运行后的样子类似这样:
下面这个效果是很多网站都有的图片广告轮换,当然实现办法有N多,这里我用Style结合ListBox弄了一个:
大致思路:用style定义ListBox的ItemsPanel,把默认纵向排列改成横向排列,然后结合Clip属性设置可视区(蒙板),让其左右移动即可。
xaml代码:
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" x:Class ="ListBoxSilde.MainPage"
d:DesignWidth ="640" d:DesignHeight ="480" >
< UserControl.Resources >
<!-- 整体样式 -->
< Style x:Key ="ListStyle" TargetType ="ListBox" >
< Setter Property ="Padding" Value ="1" />
< Setter Property ="Margin" Value ="0" />
< Setter Property ="BorderThickness" Value ="0" />
< Setter Property ="Background" Value =" {x:Null} " />
</ Style >
<!-- 排列布局(横向) -->
< ItemsPanelTemplate x:Key ="HorizontalItemPanel" >
< StackPanel Orientation ="Horizontal" />
</ ItemsPanelTemplate >
<!-- 导航区-数据项模板(内容) -->
< DataTemplate x:Key ="NavDataTemplate" >
< StackPanel MouseLeftButtonDown ="NavItemClick" Background ="#00000000" >
< TextBlock Text =" {Binding Index} " Padding ="0" Margin ="2,0" ></ TextBlock >
</ StackPanel >
</ DataTemplate >
<!-- 导航区-数据项样式(外观) -->
< Style x:Key ="NavItemStyle" TargetType ="ListBoxItem" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate >
< Grid Cursor ="Hand" >
< VisualStateManager.VisualStateGroups >
< VisualStateGroup x:Name ="SelectionStates" >
< VisualState x:Name ="Unselected" />
< VisualState x:Name ="Selected" >
< Storyboard >
< DoubleAnimationUsingKeyFrames Storyboard.TargetName ="fillColor2" Storyboard.TargetProperty ="Opacity" >
< SplineDoubleKeyFrame KeyTime ="0" Value ="0.85" />
</ DoubleAnimationUsingKeyFrames >
</ Storyboard >
</ VisualState >
</ VisualStateGroup >
</ VisualStateManager.VisualStateGroups >
< Rectangle Fill ="#99FFFFFF" IsHitTestVisible ="False" Margin ="1" />
< Rectangle x:Name ="fillColor2" Fill ="#FFBADDE9" RadiusX ="0" RadiusY ="0" IsHitTestVisible ="False" Opacity ="0" Margin ="1" />
< ContentPresenter x:Name ="contentPresenter" Content =" {TemplateBinding Content} " Margin ="2" />
</ Grid >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
<!-- 图片区-数据项模板 -->
< DataTemplate x:Key ="ImageDataTemplate" >
< Image Margin ="0" Source =" {Binding ImageUri} " Stretch ="UniformToFill" Height ="300.0" Width ="480.0" ToolTipService.ToolTip =" {Binding Title} " Cursor ="Hand" MouseLeftButtonDown ="Image_MouseLeftButtonDown" x:Name =" {Binding Index} " />
</ DataTemplate >
<!-- 图片区-数据项外观 -->
< Style x:Key ="ImageItemStyle" TargetType ="ListBoxItem" >
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate >
< ContentPresenter x:Name ="contentPresenter" Content =" {TemplateBinding Content} " Margin ="0" />
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
<!-- 动画 -->
< Storyboard x:Name ="sbMove" >
< DoubleAnimationUsingKeyFrames BeginTime ="00:00:00" Storyboard.TargetName ="lstImage" Storyboard.TargetProperty ="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" >
< EasingDoubleKeyFrame KeyTime ="00:00:00.5000000" Value ="-481" x:Name ="kTo" >
< EasingDoubleKeyFrame.EasingFunction >
< BackEase EasingMode ="EaseInOut" Amplitude ="0.5" />
</ EasingDoubleKeyFrame.EasingFunction >
</ EasingDoubleKeyFrame >
</ DoubleAnimationUsingKeyFrames >
</ Storyboard >
</ UserControl.Resources >
< Grid x:Name ="LayoutRoot" ShowGridLines ="True" Height ="300" Width ="480" MouseEnter ="LayoutRoot_MouseEnter" MouseLeave ="LayoutRoot_MouseLeave" >
< Grid.Clip >
< RectangleGeometry Rect ="0,0,480,300" />
</ Grid.Clip >
< Canvas >
< ListBox x:Name ="lstImage" Style =" {StaticResource ListStyle} " ItemsPanel =" {StaticResource HorizontalItemPanel} " ItemContainerStyle =" {StaticResource ImageItemStyle} " ItemTemplate =" {StaticResource ImageDataTemplate} " RenderTransformOrigin ="0.5,0.5" Padding ="0" >
< ListBox.RenderTransform >
< TransformGroup >
< ScaleTransform />
< SkewTransform />
< RotateTransform />
< TranslateTransform />
</ TransformGroup >
</ ListBox.RenderTransform >
</ ListBox >
</ Canvas >
< ListBox Style =" {StaticResource ListStyle} " ItemsPanel =" {StaticResource HorizontalItemPanel} " ItemContainerStyle =" {StaticResource NavItemStyle} " ItemTemplate =" {StaticResource NavDataTemplate} " HorizontalAlignment ="Right" VerticalAlignment ="Bottom" x:Name ="lstNav" />
< TextBlock x:Name ="txtDebug" HorizontalAlignment ="Left" VerticalAlignment ="Top" Foreground ="White" Text ="by 菩提树下的杨过" Margin ="3,3,0,0" Cursor ="Hand" MouseLeftButtonDown ="txtDebug_MouseLeftButtonDown" />
</ Grid >
</ UserControl >
后端代码:
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Threading;
using System.Windows.Shapes;
namespace ListBoxSilde
{
public partial class MainPage : UserControl
{
ObservableCollection < ImageItem > _Items;
int _CurrentIndex = 0 ; // 当前索引号(从0开始)
DispatcherTimer _timer;
public MainPage()
{
InitializeComponent();
this .Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded( object sender, RoutedEventArgs e)
{
string _ArremblyName = Assembly.GetExecutingAssembly().FullName.Split( ' , ' )[ 0 ];
_Items = new ObservableCollection < ImageItem > ();
for ( int i = 1 ; i <= 4 ; i ++ )
{
string _img = " http://images.24city.com/jimmy/ListBoxSlideShow/img/00 " + i.ToString() + " .jpg " ;
_Items.Add( new ImageItem() { ImageUri = _img, Title = " 这是图片00 " + i.ToString() + " .jpg " , ClickUri = _img, Index = i });
}
this .lstImage.ItemsSource = _Items;
this .lstNav.ItemsSource = _Items;
this .lstNav.SelectedIndex = _CurrentIndex;
_timer = new DispatcherTimer();
_timer.Interval = new System.TimeSpan( 0 , 0 , 2 );
_timer.Tick += new System.EventHandler(_timer_Tick);
_timer.Start();
}
void _timer_Tick( object sender, System.EventArgs e)
{
kTo.Value = _CurrentIndex * - 480 ;
sbMove.Begin();
lstNav.SelectedIndex = _CurrentIndex;
_CurrentIndex ++ ;
if (_CurrentIndex >= _Items.Count)
{
_CurrentIndex = 0 ;
}
}
private void LayoutRoot_MouseEnter( object sender, System.Windows.Input.MouseEventArgs e)
{
_timer.Stop();
}
private void LayoutRoot_MouseLeave( object sender, System.Windows.Input.MouseEventArgs e)
{
_timer.Start();
}
private void Image_MouseLeftButtonDown( object sender, System.Windows.Input.MouseButtonEventArgs e)
{
HtmlPage.Window.Navigate( new Uri(_Items[ this .lstNav.SelectedIndex].ClickUri), " _target " );
}
private void txtDebug_MouseLeftButtonDown( object sender, System.Windows.Input.MouseButtonEventArgs e)
{
HtmlPage.Window.Navigate( new Uri( " http://yjmyzz.cnblogs.com/ " ), " _target " );
}
private void NavItemClick( object sender, System.Windows.Input.MouseButtonEventArgs e)
{
StackPanel g = (sender as StackPanel);
TextBlock txt = g.Children[ 0 ] as TextBlock;
int Index = int .Parse(txt.Text);
kTo.Value = (Index - 1 ) * - 480 ;
sbMove.Begin();
_CurrentIndex = Index - 1 ;
lstNav.SelectedIndex = _CurrentIndex;
}
}
public class ImageItem
{
public string ImageUri { set ; get ; }
public string Title { set ; get ; }
public string ClickUri { set ; get ; }
public int Index { set ; get ; }
}
}