Silverlight帶了Combox控制項,但這個控制項只能選擇不能編輯,雖然它能定義Item外觀,但如果下拉選擇是一個DataGrid控制項似乎就不好定義了.還好Silverlight提供了一個靈活的Popup控制項,通過它能實作類別似於ComboGrid的功能.
先看一下需要的功能效果:
我們需要在選擇項後自動地把選擇的資料填充到相關性的兩個TextBox中.實現這個功能我們選擇了TextBox,Button和一個自訂的Popup DataGrid使用者控制項.由於Popup只負責顯示但我們需要解決一些總是,就是當Popup顯示的時候點擊自身或其他地區就自動關閉,所以需用要把Popup DataGrid封裝一起方便處理.
以下是這個Popup DataGrid的實現
<UserControl x:Class="ComboGrid.ComboGrid" 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" d:DesignHeight="300" d:DesignWidth="400" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" Loaded="UserControl_Loaded"> <Grid x:Name="LayoutRoot" Background="#09FFFFFF" MouseRightButtonDown="LayoutRoot_MouseRightButtonDown" MouseLeftButtonDown="LayoutRoot_MouseLeftButtonDown"> <sdk:DataGrid AutoGenerateColumns="False" HorizontalAlignment="Left" Name="dataGrid1" VerticalAlignment="Top" Width="253" MouseLeftButtonDown="dataGrid1_MouseLeftButtonDown" SelectionChanged="dataGrid1_SelectionChanged"> <sdk:DataGrid.Columns> <sdk:DataGridTextColumn Binding="{Binding Name}" CanUserReorder="True" CanUserResize="True" CanUserSort="True" Width="120" Header="Name" /> <sdk:DataGridTextColumn Binding="{Binding Host}" CanUserReorder="True" CanUserResize="True" CanUserSort="True" Width="*" Header="Host" /> </sdk:DataGrid.Columns> </sdk:DataGrid> </Grid></UserControl>
LayoutRoot的背景設定非常重要,因為我們需要用它來做這遮罩,來捕獲DataGrid周邊的滑鼠點擊事件,為了不影響整個布局的外觀好儘可能的設定接近秀明.給使用者控制項定義兩個mouse down事件自動隱藏
private void LayoutRoot_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { Hide(); } private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { Hide(); }
為了讓DataGrid排序等操作不觸這兩個事件,需要在DataGrid的LeftMouseDown設定一個屬性值
private void dataGrid1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { e.Handled = true; }
這樣DataGrid點擊滑鼠左鍵的時候就不會把Popup隱藏了.下面是給控制項定義顯示方法.
public void Show(Control target,Point Offset) { mPopup = new Popup(); this.Width = Application.Current.Host.Content.ActualWidth; this.Height = Application.Current.Host.Content.ActualHeight; GeneralTransform gt = target.TransformToVisual(Application.Current.RootVisual as UIElement); Point offset = gt.Transform(new Point(0, 0)); double controlTop = offset.Y; double controlLeft = offset.X; Point postion= new Point(controlLeft + Offset.X, controlTop + Offset.Y); mPopup.Child = this; dataGrid1.Margin = new Thickness(postion.X, postion.Y, 0, 0); mPopup.IsOpen = true; }
方法帶兩個參數,第一個是目標控制項,是指Popup的位置就顯示在這個控制項之上,第二個方法就是位移座標.最終通過修改DataGrid的Margin來達到所需位置的顯示.控制項隱藏方法代碼相對也是非常簡單
public void Hide() { if (mPopup != null) { mPopup.IsOpen = false; mPopup.Child = null; mPopup = null; } }
下面的工作就是處理DataGrid的SelectChanged需要做的事件,當我們改變選擇項的同時觸發一個事件告訴調用者和把當前Popup關閉即可.
private void dataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e) { if (dataGrid1.SelectedItem != null ) { Hide(); if (Selected != null) Selected((UserData)dataGrid1.SelectedItem); } }
到這時Popup DataGrid的就已經封裝完成,那實際調用代碼如下:
private ComboGrid mComboGrid = new ComboGrid(); private void button1_Click(object sender, RoutedEventArgs e) { mComboGrid.Show(textBox1, new Point(0, 26)); } private void UserControl_Loaded(object sender, RoutedEventArgs e) { mComboGrid.Selected += (s) => { textBox1.Text = s.Name; textBox2.Text = s.Host; }; }
Silverlight提供給我們的Popup可以實現的功能有很多,MessageBox,自訂Combox和右鍵菜單等等.遲下會講解如何?一個右鍵菜單.
以下這個地址實現了這幾種效果:sl.henryfan.net
下載完整代碼: ComboGrid.rar (1.88 mb)