有关AutoCompleteBox组件的研究[4]_下拉框内嵌DataGrid与被嵌入DataGrid——Silverlight学习笔记[39]
在AutoCompleteBox组件下拉框中嵌入DataGrid可以让我们更好地组织候选数据以达到更好的显示效果。与此类似的,在DataGrid组件中嵌入AutoCompleteBox组件可以便于我们进行数据的输入。本文将为大家讲述如何实现这两种效果。
※内嵌DataGrid
为了能实现在AutoCompleteBox组件的下拉框中成功地嵌入DataGrid,我们需要用到微软提供给我们的一个辅助类DataGridSelectionAdapter,该类继承自DataGrid并实现了ISelectionAdapter接口。该类的代码如下:
DataGridSelectionAdapter.cs(将该文件保存在Silverlight项目文件夹下)
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls;
using System.Windows.Input;
namespace SilverlightClient
{
public class DataGridSelectionAdapter : DataGrid, ISelectionAdapter
{
private bool IgnoreAnySelection { get; set; }
private bool IgnoringSelectionChanged { get; set; }
public new event SelectionChangedEventHandler SelectionChanged;
public event RoutedEventHandler Commit;
public event RoutedEventHandler Cancel;
public DataGridSelectionAdapter()
{
base.SelectionChanged += OnSelectionChanged;
MouseLeftButtonUp += OnSelectorMouseLeftButtonUp;
}
public new object SelectedItem
{
get
{
return base.SelectedItem;
}
set
{
IgnoringSelectionChanged = true;
base.SelectedItem = value;
IgnoringSelectionChanged = false;
}
}
private void OnSelectorMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
IgnoreAnySelection = false;
OnSelectionChanged(this, null);
OnCommit(this, new RoutedEventArgs());
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (IgnoringSelectionChanged)
{
return;
}
if (IgnoreAnySelection)
{
return;
}
SelectionChangedEventHandler handler = this.SelectionChanged;
if (handler != null)
{
handler(sender, e);
}
}
public new IEnumerable ItemsSource
{
get { return base.ItemsSource; }
set
{
if (base.ItemsSource != null)
{
INotifyCollectionChanged notify = base.ItemsSource as INotifyCollectionChanged;
if (notify != null)
{
notify.CollectionChanged -= OnCollectionChanged;
}
}
base.ItemsSource = value;
if (base.ItemsSource != null)
{
INotifyCollectionChanged notify = base.ItemsSource as INotifyCollectionChanged;
if (notify != null)
{
notify.CollectionChanged += OnCollectionChanged;
}
}
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
IgnoreAnySelection = true;
}
private ObservableCollection<object> Items
{
get { return ItemsSource as ObservableCollection<object>; }
}
private void SelectedIndexIncrement()
{
SelectedIndex = SelectedIndex + 1 >= Items.Count ? -1 : SelectedIndex + 1;
ScrollIntoView(SelectedItem, this.Columns[0]);
}
private void SelectedIndexDecrement()
{
int index = SelectedIndex;
if (index >= 0)
{
SelectedIndex--;
}
else if (index == -1)
{
SelectedIndex = Items.Count - 1;
}
ScrollIntoView(SelectedItem, this.Columns[0]);
}
public void HandleKeyDown(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Enter:
OnCommit(this, e);
e.Handled = true;
break;
case Key.Up:
IgnoreAnySelection = false;
SelectedIndexDecrement();
e.Handled = true;
break;
case Key.Down:
if ((ModifierKeys.Alt & Keyboard.Modifiers) == ModifierKeys.None)
{
IgnoreAnySelection = false;
SelectedIndexIncrement();
e.Handled = true;
}
break;
case Key.Escape:
OnCancel(this, e);
e.Handled = true;
break;
default:
break;
}
}
private void OnCommit(object sender, RoutedEventArgs e)
{
RoutedEventHandler handler = Commit;
if (handler != null)
{
handler(sender, e);
}
AfterAdapterAction();
}
private void OnCancel(object sender, RoutedEventArgs e)
{
RoutedEventHandler handler = Cancel;
if (handler != null)
{
handler(sender, e);
}
AfterAdapterAction();
}
private void AfterAdapterAction()
{
IgnoringSelectionChanged = true;
SelectedItem = null;
SelectedIndex = -1;
IgnoringSelectionChanged = false;
// Reset, to ignore any future changes
IgnoreAnySelection = true;
}
public AutomationPeer CreateAutomationPeer()
{
return new DataGridAutomationPeer(this);
}
}
}
※DataGrid中嵌入AutoCompleteBox
主要用到的方法是使用DataGrid组件中的DataGridTemplateColumn标签。
完整的实例代码:
详细的说明在代码注释中给出。
MainPage.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"
xmlns:samples="clr-namespace:SilverlightClient"
mc:Ignorable="d" xmlns:input="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input" xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data" x:Class="SilverlightClient.MainPage"
d:DesignWidth="320" d:DesignHeight="480">
<Grid x:Name="LayoutRoot" Width="320" Height="480" Background="White">
<Grid.Resources>
<!--AutoCompleteBox组件数据网格样式设定-->
<Style x:Key="DataGridAutoCompleteTemplate" TargetType="input:AutoCompleteBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="input:AutoCompleteBox">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="PopupStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2" To="PopupOpened" />
<VisualTransition GeneratedDuration="0:0:0.2" To="PopupClosed" />
</VisualStateGroup.Transitions>
<VisualState x:Name="PopupOpened">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PopupBorder" Storyboard.TargetProperty="Opacity" To="1.0" />
</Storyboard>
</VisualState>
<VisualState x:Name="PopupClosed">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="PopupBorder" Storyboard.TargetProperty="Opacity" To="0.0" />
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<TextBox IsTabStop="True" x:Name="Text" Margin="0" />
<Popup x:Name="Popup">
<Border x:Name="PopupBorder" HorizontalAlignment="Stretch" Opacity="0.0" BorderThickness="0" CornerRadius="3">
<Border.RenderTransform>
<TranslateTransform X="2" Y="2" />
</Border.RenderTransform>
<Border.Background>
<SolidColorBrush Color="#11000000" />
</Border.Background>
<Border HorizontalAlignment="Stretch" BorderThickness="0" CornerRadius="3">
<Border.Background>
<SolidColorBrush Color="#11000000" />
</Border.Background>
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform X="-1" Y="-1" />
</TransformGroup>
</Border.RenderTransform>
<Border HorizontalAlignment="Stretch" Opacity="1.0" Padding="1" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="3">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform />
<SkewTransform />
<RotateTransform />
<TranslateTransform X="-2" Y="-2" />
</TransformGroup>
</Border.RenderTransform>
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFDDDDDD" Offset="0"/>
<GradientStop Color="#AADDDDDD" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<!--为DataGridSelectionAdapter绑定数据字段-->
<samples:DataGridSelectionAdapter
x:Name="SelectionAdapter"
AutoGenerateColumns="False"
IsReadOnly="True" FontSize="14">
<samples:DataGridSelectionAdapter.Columns>
<data:DataGridTextColumn Header="员工号" Binding="{Binding EmployeeID}" />
<data:DataGridTextColumn Header="员工姓名" Binding="{Binding EmployeeName}" />
<data:DataGridTextColumn Header="员工年龄" Binding="{Binding EmployeeAge}" />
</samples:DataGridSelectionAdapter.Columns>
</samples:DataGridSelectionAdapter>
</Border>
</Border>
</Border>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Grid.Resources>
<input:AutoCompleteBox x:Name="acb" Height="26" Margin="8,32,132,0" VerticalAlignment="Top" Style="{StaticResource DataGridAutoCompleteTemplate}" ValueMemberBinding="{Binding EmployeeName}"/>
<data:DataGrid x:Name="dgEmployee" Height="209" Margin="8,0,8,8" VerticalAlignment="Bottom" AutoGenerateColumns="False" FontSize="14">
<data:DataGrid.Columns>
<data:DataGridTextColumn Header="员工号" Binding="{Binding EmployeeID}" IsReadOnly="True" />
<data:DataGridTemplateColumn Header="员工姓名" Width="90">
<!--设置AutoCompleteBox模板-->
<data:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding EmployeeName,Mode=TwoWay}"/>
</DataTemplate>
</data:DataGridTemplateColumn.CellTemplate>
<data:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<input:AutoCompleteBox x:Name="embeddedACB" Text="{Binding EmployeeName,Mode=TwoWay}" ValueMemberPath="EmployeeName" Loaded="embeddedACB_Loaded" Width="90">
<input:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding EmployeeName}"/>
</DataTemplate>
</input:AutoCompleteBox.ItemTemplate>
</input:AutoCompleteBox>
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
<data:DataGridTextColumn Header="员工年龄" Binding="{Binding EmployeeAge,Mode=TwoWay}" />
</data:DataGrid.Columns>
</data:DataGrid>
</Grid>
</UserControl>
MainPage.xaml.cs文件代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Common;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
namespace SilverlightClient
{
//业务对象类
public class Employees
{
public int EmployeeID { get; set; }
public string EmployeeName { get; set; }
public int EmployeeAge { get; set; }
}
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
//注册事件触发
this.Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
//为AutoCompleteBox和DataGrid填充数据
acb.ItemsSource = GetEmployees();
acb.FilterMode = AutoCompleteFilterMode.Contains;
dgEmployee.ItemsSource = GetEmployees();
}
//为DataGrid组件中的AutoCompleteBox组件提供数据
void embeddedACB_Loaded(object sender, RoutedEventArgs e)
{
AutoCompleteBox myacb = sender as AutoCompleteBox;
myacb.ItemsSource = GetEmployees();
}
//数据源
ObjectCollection GetEmployees()
{
ObjectCollection returnedValue = new ObjectCollection();
returnedValue.Add(new Employees() { EmployeeID = 1, EmployeeName = "Alice", EmployeeAge = 21 });
returnedValue.Add(new Employees() { EmployeeID = 2, EmployeeName = "Allen", EmployeeAge = 22 });
returnedValue.Add(new Employees() { EmployeeID = 3, EmployeeName = "Benedict", EmployeeAge = 23 });
returnedValue.Add(new Employees() { EmployeeID = 4, EmployeeName = "Ben", EmployeeAge = 24 });
returnedValue.Add(new Employees() { EmployeeID = 5, EmployeeName = "Black", EmployeeAge = 25 });
returnedValue.Add(new Employees() { EmployeeID = 6, EmployeeName = "Charles", EmployeeAge = 26 });
returnedValue.Add(new Employees() { EmployeeID = 7, EmployeeName = "Chasel", EmployeeAge = 27 });
returnedValue.Add(new Employees() { EmployeeID = 8, EmployeeName = "Dave", EmployeeAge = 28 });
returnedValue.Add(new Employees() { EmployeeID = 9, EmployeeName = "David", EmployeeAge = 29 });
returnedValue.Add(new Employees() { EmployeeID = 10, EmployeeName = "Dean", EmployeeAge = 30 });
return returnedValue;
}
}
}
最终效果图:
文章出处:Kinglee’s Blog (http://www.cnblogs.com/Kinglee/)
版权声明:本文的版权归作者与博客园共有。转载时须注明本文的详细链接,否则作者将保留追究其法律责任。