[Silverlight]學習筆記-製作可收合的功能選單(使用TabControl)
最近正在學習使用Silverlight,前陣子剛好看到Ouch兄這篇 [Silverlight]利用圖釘做出可以收合、開啟的面版 的教學,原來使用Silverlight就可輕鬆達成面版的收合,之前處理收合面版都得透過Java Script。
一般傳統的 Web 功能選單有不少是使用TreeView搭配Frame框架來使用,此例我是用 TabControl 來製作功能選單。
首先來設計前端的頁面及面版收合的動作 (可先參考Ouch兄的那篇教學)
1.使用 Expression Blend 4 開啟一個新專案,這裡使用的專案類型為 Silverlight應用程式+網站 。
2.放入一個Border控制項物件到LayoutRoot裡。
Border物件的細部XAML設定如下:
3.放入一個TabControl控制項到Border裡。
設定 TabControl 一般屬性下的 TabStripPlacement 屬性為 Right ,以便將 TabItem 置於 TabControl 的右方。
預設的TabControl有二個TabItem,刪除其中一個TabItem,只須留下一個TabItem。
保留下來的這個TabItem將會用來收合面版使用,其它的 TabItem 選單則於執行時期交由程式動態產生。
TabControl物件的細部XAML設定如下:
此處因要將 TabItem.Header 旋轉90度置放,所以包了一個TextBlock在TabItem.Header裡,以便透過 TextBlock.RenderTransform 設定Rotation=90。
4.接下來開始準備設計面版收合、展開的動畫。
切換到狀態頁籤,新增一個狀態群組,並將其名稱改為 LeftPanelStateGroup 。
在剛新增的 LeftPanelStateGroup 狀態群組中,新增二個狀態。
再將第一個狀態改名為 ShowLeftPanel (拿來當開啟面版的狀態),另一個狀態則改名為 HideLeftPanel (拿來當收合面版的狀態)。
接著設定狀態切換的動畫為 Bounce Out 。
並將切換動畫的持續時間設為 1 s (1秒)。
接著使用RenderTransform的 X 軸位移來設定面版隱藏狀態。
先選擇左側的 HideLeftPanel 狀態以及 Border 物件,設定其 RenderTransform 的 X 軸屬性的平移值為 –170,將Border物件移出至視窗左方,只保留一些空間讓 TabItem 得以顯示。。
點選工作區上方 HideLeftPanel 狀態 錄製已開啟 前的紅色圖示關閉錄製。
5.幫TabControl加上變更狀態的 GoToStateAction 行為,以用來切換狀態。
切換到資產頁籤,找到行為(Behaviors)底下的GoToStateAction,分別各拖曳一個GoToStateAction到TabControl 及TabItem 物件底下。
設定 TabControl 底下的 GoToStateAction 屬性如下,由 TabControl.SelectionChanged() 去觸發 ShowLeftPanel 狀態(開啟面版)。
設定 TabItem 底下的 GoToStateAction 屬性如下,由 TabItem.GotFocus() 去觸發HideLeftPanel 狀態(收合面版)。
6.最後,再放一個 Frame控制項到 LayoutRoot裡,並調整Margin屬性為適當的邊距,上邊距可多留白一點用來Banner或Logo。
Frame物件的細部XAML設定如下:
至此,前端的頁面設計就完成了。
接下來開始處理TabControl選單的部份。
一般AP的功能選單通常都會跟系統安控綁在一起,以便管控每個使用者或角色的系統使用權限,這部份的資料絕大多數都是存放在DataBase裡。
此例不考慮安控問題,我另外準備一個簡單的 XML 檔來存放功能選單的內容如下:
功能清單分二個清單群組GroupA及GroupB,每個群組底下各有二個功能清單記錄其ID、URL及功能名稱。
1.使用 Visual Studio 2010 開啟剛建立的 SL_TabControl.sln 方案
2.配合要使用的 XMLData.xml 功能清單檔的內容,先建一個 View 目錄。
接著在 View 目錄底下加入四個 Silverlight頁面,分別命名為 QueryA.xmal、QueryB.xaml、QueryC.xaml及QueryD.xaml。
並將這四個頁面的 Background屬性分別設成四種不一樣的底色以示區別。
3.切換到 MainPage.xaml.cs ,先加這二個namespace (必須先將 System.Xml.Linq.dll 加入參考)
using System.Xml.Linq;
using System.Linq;
再加入一個GetXML() 的Method,將 XMLData.xml 功能清單檔的內容套入TabControl中。
/// <summary>
/// 取得XML 功能清單
/// </summary>
private void GetXML()
{
XDocument docMenu = XDocument.Load("XMLData.xml");
//取得 FunctionGroup
var fgs = from c in docMenu.Descendants("FunctionGroup")
select new
{
TypeName = c.Attribute("ID").Value
};
foreach (var fg in fgs)
{
//每個 FunctionGroup 產生一個 TabItem 頁簽
TabItem ti = new TabItem();
ti.Name = fg.TypeName;
// 頁簽的 header
TextBlock tbk = new TextBlock();
tbk.Text = fg.TypeName;
tbk.TextWrapping = TextWrapping.Wrap;
tbk.Margin = new Thickness(-20, 27, -19, 35);
tbk.FontSize = 12;
tbk.RenderTransformOrigin = new Point(0.5, 0.5);
tbk.UseLayoutRounding = false;
CompositeTransform ctf = new CompositeTransform();
ctf.Rotation = 90;
tbk.RenderTransform = ctf;
ti.Header = tbk;
//頁簽的內容
StackPanel sp = new StackPanel();
sp.Background = new SolidColorBrush(Colors.LightGray);
// 取得某 FunctionGroup 底下的 FunctionMember
var fms = from c in docMenu.Descendants("FunctionGroup")
where c.Attribute("ID").Value == fg.TypeName
select c.Elements("FunctionMember");
foreach (var fm in fms.First())
{
HyperlinkButton hy = new HyperlinkButton();
hy.Name = "hy" + fm.Attribute("ID").Value;
hy.Content = fm.Value;
hy.NavigateUri = new Uri(@"/SL_TabControl;component" + fm.Attribute("URL").Value, UriKind.RelativeOrAbsolute);
hy.TargetName = "frmContent";
hy.ClickMode = ClickMode.Press;
hy.Foreground = new SolidColorBrush(Color.FromArgb(255, 2, 24, 186));
hy.Margin = new Thickness(10);
hy.FontSize = 16;
sp.Children.Add(hy);
}
ti.Content = sp;
((TabControl)this.FindName("tbcLeftMenu")).Items.Add(ti);
ti = null;
}
}
然後在 LayoutRoot Loaded去執行GetXML()即可。
private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
{
this.GetXML();
tbcLeftMenu.SelectedIndex = 1;
}
這樣就完成了!
另外附上完整的 MainPage.xaml。
<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" mc:Ignorable="d"
x:Class="SL_TabControl.MainPage"
Width="800" Height="600">
<Grid x:Name="LayoutRoot" Background="White" Width="800" Height="600" Loaded="LayoutRoot_Loaded">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="LeftPanelStateGroup">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:1">
<VisualTransition.GeneratedEasingFunction>
<BounceEase EasingMode="EaseOut"/>
</VisualTransition.GeneratedEasingFunction>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState x:Name="ShowLeftPanel"/>
<VisualState x:Name="HideLeftPanel">
<Storyboard>
<DoubleAnimation Duration="0" To="-170" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="Border" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<sdk:Frame x:Name="frmContent" Margin="40,100,40,10" Content=""/>
<Border x:Name="Border" BorderBrush="White" Background="White" BorderThickness="1" Width="200"
HorizontalAlignment="Left" Margin="0,10" CornerRadius="0,10,10,0" RenderTransformOrigin="0.5,0.5">
<Border.RenderTransform>
<CompositeTransform/>
</Border.RenderTransform>
<sdk:TabControl x:Name="tbcLeftMenu" TabStripPlacement="Right" Margin="0">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<ei:GoToStateAction x:Name="ShowAction" StateName="ShowLeftPanel"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<sdk:TabItem x:Name="tbiClose" Height="27" VerticalAlignment="Top" ToolTipService.ToolTip="關閉" >
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<ei:GoToStateAction x:Name="HideAction" StateName="HideLeftPanel"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<sdk:TabItem.Header>
<TextBlock TextWrapping="NoWrap" Text="X" Margin="-5,1,-25,1" FontSize="13.333"
RenderTransformOrigin="0.5,0.5" UseLayoutRounding="False" Width="12"
HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBlock.RenderTransform>
<CompositeTransform Rotation="90"/>
</TextBlock.RenderTransform>
</TextBlock>
</sdk:TabItem.Header>
<Grid x:Name="grid" Background="#FFE5E5E5" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<CompositeTransform/>
</Grid.RenderTransform>
</Grid>
</sdk:TabItem>
</sdk:TabControl>
</Border>
</Grid>
</UserControl>
執行結果:
因我沒有外部網路空間可以放 Silverlight 的檔案,無法實際Demo,所以請看圖說故事。
執行後,預設為開啟狀態,點選【x】後,面版主體會往左收合移至視窗外,只留下TabControl的頁籤。
在收合狀態下,點選 【GroupA】頁籤開啟面版,再點選【查詢功能B】,載入QueryB.xaml之後底色變成設定的 Background 顏色。
參考資料: