[Silverlight]學習筆記-使用 Deep Zoom 功能並顯示Sub-Images的Metadata(2)

  • 4751
  • 0
  • C#
  • 2011-01-10

[Silverlight]學習筆記-使用 Deep Zoom 功能並顯示Sub-Images的Metadata(2)

在進入本篇主題之前,先來看一下Hard Rock Cafe Memorabilia網站(底下簡稱Hard Rock網站)顯示Sub-ImagesMetadata方法。

 

剛開始進入Hard Rock網站,頁面右方的MultiScaleImage顯示如下:

01_Rock

 

當我們使用滑鼠滾輪將圖片放大到某種程度,MultiScaleImage的右側就會自動出現該圖片的資訊。

這裡顯示的資訊有二種方式,其一當滑鼠的操作為MouseDownMouseUp時,則點選的圖片會置中並放大,顯示的訊息即為點選圖片的資訊。而其二當滑鼠的操作為MouseMoveMouseWheel時,資訊顯示的是位於MultiScaleImage中心點那張圖片的資訊。

02_Rock

 

 

接著來看一下圖片資訊右上角個有個收合符號,點選它就可以將訊資的內容收合隱藏,隱藏之後則右上角的符號會改變,並出現More info字樣,若再點選它,則隱藏的資訊又會再展開。

03_Rock

 

 

 

在上一篇的[Silverlight]學習筆記-使用 Deep Zoom 功能並顯示Sub-Images的Metadata(1)中,已簡單介紹在Deep Zoom底下如何顯示SubImagesMetadata資訊,此例再使用Deep Zoom功能來做一個類似上述Hard Rock網站一樣的自動顯示圖片資訊的效果。

 

首先,使用Deep Zoom Composer(DZC)依上一篇DZC Project的建立方式,在第三步驟Export中,Export options裡有五種Templates選項,這五種TemplatesDZC User Guide的說明如下:

000_DZC

 

此例因要另外使用Blend 4進行後續的設定,所以就選擇 Expression Blend 4 + Source來練習。

00_DZC

 

使用檔案總管看一下Export出來的內容如下,所有DeepZoom的功能都有各自的class。

0000_DZC

 

 

接著使用 Blend 4 開啟剛建立的 DeepZoomProject.sln 方案,並調整其中Page.xaml頁面配置如下:

 

04_Blend

 

這裡新增一個Border容器(InfoBorder),其內再放一個Canvas容器(InfoCanvas),InfoCanvas容器內放入三個TextBlock控制項以便顯示影片資訊。

XAML的內容如下:

 

	<Canvas x:Name="LayoutRoot" Background="Black" Height="480" Width="800" >
		<MultiScaleImage x:Name="msi" Source="/GeneratedImages/dzc_output.xml" Height="480" Width="800">
		</MultiScaleImage>
		<Canvas Height="37" HorizontalAlignment="Right" x:Name="buttonCanvas" Width="348" Opacity="0" Background="{x:Null}" Canvas.Left="444" Canvas.Top="435">
			<Button Height="30" x:Name="zoomIn" Width="42" Canvas.Left="197" Canvas.Top="4" Template="{StaticResource zoomInTemplate}" Content="Button" />
			<Button Height="30" x:Name="zoomOut" Width="42" Template="{StaticResource zoomOutTemplate}" Content="Button" Canvas.Left="227" Canvas.Top="4" />
			<Button Height="30" x:Name="goHome" Width="42" Template="{StaticResource homeTemplate}" Content="Button" Canvas.Left="257" Canvas.Top="4" />
			<Button Height="30" x:Name="fullScreen" Width="42" Template="{StaticResource fullScreenTemplate}" Content="Button" Canvas.Left="287" Canvas.Top="4" />
		</Canvas>
    	<Border x:Name="InfoBorder" BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Right" Height="480" VerticalAlignment="Top" Width="160" RenderTransformOrigin="1,0" Background="#7F000000" Canvas.Left="640">
    		<Canvas x:Name="InfoCanvas" Margin="0,0,-2,-2">
    			<TextBlock x:Name="tbECapital" Canvas.Left="8" TextWrapping="Wrap" Text="TextBlock" Canvas.Top="38" Width="144" Height="16" Foreground="White"/>
    			<TextBlock x:Name="tbCCapital" Canvas.Left="8" TextWrapping="Wrap" Text="TextBlock" Canvas.Top="71" Width="144" Height="16" Foreground="White"/>
    			<TextBlock x:Name="tbDesciption" Canvas.Left="8" TextWrapping="Wrap" Text="TextBlock" Canvas.Top="101" Width="144" Height="371" Foreground="White"/>
    		</Canvas>
    	</Border>		
	</Canvas>

 

