[Silverlight]學習筆記-製作可收合的功能選單(使用TabControl)

[Silverlight]學習筆記-製作可收合的功能選單(使用TabControl)

最近正在學習使用Silverlight,前陣子剛好看到Ouch兄這篇 [Silverlight]利用圖釘做出可以收合、開啟的面版 的教學,原來使用Silverlight就可輕鬆達成面版的收合,之前處理收合面版都得透過Java Script。

 

一般傳統的 Web 功能選單有不少是使用TreeView搭配Frame框架來使用,此例我是用 TabControl 來製作功能選單。

 

首先來設計前端的頁面及面版收合的動作 (可先參考Ouch兄的那篇教學)

 

1.使用 Expression Blend 4 開啟一個新專案,這裡使用的專案類型為 Silverlight應用程式+網站

NewProject

 

2.放入一個Border控制項物件到LayoutRoot裡。

00_start

Border物件的細部XAML設定如下:

01_Border

 

3.放入一個TabControl控制項到Border裡。

 

設定 TabControl 一般屬性下的 TabStripPlacement 屬性為 Right  以便TabItem 置於 TabControl 的右方。

 

預設的TabControl有二個TabItem,刪除其中一個TabItem,只須留下一個TabItem。

保留下來的這個TabItem將會用來收合面版使用,其它的 TabItem 選單則於執行時期交由程式動態產生。

03_Tab

TabControl物件的細部XAML設定如下:

04_TabXAML

 

此處因要將 TabItem.Header 旋轉90度置放,所以包了一個TextBlockTabItem.Header裡,以便透過 TextBlock.RenderTransform 設定Rotation=90

 

4.接下來開始準備設計面版收合、展開的動畫。

 

切換到狀態頁籤,新增一個狀態群組,並將其名稱改為 LeftPanelStateGroup

05_AddStatusGroup

 

在剛新增的 LeftPanelStateGroup 狀態群組中,新增二個狀態

再將第一個狀態改名為 ShowLeftPanel (拿來當開啟面版的狀態),另一個狀態則改名為 HideLeftPanel (拿來當收合面版的狀態)。

06_AddStatusGroup

 

接著設定狀態切換的動畫為 Bounce Out

07_AddStatusGroup

並將切換動畫的持續時間設為 1 s (1秒)。

08_AddStatusGroup

 

接著使用RenderTransformX 軸位移來設定面版隱藏狀態。

先選擇左側的 HideLeftPanel 狀態以及 Border 物件,設定其 RenderTransformX 軸屬性的平移值為 –170,Border物件移出至視窗左方,只保留一些空間讓 TabItem 得以顯示。。

09_AddStatusGroup

 

點選工作區上方 HideLeftPanel 狀態 錄製已開啟 前的紅色圖示關閉錄製。

10_AddStatusGroup

 

5.幫TabControl加上變更狀態的 GoToStateAction 行為,以用來切換狀態。

 

切換到資產頁籤,找到行為(Behaviors)底下的GoToStateAction,分別各拖曳一個GoToStateActionTabControlTabItem 物件底下。

11_AddStatusGroup

 

設定 TabControl 底下的 GoToStateAction 屬性如下,由 TabControl.SelectionChanged() 去觸發 ShowLeftPanel 狀態(開啟面版)。

12_AddStatusGroup

 

設定 TabItem 底下的 GoToStateAction 屬性如下,由 TabItem.GotFocus() 去觸發HideLeftPanel 狀態(收合面版)。

13_AddStatusGroup

 

6.最後,再放一個 Frame控制項到 LayoutRoot裡,並調整Margin屬性為適當的邊距,上邊距可多留白一點用來Banner或Logo。

14_AddStatusGroup

Frame物件的細部XAML設定如下:

15_AddStatusGroup

 

至此,前端的頁面設計就完成了。

 

接下來開始處理TabControl選單的部份。

 

一般AP的功能選單通常都會跟系統安控綁在一起,以便管控每個使用者或角色的系統使用權限,這部份的資料絕大多數都是存放在DataBase裡。

此例不考慮安控問題,我另外準備一個簡單的 XML 檔來存放功能選單的內容如下:

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屬性分別設成四種不一樣的底色以示區別。

vs2010_01

 

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的頁籤。

RunTime_01

 

在收合狀態下,點選 【GroupA】頁籤開啟面版,再點選【查詢功能B】,載入QueryB.xaml之後底色變成設定的 Background 顏色。

RunTime_02

 

參考資料:

[Silverlight][教學影片]利用圖釘做出可以收合、開啟的面版