用LongListSelector代替ListBox

摘要:用LongListSelector代替ListBox

若想要呈現一大筆資料的時候,想必大家應該是用ListBox來輸出吧,如果是想要做到拉到最底或是最頂端更新的話,要修改一些東西才能達到效果,若還要移動到指定的項目的話,這又要寫一堆有的沒的,拋棄它吧,來用更好用的LongListSelector!

 

這個控件是SilverLightToolkit裡的一員,不過Windows Phone 8也內建此控件了,且是像聯絡人那樣子的,連動畫都幫你做好了!這可真是德政啊!不過我現在要介紹的是在Windows Phone 7.5裡用的,8的以後再介紹,其實沒差很多就是。

 

不過有些準備工作是要先完成的,首先要先下載SilverLight Toolkit的原始碼回來編譯,因為雖然LongListSelector裡面有留StrechingTopStrechingBottom,以及StrechingCompleted,但是拿來使用的時候卻一點反應都沒有,看了一下原始碼,原來雖然有放,但是卻沒有去實作就是,所以這邊就要我們自己去處理了。

 

先打開SilverLight Toolkit的專案,然後再打開LongListSelector/LongListSelector.cs,首先先找到public override void OnApplyTemplate(),下面這段


FrameworkElement element = VisualTreeHelper.GetChild(sv, 0) as FrameworkElement;
if (element != null)
{
	_scrollGroup = VisualStates.TryGetVisualStateGroup(sv, ScrollStatesGroupName);
	if (_scrollGroup != null)
	{
		_scrollGroup.CurrentStateChanging += OnScrollStateChanging;
	}

	_verticalCompressionGroup = VisualStates.TryGetVisualStateGroup(sv, VerticalCompressionStateName);
	if (_verticalCompressionGroup != null)
	{
		_verticalCompressionGroup.CurrentStateChanging += OnStretchStateChanging;
	}
}

改成


FrameworkElement element = VisualTreeHelper.GetChild(sv, 0) as FrameworkElement;
if (element != null)
{
	_scrollGroup = VisualStates.TryGetVisualStateGroup(sv, "ScrollStates");
	if (_scrollGroup != null)
	{
		_scrollGroup.CurrentStateChanging += OnScrollStateChanging;
	}

	var verticalGroup = VisualStates.TryGetVisualStateGroup(sv, "VerticalCompression");
	if (verticalGroup != null)
	{
		verticalGroup.CurrentStateChanging += OnScrollStateChanging;
	}
}

然後再找到private void OnScrollStateChanging(object sender, VisualStateChangedEventArgs e)內容改成


IsScrolling = e.NewState.Name == ScrollingState;

if (e.NewState.Name == ScrollingState && ScrollingStarted != null)
{
	ScrollingStarted(this, null);
}
else if (e.NewState.Name == NotScrollingState && ScrollingCompleted != null)
{
	ScrollingCompleted(this, null);
}
else if (e.NewState.Name == CompressionTop && StretchingTop != null)
{
	StretchingTop(this, null);
}
else if (e.NewState.Name == CompressionBottom && StretchingBottom != null)
{
	StretchingBottom(this, null);
}
else if (e.NewState.Name == NoVerticalCompression && StretchingCompleted != null)
{
	StretchingCompleted(this, null);
}

改完再編譯,這樣準備工作就完成啦,接下來就可以用到你自己的專案了,這裡先做個簡單範例,首先當然是先引用你剛剛完成的Microsoft.Phone.Controls.Toolkit.dll,然後在xaml檔裡放入


<toolkit:LongListSelector x:Name="testLongListSelector" IsFlatList="True" Margin="0,0,0,106">
                
	<toolkit:LongListSelector.ItemTemplate>
		<DataTemplate>
			<StackPanel Background="Red" Margin="10">
				<TextBlock Text="{Binding Name}" FontSize="28" HorizontalAlignment="Left" />
				<TextBlock Text="{Binding Phone}" FontSize="28" HorizontalAlignment="Left" />
			</StackPanel>
		</DataTemplate>
	</toolkit:LongListSelector.ItemTemplate>
	
</toolkit:LongListSelector>

IsFlatList記得設成True,這樣行為才會像一般的ListBox,接下來要設定Resource,在空白處加入這段


<phone:PhoneApplicationPage.Resources>

<Style TargetType="ScrollViewer">
            <Setter Property="VerticalScrollBarVisibility" Value="Auto"/>
            <Setter Property="HorizontalScrollBarVisibility" Value="Auto"/>
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Padding" Value="0"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ScrollViewer">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="ScrollStates">
                                    <VisualStateGroup.Transitions>
                                        <VisualTransition GeneratedDuration="00:00:00.5"/>
                                    </VisualStateGroup.Transitions>
                                    <VisualState x:Name="Scrolling">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="VerticalScrollBar"
                                            Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
                                            <DoubleAnimation Storyboard.TargetName="HorizontalScrollBar"
                                            Storyboard.TargetProperty="Opacity" To="1" Duration="0"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="NotScrolling">
                                    </VisualState>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="VerticalCompression">
                                    <VisualState x:Name="NoVerticalCompression"/>
                                    <VisualState x:Name="CompressionTop"/>
                                    <VisualState x:Name="CompressionBottom"/>
                                    <VisualState x:Name="StretchingTop"/>
                                    <VisualState x:Name="StretchingBottom"/>
                                </VisualStateGroup>
                                <VisualStateGroup x:Name="HorizontalCompression">
                                    <VisualState x:Name="NoHorizontalCompression"/>
                                    <VisualState x:Name="CompressionLeft"/>
                                    <VisualState x:Name="CompressionRight"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Grid Margin="{TemplateBinding Padding}">
                                <ScrollContentPresenter x:Name="ScrollContentPresenter" Content="{TemplateBinding Content}"
                                ContentTemplate="{TemplateBinding ContentTemplate}"/>
                                <ScrollBar x:Name="VerticalScrollBar" IsHitTestVisible="False" Height="Auto" Width="5"
                                HorizontalAlignment="Right" VerticalAlignment="Stretch" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}"
                                IsTabStop="False" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Value="{TemplateBinding VerticalOffset}"
                                Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}" />
                                <ScrollBar x:Name="HorizontalScrollBar" IsHitTestVisible="False" Width="Auto" Height="5"
                                HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}"
                                IsTabStop="False" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Value="{TemplateBinding HorizontalOffset}"
                                Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" />
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
		
</phone:PhoneApplicationPage.Resources>

這邊主要是設定ScrollView的Style,接下來到程式碼裡面,加入


public class CTest
{
	public string Name { get; set; }
	public string Phone { get; set; }
}

private void test()
{
	List listTest = new List();
	listTest.Add(new CTest { Name = "01", Phone = "12345" });
	listTest.Add(new CTest { Name = "02", Phone = "12345" });
	listTest.Add(new CTest { Name = "03", Phone = "12345" });
	listTest.Add(new CTest { Name = "04", Phone = "12345" });
	listTest.Add(new CTest { Name = "05", Phone = "12345" });
	listTest.Add(new CTest { Name = "06", Phone = "12345" });
	listTest.Add(new CTest { Name = "07", Phone = "12345" });
	listTest.Add(new CTest { Name = "08", Phone = "12345" });
	listTest.Add(new CTest { Name = "09", Phone = "12345" });

	this.testLongListSelector.ItemsSource = listTest;
}

然後在頁面建構式裡面跑test(),就會看到畫面了,看起來是不是跟一般的ListBox一樣呢!然後如果我們要加上拉到最底更新或拉到最上更新,就可以利用這三個事件來達成目的


this.testLongListSelector.StretchingBottom += new EventHandler(testLong_StretchingBottom);
void testLong_StretchingBottom(object sender, EventArgs e)
{
	MessageBox.Show("Bottom");
}

this.testLongListSelector.StretchingCompleted += new EventHandler(testLong_StretchingCompleted);
void testLong_StretchingCompleted(object sender, EventArgs e)
{
	MessageBox.Show("Finished");
}

this.testLongListSelector.StretchingTop += new EventHandler(testLong_StretchingTop);
void testLong_StretchingTop(object sender, EventArgs e)
{
	MessageBox.Show("Top");
}

例如拉到最上更新的話,我們可以在使用者拉到最上的時候,也就是會跑StretchingTop這邊放個判斷說使用者拉到最上,然後當使用者放開的時候,也就是會跑StretchingCompleted這邊來計時說拉到最上幾秒才要更新,這樣就可以達到需求了。如果你還想要讓畫面滑到你想指定的項目的話,可以使用ScrollTo(object item)來達成喔。

 

大概就是這個樣子,之後再寫一篇有關Windows Phone 8的LongListSelector的介紹吧!