接下來我另外準備了一個類似Hard Rock網站上右上角收合圖片資訊的自訂控制項ArrowCheckBox,該控制項的狀態如下:

左邊為控制項UnChecked時的狀態,箭頭向左,左方有More info字樣。中間為MouseOver狀態,箭頭的Alpha值提高。右邊為Checked狀態,箭頭向右,原先的More info字樣消失。

14_Blend

 

Blend自訂控制項可參考[Silverlight]天啊!我把CheckBox變成圖釘了!!一文,在此加碼簡述一下此ArrowCheckBox控制項的作法如下:


1.使用BlendDeepZoom Project底下新增UserControl項目,名稱改為ArrowCheckBox.xaml

05_Blend

 

2.在ArrowCheckBoxLayoutRoot中任意拉一Ellipse楕圓形,並使其Width=Height=100變成圓形。另外拉三個Path線條,再將三個線條組成左箭號的形狀放在Ellipse內,並將所有物件其筆刷的Stroke全設成相同的顏色,Ellipse的填充顏色Fill順便也改一下,調整完頁面如下:

06_Blend

 

3.將Ellipse及三個Path全部選取,並於其上按滑鼠右鍵,選取【路徑】/【製作複合路徑】,將四個物件組成一個Path

07_Blend

 

4.接著調整組合成功的PathWidthHeight屬性縮小為20,而UserControlLayoutRootWidth=80Height=20,並調整所有物件的MarginHorizontalAlignment,調整完頁面如下:

09_Blend

整個XAML的內容如下:


	<UserControl
	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="DeepZoomProject.ArrowCheckBox"
	d:DesignWidth="640" d:DesignHeight="480" Width="80" Height="20">

	<Canvas x:Name="LayoutRoot" Width="80" Height="20">
		<Path Data="M19.5,10 C19.5,15.246705 15.246705,19.5 10,19.5 C4.7532949,19.5 0.5,15.246705 0.5,10 C0.5,4.7532949 4.7532949,0.5 10,0.5 C15.246705,0.5 19.5,4.7532949 19.5,10 z M3.6319995,10.086001 L16.873999,10.086001 M3.9860034,10.086 L8.5920029,5.480001 M3.9860034,10.086001 L8.5920029,14.692001" Fill="Black" Height="20" Canvas.Left="60" Stretch="Fill" Stroke="#FFC87800" UseLayoutRounding="False" Width="20"/>
	</Canvas>
</UserControl>

 

5.接著在組合成功的Path上按滑鼠右鍵,選取【變成控制項】,於對話視窗的控制項類型中,選取CheckBox,名稱改為ArrowCheckBoxStyle,然後按【確定】鈕。

081_Blend

 

6.變成控制項後,調整其中ContentPresenter文字至左方,並修改Path箭號圖的Alpha值為50%

10_Blend

 

7.接著開始為控製項設定狀態。

切換到狀態頁籤,然後選擇MouseOver,再選擇Path物件,設定筆刷的Alpha50%改為80%

11_Blend

 

再選擇CheckStates底下的Checked,再選擇ContentPresenter物件,將其Visible屬性設為Collapsed

12_Blend

 

最後再選擇Path物件,設定其RenderTransform翻轉X軸,讓原先的向左的箭號變成向右的箭號。

13_Blend

 

狀態設定完成後,執行建置專案,讓控制項生效。

 

自訂控制項介紹到此。


 

再回到Page.xaml看其它的設定。

 

