了解WP的傳感器


  之前看到老大的一個QQ簽名,說想寫一個WP的程序,可是后來,后來就沒有后來了。我去年打算學一下WP程序開發的,一年了也無任何進展,我可不想后來,后來就沒有后來。於是抽時間來接觸一下。雖然都是用CShsarp,雖然都是拖控件,但是xaml不熟悉,界面的布局也不熟悉,就連手機的環境也不熟悉。以前寫winform程序時知道鼠標單擊事件是Click,鍵盤按鍵就keypress等。可是WP的控件沒有Click。於是這回就熟悉一下WP的重力感應,觸控和加速這三方面。

方向處理

  在使用WP的時候就會發現,一個長方形的屏幕,有時候它的內容是豎屏顯示的,像開始菜單,QQ;有些內容是橫屏顯示的,像視頻的播放;有些內容是隨着重力傳感器傳來的信息自動切換橫豎屏顯示的,像一部分系統的頁面:信息啊,郵件啊,IE瀏覽器啊。當我們默認建立一個頁面的時候,無論怎么翻轉模擬器,它只能是豎屏顯示。此時需要設置PhoneApplicationPage標記下的SupportedOrientations屬性就可以了,這個屬性是一個枚舉,有三個值Portrait(豎屏),Landscape(橫屏)和PortraitOrLandscape(橫豎屏切換)。默認是Portrait。

在這個橫豎屏切換到的過程中,頁面上某些容器的大小Size會發生變化,例如整個頁面的LayoutRoot標題部分的TitlePanel還有頁面內容部分的ContentPanel。不過這些變化其實挺直觀的。

       在方向變換的時候,都會觸發一個事件OrientationChanged,PhoneApplicationPage和PhoneApplicationFrame都擁有這個事件。當然除了通過給這個事件綁定方法外,還可以重寫PhoneApplicationPage的OnOrientationChanged(一般都這樣,每個事件多半會有個On作前綴的虛方法)。

例如在PhoneApplicationPage節點上綁定事件

OrientationChanged="PhoneApplicationPage_OrientationChanged"

方法定義這樣

1         private void PhoneApplicationPage_OrientationChanged(object sender, OrientationChangedEventArgs e)
2         {
3             this.txtDirection.Text = "Contentpanel\r\n" + ContentPanel.RenderSize.Width + " * " + ContentPanel.RenderSize.Height;
4         }

運行的效果是

觸控

  觸屏手機相比起以前的按鍵手機而言,在人機交互方面就提升了不少用戶體驗。用戶直接點擊屏幕(類似使用電腦時用鼠標點擊)來輸入信息代替了啪啪啪地按手機鍵盤。

  在WP里面處理觸控的有兩個層面,一個是底層的Touch類的靜態事件FrameReported;另一個是高層的UIElement類的Manipulation事件組。為啥說它是事件組,其實它是由三個事件組成:ManipulationStart、ManipulationDelta和ManipulationCompleted。那么下面就分別嘗試一下兩種方式的觸控處理

若要使用Touch的FrameReported,只能在相應的地方加上一下的代碼

Touch.FrameReported += new TouchFrameEventHandler(Touch_FrameReported);

  我自己呢就那這個事件綁定的放在MainPage的構造函數里面。綁定的方法如下,其效果是點擊屏幕上的任意位置,該位置的坐標點會顯示在頁面標題的地方

        void Touch_FrameReported(object sender, TouchFrameEventArgs e)
        {
            TouchPoint tp= e.GetTouchPoints(null).First();
            this.PageTitle.Text = tp.Position.ToString();
        }

  可以看出Touch的FrameReported是個靜態事件,那么一旦注冊了這個事件,在程序上別的頁面都會觸發這個事件了。所以用的時候這一點要注意。

現在看會來事件的參數TouchFrameEventArgs,它里面有三個可調動的方法

方法名

參數

返回

描述

GetTouchPoints

UIElement

TouchPointCollection

獲取相對UIElement於的多點觸控的TouchPoint集合

GetPrimaryTouchPoint

UIElement

TouchPoint

獲取相對UIElement的主觸控點的TouchPoint

SuspendMousePromotionUntilTouchUp

-

void

掛起把觸控事件提升為鼠標事件

這個表格里頭有幾點又要說明一下

  第一就是那個SuspendMousePromotionUntilTouchUp方法的,原本的觸摸事件提升為原本Silverlight桌面版本的鼠標事件的方法,也就是那個Moues的方法組。當調用了SuspendMousePromotionUntilTouchUp之后,綁定在控件上的Mouse事件就不會觸發了。

例如這里有一個TextBlock

            <TextBlock x:Name="txtDirection" Text="Hello world"  Height="64" Width="159"
                       VerticalAlignment="Center"  HorizontalAlignment="Center" 
                       SizeChanged="txtDirection_SizeChanged"
                       MouseLeftButtonDown="txtDirection_MouseLeftButtonDown"></TextBlock>

