c# WPF動畫影象按鈕沒有按鈕
介紹 在Windows應用程式中,改進使用者互動的一個眾所周知的方法是在按鈕中放置一個影象,當操作比“提交”操作更抽象時,可以將它們執行的操作視覺化。最簡單的方法是使用一個簡單的點陣圖影象作為按鈕UIElement的背景刷。但是,有時按鈕的單擊動畫的預設行為是不可取的。在本文中,我想做的是概述一個可重用的矩形,以模擬按鈕的一般行為,但使用簡單的影象轉換,並顯示在網格“快速欄”中。 簡單地說,我開始建立一個控制元件,它將閃現一個影象底片,這樣使用者就知道他們沒有使用按鈕就點選了它。 在啟動影象快取 為了在顯示動畫時消除任何延遲,我發現最好在應用程式啟動時將所有影象載入到一個字典集合中。 這些是我在製作這個的時候用到的圖片。 我在專案中添加了這些圖片作為資源。兩者都是29x29畫素。 隱藏,複製Code
// the image dictionary private Dictionary<string, ImageSource> _imageCache; // helper function to convert resource bitmaps into a BitmapSource // since resource images are loaded as plain bitmaps private BitmapSource CreateSourceFromBitmap(System.Drawing.Bitmap bitmap) { return System.Windows.Interop.Imaging.CreateBitmapSourceFrom HBitmap( bitmap.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions() ); } // loading the images into memory private void LoadImages() { _imageCache = new Dictionary<string, ImageSource>(); _imageCache.Add("Search", CreateSourceFromBitmap(Properties.Resources.Search)); _imageCache.Add("SearchInverted", CreateSourceFromBitmap(Properties.Resources.SearchInverted)); }
有了這個,我們的影象是預先載入和準備去做一個快速過渡動畫。 的QuickBar QuickBar是一個簡單的網格,用於包含按鈕。我在網格中定義了按鈕的大部分屬性,以獲得統一的外觀。此外,所有按鈕事件都連線到所有按鈕的單個事件。我將很快討論如何處理這個問題。我選擇了這個方法,這樣每個按鈕的事件處理程式都是不必要的。 隱藏,收縮,複製Code
<Gridx:Name="_grid_Content_QuickBar"> <Grid.ColumnDefinitions> <ColumnDefinitionWidth="38"> <!-- Add more columns for more buttons --> <ColumnDefinitionWidth="1*"> </Grid.ColumnDefinitions> <Grid.Resources> <StyleTargetType="Rectangle"> <SetterProperty="VerticalAlignment"Value="Center"/> <SetterProperty="HorizontalAlignment"Value="Center"/> <SetterProperty="Margin"Value="3"/> <SetterProperty="Width"Value="32"/> <SetterProperty="Height"Value="32"/> <SetterProperty="RadiusX"Value="2"/> <SetterProperty="RadiusY"Value="2"/> <SetterProperty="Stroke"Value="#858585"/> <SetterProperty="StrokeThickness"Value="1.5"/> <EventSetterEvent="MouseEnter"Handler="QuickMenu_MouseEnter"/> <EventSetterEvent="MouseLeave"Handler="QuickMenu_MouseLeave"/> <EventSetterEvent="MouseDown"Handler="QuickMenu_MouseClick"/> </Style> </Grid.Resources> <RectangleGrid.Column="0"ToolTip="Launch new search"x:Name="rect_Search"> <Rectangle.Fill> <ImageBrushImageSource=".\Resources\Search.png"Stretch="Uniform"/> </Rectangle.Fill> </Rectangle> </Grid>
連線事件 由於我決定通過單個事件處理程式來處理所有事件,因此需要一些程式碼來處理它們。雖然我使用了在單個處理程式中處理MouseDown事件的方法,但將該事件處理程式新增到每個按鈕也同樣容易。 隱藏,收縮,複製Code
// event function mapper private Dictionary<string, Action> _buttonEventHandlers; // a method to register events. Called during app initialization private void RegisterEventHandlers() { _buttonEventHandlers = new Dictionary<string, Action>(); _buttonEventHandlers.Add(rect_Search.Name, SearchClick); } // button event handlers // this one changes the button outline to highlight which button the mouse is over private void QuickMenu_MouseEnter(object sender, RoutedEventArgs e) { Rectangle rect = sender as Rectangle; if (rect != null) { rest.Stroke = Brushes.Thistle; // change the color of the rectangle border on mouseover } } // this one removes the highlight when the mouse leaves the button private void QuickMenu_MouseLeave(object sender, RoutedEventArgs e) { Rectangle rect = sender as Rectangle; if (rect != null) { rect.Stroke = new SolidColorBrush (Color.FromArgb(255, 85, 85, 85); // change the color back to the original on mouseleave } } // this one handles the user clicks private void QuickMenu_MouseClick(object sender, MouseButtonEventArgs e) { Rectangle rect = sender as Rectangle; Action action; if (rect != null) { action = _buttonEventHandlers[rect.Name]; action?.Invoke(); } }
處理MouseLeave事件的更好方法是在啟動程式碼中定義一個預設的SolidColorBrush,以節省一些效能,而不是每次單擊都建立一個新的畫筆。 動畫按鈕 為了確保每個按鈕正確地處理其影象,我添加了這段程式碼,這段程式碼將在對映到按鈕的單擊事件的Action函式中呼叫。動畫是通過ObjectAnimationUsingKeyFrames類完成的。使用關鍵幀的objectanimationusingkeyframe與其他關鍵幀動畫類的區別在於沒有幀之間的過渡平滑。 隱藏,收縮,複製Code
// the animation code private void QuickButtonClicked(Rectange rect, ImageSource originalImg, ImageSource alternateImg) { ObjectAnimationUsingKeyFrames animation = new ObjectAnimationUsingKeyFrames() { AutoReverse = true, Duration = new Duration(TimeSpan.FromSeconds(0.125)), // duration is very important here RepeatBehavior = new RepeatBehavior(2D) // flash twice }; var startFrame = new DiscreteObjectKeyFrame(); startFrame.Value = originalImg; startFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0.0)); animation.KeyFrames.Add(startFrame); var altFrame = new DiscreteObjectKeyFrame(); altFrame.Value = alternateImg; altFrame.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromSeconds(0.0625)); animation.KeyFrame.Add(altFrame); rect.Fill.BeginAnimation(ImageBrush.ImageSourceProperty, animation); } // the button click handler private void SearchClick() { QuickButtonClicked(rect_Search, _imageCache["Search"], _imageCache["SearchInverted"]); // ToDo: respond to the click }
在這裡,我使用離散objectkeyframe類定義動畫的每一幀。因為只有兩個框架,所以很簡單。有兩個重要的部分,一個是幀值,它被設定為將要顯示的影象,另一個是KeyTime,它指示在動畫時間軸中何時移動到下一幀。由於只有兩幀,我將第二個鍵時間設定為持續時間的一半。 值得注意的是,雖然我使用了一個簡單的動畫在兩個影象之間快速切換以響應滑鼠點選,但在使用具有幾十個關鍵幀的更復雜的影象動畫時應該沒有什麼困難。 總之 為了創造更好的使用者體驗,我還在學習WPF動畫的強大功能。由於我在理解這個問題上有些困難,所以我想分享一下我學到的經驗。 歷史 10/11/2016:最初的帖子 本文轉載於:http://www.diyabc.com/frontweb/news517.html