1.拉一個CheckBox控制項到頁面上,將該控制項名稱改為chkShowInfoForeground設為#FFFFFFFF(白色),Content改為More info,再設定其StyleArrowCheckBoxStyle,這個CheckBox控制項的外型就會變成之前完成的ArrowCheckBox箭號樣式。最後再將該控制項移到頁面的右上角處。

21_Blend

 

2.選取InfoBorder容器,先設定其轉換縮放中的X軸縮放比例0,將其隱藏起來。

17_Blend

 

3.切換到狀態頁籤,點選新增狀態群組以新增一個狀態群組,並將其改名為 InfoStateGroup

15_Blend

 

3.在InfoStateGroup狀態群組底下,新增二個狀態,分別命名為 ShowInfoBorderHideInfoBorder

16_Blend

 

4.先選擇ShowInfoBorder狀態,再選擇InfoBorder容器,然後設定其轉換縮放中的X軸縮放比例1,讓其顯示。

18_Blend

 

5.切換到資產頁籤,拉二個GoToStateAction行為到ArrowCheckBox控制項底下,分別命名為ShowStateActionHideStateAction

20_Blend

 

這二個行為的設定分別如下:

22_Blend

 

到此先存檔,接來的工作交給Visual Studio 2010

 

接著使用 VS 2010 開啟 DeepZoomProject.sln 方案:

 

1.先把上個練習範例中電影資訊檔MoviesContent.XML加進方案中。

 

2.為了達成前述Hard Rock網站顯示圖片資訊的功能,我們必須要知道MultiScaleImage的三項資訊才能進行,這三項必要的資訊為 : 目前的縮放比、點擊了哪張圖片以及滑鼠是否為拖曳狀態。

 

開啟DeepZoomInitializer.cs,替MultiScaleImage追加三個DependencyProperty以記錄上述三項資訊,分別為ZoomFactorPropertySelectedIndexPropertyDuringDragsProperty


	public static readonly DependencyProperty ZoomFactorProperty = DependencyProperty.Register("ZoomFactor",typeof(double),typeof(MultiScaleImage), null);
        public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register("SelectedIndex",typeof(int),typeof(MultiScaleImage), null);
        public static readonly DependencyProperty DuringDragsProperty = DependencyProperty.Register("DuringDrags", typeof(bool), typeof(MultiScaleImage), null);

並且在Zoom()裡賦與ZoomFactor值給ZoomFactorProperty

 

 


	private void Zoom(double newzoom, Point p)
        {
            // Do something

            msi.SetValue(ZoomFactorProperty, this.ZoomFactor);
        }

另外在這裡加入將點擊圖片置中的功能,並且賦與值給SelectedIndexPropertyDuringDragsProperty


	msi.MouseLeftButtonUp += delegate(object sender, MouseButtonEventArgs e)
            {
                if (!duringDrag)
                {
                    // Do something

                    selectedIndex = SubImageHit(this.msi.ElementToLogicalPoint(e.GetPosition(this.msi)));
                    if (selectedIndex >= 0)
                        this.DisplaySubImageCentered(selectedIndex);    //點擊的圖片置中

                    Zoom(newzoom, msi.ElementToLogicalPoint(this.lastMousePos));

                    msi.SetValue(SelectedIndexProperty, selectedIndex);
                }

                msi.SetValue(DuringDragsProperty, duringDrag);
            };

 

3.切換到 Page.xaml.cs ,先加這二個namespace (必須先將 System.Xml.Linq.dll 加入參考)


	using System.Xml.Linq;
using System.Linq;

然後再宣告三個Property,透過這三個Property去取得MultiScaleImageDeepZoomInitializer所追加的那三個DependencyProperty


	public double ZoomFactor
{
    get { return (double)msi.GetValue(DeepZoomInitializer.ZoomFactorProperty); }
}

public int SelectedIndex
{
    get { return (int)msi.GetValue(DeepZoomInitializer.SelectedIndexProperty); }
}

public bool DuringDrags
{
    get { return (bool)msi.GetValue(DeepZoomInitializer.DuringDragsProperty); }
}


另外追加MultiScaleImage三個EventHandler


	public Page()
        {
            InitializeComponent();

            this.msi.ImageOpenSucceeded += new RoutedEventHandler(msi_ImageOpenSucceeded);
            this.msi.MouseLeftButtonUp += new MouseButtonEventHandler(msi_MouseLeftButtonUp);
            this.msi.MouseWheel += new MouseWheelEventHandler(msi_MouseWheel);
        }

 

其中msi_ImageOpenSucceeded的內容如上個範例,主要是載入影片的資訊,在此不再贅述。

 

msi_MouseLeftButtonUpmsi_MouseWheel的內容如下:

 


	private void msi_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (!this.DuringDrags)
            {
                imageIndex = this.SelectedIndex; //取得點擊的圖片索引

                if (imageIndex < 0)
                    imageIndex = SubImageHit(this.msi.ElementToLogicalPoint(new Point(this.msi.ActualWidth / 2, this.msi.ActualHeight / 2)));  //取得中心點所在的圖片索引
            }
            else
            {
                imageIndex = SubImageHit(this.msi.ElementToLogicalPoint(new Point(this.msi.ActualWidth / 2, this.msi.ActualHeight / 2)));  //取得中心點所在的圖片索引
            }

            this.MappingInfo(imageIndex);    //取得對應的影片訊息
        }

        private void msi_MouseWheel(object sender, MouseWheelEventArgs e)
        {
            imageIndex = SubImageHit(this.msi.ElementToLogicalPoint(new Point(this.msi.ActualWidth / 2, this.msi.ActualHeight / 2)));  //取得中心點所在的圖片索引

            this.MappingInfo(imageIndex);   //取得對應的影片訊息
        }

 

msi_MouseLeftButtonUp裡先判斷是否有點擊圖片,若有則取得點擊圖片索引,若無(ex.點擊在圖片外的範圍)則取得MultiScaleImage中心點所在的那張圖片索引,MultiScaleImage的中心點可用new Point(this.msi.ActualWidth / 2, this.msi.ActualHeight / 2)取得。 取得圖片索引值之後,再透過MappingInfo()去取得該圖片的相關影片訊息及判斷目前的ZoomFactor是否需要顯示訊息。

 

而在msi_MouseWheel裡,則直接則取得MultiScaleImage中心點所在的那張圖片索引,再透過MappingInfo()去取得該圖片的相關影片訊息及判斷目前的ZoomFactor是否需要顯示訊息。

 

另外,MappingInfo()取得影片訊息的內容如下,其中ZoomFactor>=2.8才會顯示影片資訊,這個條件可視情況自行調整。


	//取得對應的影片訊息
        private void MappingInfo(int index)
        {
            if (index >= 0)
            {
                //由ImageInfo取得該張圖片的影片資訊
                SubImageInfo subImageInfo = ImageInfo.FirstOrDefault(s => s.Index == index);

                tbECapital.Text = subImageInfo.E_Caption;       //英文片名
                tbCCapital.Text = subImageInfo.C_Caption;       //中文片名
                tbDesciption.Text = subImageInfo.Description;   //影片說明
            }
            else
            {
                tbECapital.Text = string.Empty;
                tbCCapital.Text = string.Empty;
                tbDesciption.Text = string.Empty;
            }

            // 判斷是否要秀影片訊息
            if (index < 0)
            {
                this.ShowInfo(false);
                return;
            }

            if (this.ZoomFactor >= 2.8)    //當縮放值>2.8則顯示資訊,此值可視情況自行調整
                this.ShowInfo(true);
            else
                this.ShowInfo(false);
        }

        private void ShowInfo(bool show)
        {
            if (show)
            {
                chkShowInfo.Visibility = Visibility.Visible;
                InfoBorder.Visibility = Visibility.Visible;
            }
            else
            {
                InfoBorder.Visibility = Visibility.Collapsed;
                chkShowInfo.Visibility = Visibility.Collapsed;
            }
        }

 

最後來看一下執行結果:

MoviesList

 

完整的範例程式碼可於此下載 MoviesList2.zip

 

參考資料:

Hard Rock Cafe Memorabilia

[Silverlight]天啊!我把CheckBox變成圖釘了!!

 

電影圖片及資料來源:

KingNet歡樂網路王國

開眼電影網