txtDirection_MouseLeftButtonDown方法就是show一個MessageBox,說明單擊了鼠標左鍵。

但是如果調用了SuspendMousePromotionUntilTouchUp方法之后,那個MessageBox就不會顯示出來,調用的方式如下

        void Touch_FrameReported(object sender, TouchFrameEventArgs e)
        {
            TouchPoint tp = e.GetPrimaryTouchPoint(null);
            if (tp != null && tp.Action == TouchAction.Down)
                e.SuspendMousePromotionUntilTouchUp();
        }

  第二點就是前兩個獲取觸控點的方法,獲取的點都是相對於傳入的UIElement的點的坐標,那個UIElement就是一個參照點,假如傳入的參數是null的,參照點則是正向(三個按鍵在下面的豎屏方向)的左上角了。

第三點就是介紹一下返回的觸控點TouchPoint實例,它有以下4個只讀屬性,

屬性名稱

類型

描述

Action

TouchAction

描述特定觸控點的操作,包括Up(抬起),Move(拖動),Down(放下)

Position

Point

相對於參考元素左上角的位置

Size

Size

接觸的面積

TouchDevice

TouchDevice

生成這個TouchPoint的觸摸設備,通過其DirectlyOver屬性可以獲得手指下最頂層的元素

接着到Manipulation事件組了

Manipulation的三個事件名稱眼看都能知道他們觸發的時機,下面則單通過Manipulation事件來介紹,TextBlock按如下定義

            <TextBlock x:Name="txtDirection" Text="Hello world"  Height="364" Width="359"
                       VerticalAlignment="Center"  HorizontalAlignment="Center"
                       ManipulationStarted="txtDirection_ManipulationStarted"></TextBlock>

綁定的方法如下

        private void txtDirection_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
        {
            double destinct = Math.Sqrt(e.ManipulationOrigin.X * e.ManipulationOrigin.X +
                e.ManipulationOrigin.Y * e.ManipulationOrigin.Y);
            Brush brush=new SolidColorBrush(Color.FromArgb(255,(byte)destinct,0,0 ));
            (e.OriginalSource as TextBlock).Foreground=brush;
            e.Complete();
            e.Handled = true;
        }

  這個事件參數ManipulationStartedEventArgs其實繼承RoutedEventArgs傳遞了事件的觸發源元素和觸控的位置等信息,其中的ManipulationContainer和RoutedEventArgs的OriginalSource都是獲取觸發事件的對象,在這里的話他們都是跟sender一樣引用這同一個對象。ManipulationStartedEventArgs的ManipulationOrigin其實跟TouchPoint的Position一樣。而Handled屬性和Complete()方法都是告知系統觸控處理已經完畢了,不需要在處理Manipulation事件了。這里其實還涉及到WPF里面的事件冒泡方面的知識。

加速計

  加速計是位於WP手機內部的一個小硬件,用於測量力的。一個很簡單的例子,在重力場中的WP手機,這個加速計會響應WP手機的重力。它可以告知力的大小和方向,並通過時間換算出加速度。這個力是一個矢量,在這里是通過一個數學的空間直角坐標系來描述。那下面則通過一個demo使用這個加速計。

xaml文件的內容同樣是這樣子

            <TextBlock x:Name="txtDirection" Text="Hello world"  Height="364" Width="359"
                       VerticalAlignment="Center"  HorizontalAlignment="Center"></TextBlock>

在MainPage的構造函數里面調用加速計

            Accelerometer acc = new Accelerometer();
            acc.ReadingChanged += new EventHandler<AccelerometerReadingEventArgs>(acc_ReadingChanged);

            try
            {
                acc.Start();
            }
            catch (Exception ex)
            {
                txtDirection.Text = ex.Message;
            }

當加速計有變化的時候就會觸發ReadingChanged事件,該事件的會傳入一個AccelerometerReadingEventArgs類型的實例作參數,里面有加速度的向量表示以及時間。

        void acc_ReadingChanged(object sender, AccelerometerReadingEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("X={0:F2}\r\n", e.X);
            sb.AppendFormat("Y={0:F2}\r\n", e.Y);
            sb.AppendFormat("Z={0:F2}\r\n", e.Z);
            sb.AppendFormat("Time={0}\r\n", e.Timestamp);

            txtDirection.Dispatcher.BeginInvoke(delegate() {
                txtDirection.Text = sb.ToString();
            });

        }

結果如圖所示

可惜只是在模擬器上運行,試不出真正效果,模擬器的加速度一直都是(0,0,-1)。

  由於時間不是停止的,所以只要加速計還在運行(就是不調用Stop)ReadingChanged事件一直會觸發,acc_ReadingChanged一直在執行。而這個加速計貌似是開了另一個線程的,所以執行ReadingChanged事件時會涉及到線程安全的問題,就像平時在寫WinForm多線程程序時,從非窗體線程調用窗體的界面時,都要用Invoke 方法,這里就用BeginInvoke方法。

 

以上其實基本上是讀書筆記,有什么意見或建議不妨@一下。謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM