彩票走势图

Silverlight DataGrid中增加AutoCompleteBox列的方法

转帖|其它|编辑:郝浩|2011-03-25 16:26:57.000|阅读 1383 次

概述:本文介绍为silverlight DataGrid增加AutoCompleteBox列的两种方法,众所周知DataGrid有个模板列 (DataGridTempleteColumn)列,其功能非常强大,在模板列中基本上什么组件都可以放,因此我们不难想到用模板列很容易就可以实现. 下面展示模板列的方式的几个步骤。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

  本文介绍为silverlight DataGrid增加AutoCompleteBox列的两种方法,众所周知DataGrid有个模板列(DataGridTempleteColumn)列,其功能非常强大,在模板列中基本上什么组件都可以放,因此我们不难想到用模板列很容易就可以实现.下面展示模板列的方式的几个步骤:

  1.在Resource中定义AutoCompleteBox的ItemTemplate,定义下拉列表中的每一项的显示方式及其内容.

<data:DataGrid.Resources>  

<DataTemplate x:Name="currencyDataTemplate">  

 <TextBlock Text="{Binding Path=Name}"/>&nbsp; 

</DataTemplate>  

</data:DataGrid.Resources>  

  2.定义AutoCompleteBox的数据源

<data:DataGrid.Resources>
  <riaControls:DomainDataSource x:Key=

"currencyDomainDataSource" AutoLoad="True" 
d:DesignData="{d:DesignInstance models:Currency, CreateList=true}" Height="0" 
  LoadedData= "currencyDomainDataSource_LoadedData&quot; 

Name="currencyDomainDataSource" 
QueryName= "GetCurrenciesQuery" Width="0">
  <riaControls:DomainDataSource.DomainContext>
  <services:MtsDomainContext />
     </riaControls:DomainDataSource.DomainContext>
  </riaControls:DomainDataSource>

      <DataTemplate x:Name="currencyDataTemplate">
         <TextBlock Text="{Binding Path=Name}"/>
      </DataTemplate>
                
  </data:DataGrid.Resources>

  2.定义DataGridTemplateColumn字段

<data:DataGridTemplateColumn x:Name="currencyColumn" 

Header="Currency" Width="SizeToHeader">  
     <data:DataGridTemplateColumn.CellTemplate>  
         <DataTemplate>  
  <TextBlock Text=";{Binding Currency}" VerticalAlignment=

"Center" Margin="3"/>  
         </DataTemplate>  
     </data:DataGridTemplateColumn.CellTemplate>  
     <data:DataGridTemplateColumn.CellEditingTemplate>  
         <DataTemplate>  
             <input:AutoCompleteBox x:Name="currencyAutoComplete" Text="{Binding Path=CurrencyID,Mode=TwoWay}"                                                       
  ItemsSource= "{Binding Path=Data,Source=

{StaticResource currencyDomainDataSource}}"  
&nbsp; ValueMemberPath= "Name&quot; ItemTemplate=

"{StaticResource currencyDataTemplate}" />    
         </DataTemplate>  
     </data:DataGridTemplateColumn.CellEditingTemplate>  
</data:DataGridTemplateColumn>  ;

  3.如果需要,实现转换器类,实现IValueConverter接口,binding表达式中指定转换器

  在上面例子中数据源的CurrencyID对应Currency的ID字段,用户输入时输入Currency的Name字段,因此需要ID和Name之间进行转换.

 public class CurrencyValueConverter : IValueConverter
     {

         #region IValueConverter Members
        
         public object Convert(object&nbsp;value, Type targetType, 

object parameter, System.Globalization.CultureInfo culture)
         {
             //这里实现转换成Name
             return value;            
         }

  public object ConvertBack(object value, Type targetType, 

object parameter, System.Globalization.CultureInfo culture)
         {
             //这里实现从Name转换成ID
             return value;
         }

    ;     #endregion

  4.在Resouces中声明Converter

  1. <helper:CurrencyValueConverter x:Key="currencyValueConverter"/>  

  5.修改binding语句指定Converter及其Convert的参数等信息.

  1. Text="{Binding Path=CurrencyID,Mode=TwoWay,Converter={StaticResource currencyValueConverter}}"  

  经过以上步骤基本完成了AutoCompleteBox列增加.

  上述方法有以下问题:

  1.步骤比较多

  2.为每个使用到AutoCompleteBox列的地方都要以上处理,重复工作较多

  3.为每个类似Key,Value的转换都要写个Converter类

  那么我们能否写个类似DataGridTextColumn的DataGridAutoCompleteColumn类,通过简单的绑定就可以完成以上工作呢?答案肯定是可以的.

  下面让我们来动手实现这个DataGridAutoCompleteColumn吧!

  设计DataGridAutoCompleteColumn类面临几个问题:

  1.为我们的DataGridAutoCompleteColumn选择一个合适的基类,并重写相应的方法

  2.实现一个通用的转换器,完成Key,Value的映射

  解决方法:

  对于第一个问题我们选择DataGridBoundColumn类做为基类,重写GenerateElement,GenerateEditingElement,CancelCellEdit,PrepareCellForEdit等方法.

  对于第二个问题我们指定ValueMemberPath,DisplayMemberPath,利用反射机制来实现这两个字段间的映射即可。下面是我实现的代码:

DataGridAutoCompleteColumn实现代码:

public class DataGridAutoCompleteColumn : DataGridBoundColumn
     {
   public DataGridAutoCompleteColumn()
         {
     //this.DefaultStyleKey = typeof(DataGridAutoCompleteColumn);  
  //this._converter = new DataGridAutoCompleteColumnConverter(this);  
            
         }

   public override System.Windows.Data.Binding Binding
         {
             get
             {
                 return base.Binding;
             }
             set
             {
                 if (value != null)
                 {
  if (value.Converter == null)//如果没指定转换器,指定通用转换器来转
                     {
     value.Converter = new DataGridAutoCompleteColumnConverter();
                     }                    
                 }

                 base.Binding = value;
             }
         }

         private IValueConverter Converter
         {
             get 
             {
                 if (this.Binding != null)
                 {
                     return this.Binding.Converter;
                 }
                 return null;
             }
             //set { this._converter = value; }
         }

  protected override FrameworkElement&nbsp;GenerateElement

(DataGridCell cell, object dataItem)
         {
             //throw new NotImplementedException();
            
             TextBlock block = new TextBlock();
             block.Margin = new Thickness(4.0);
             block.VerticalAlignment = VerticalAlignment.Center;
            
             if ((this.Binding != null) || !DesignerProperties.IsInDesignTool)
             {
    block.SetBinding(TextBlock.TextProperty, this.Binding);
             }
             return block;

         }

  protected override FrameworkElement GenerateEditingElement

(DataGridCell cell, object dataItem)
         {
             AutoCompleteBox box = new AutoCompleteBox();
             box.VerticalAlignment = VerticalAlignment.Center;

   box.Background = new SolidColorBrush(Colors.Transparent);


  if ((this.Binding != null) || !DesignerProperties.IsInDesignTool)
             {
                 box.ItemsSource = this.ItemsSource;
   DataTemplate itemTemplate = this.ItemTemplate;
   if (itemTemplate == null  && !String.IsNullOrEmpty(this.DisplayMemberPath))
                 {
  string xaml =  "<DataTemplate xmlns=

\"//schemas.microsoft.com/winfx/2006/xaml/presentation\"> 
<TextBlock Text=\"{Binding Path=" +
      this.DisplayMemberPath +  "}\" /> </DataTemplate>";
    itemTemplate = (DataTemplate)XamlReader.Load(xaml);
                 }

                 box.ItemTemplate = itemTemplate;
                
                 if (!String.IsNullOrEmpty(DisplayMemberPath))
                 {
                     Binding valueBinding = new Binding(this.DisplayMemberPath);                   
                     box.ValueMemberBinding = valueBinding;
                 }
                 else if (!String.IsNullOrEmpty(ValueMemberPath))
                 {
   box.ValueMemberPath = this.ValueMemberPath;
                 }

     box.SetBinding(AutoCompleteBox.TextProperty, this.Binding);
                 //box.SetBinding(base.BindingTarget, this.Binding);
             }

             return box;            
         }

  protected override void CancelCellEdit

(FrameworkElement editingElement, object uneditedValue)
         {
             //base.CancelCellEdit(editingElement, uneditedValue);
             AutoCompleteBox box = editingElement as AutoCompleteBox;
             if (box != null)
             {
                 if (this.RequiredConverter)
                 {
   ;                  box.Text = (string)this.Converter.Convert(uneditedValue, typeof(string), 

null, System.Globalization.CultureInfo.CurrentCulture);
  }
                 else if(uneditedValue != null)
   {
    box.Text = uneditedValue.ToString();
                 }
             }
         }

  protected override&nbsp;object PrepareCellForEdit

(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
         {
   AutoCompleteBox box = editingElement as AutoCompleteBox;
             if (box != null)
             {
                 return box.Text;               
             }
             else
             {                
                 return string.Empty;
             }
   //return base.PrepareCellForEdit(editingElement, editingEventArgs);
         }

         private bool RequiredConverter
         {
             get
             {
                 return !String.IsNullOrEmpty(this.ValueMemberPath)
                     && !String.IsNullOrEmpty(this.DisplayMemberPath);
             }
         }               

         #region AutoComplete

         public string ValueMemberPath
         {
             get { return GetValue(ValueMemberPathProperty) as string; }
             set { SetValue(ValueMemberPathProperty, value); }
         }

         // Using a DependencyProperty as the backing store for ValueMemberPath.  

This enables animation, styling, binding, etc...
  public static readonly DependencyProperty ValueMemberPathProperty =
             DependencyProperty.Register( "ValueMemberPath", typeof(string), typeof(DataGridAutoCompleteColumn), 

new PropertyMetadata(null, OnMemberPathPropertyChanged));


         public string DisplayMemberPath
         {
             get { return GetValue(DisplayMemberPathProperty) as string; }
             set { SetValue(DisplayMemberPathProperty, value); }
         }

         // Using a DependencyProperty as the backing store for ;DisplayMemberPath. 

 This enables animation, styling, binding, etc...
         public static readonly DependencyProperty DisplayMemberPathProperty =
             DependencyProperty.Register( "DisplayMemberPath", typeof(string), typeof(DataGridAutoCompleteColumn), 

new PropertyMetadata(null, OnMemberPathPropertyChanged));

        
         public IEnumerable ItemsSource
         {
             get { return GetValue(ItemsSourceProperty) as IEnumerable; }
             set { SetValue(ItemsSourceProperty, value); }
         }

         // Using ;a DependencyProperty as the backing store for ItemsSource.  

This enables animation, styling, binding, etc...
         public static readonly DependencyProperty ItemsSourceProperty =
             DependencyProperty.Register( "ItemsSource", typeof(IEnumerable),
  typeof(DataGridAutoCompleteColumn), new PropertyMetadata

(null, OnItemsSourcePropertyChanged));


         public DataTemplate ItemTemplate
         {
             get { return GetValue(ItemTemplateProperty) as DataTemplate; }
             set { SetValue(ItemTemplateProperty, value); }
         }

         // Using&nbsp;a DependencyProperty as the backing store for ItemTemplate.&nbsp; 

This enables animation, styling, binding, etc...
         public static readonly DependencyProperty ItemTemplateProperty =
             DependencyProperty.Register( "ItemTemplate", typeof(DataTemplate), typeof(DataGridAutoCompleteColumn),

 new PropertyMetadata(null));

         private static void OnMemberPathPropertyChanged(DependencyObject&nbsp;d, 

DependencyPropertyChangedEventArgs e)
         {
  DataGridAutoCompleteColumn control = d as DataGridAutoCompleteColumn;
             if (control != null)
             {
                 control.OnMemberPathChanged();
             }
         }

        
         private void OnMemberPathChanged()
         {
             //set binding converter
          ;   DataGridAutoCompleteColumnConverter converter =

 this.Converter as DataGridAutoCompleteColumnConverter;
             if (converter != null)
             {
                 converter.ValueMember = this.ValueMemberPath;
                 converter.DisplayMember = this.DisplayMemberPath;   
             }
         }

         private static void&nbsp;OnItemsSourcePropertyChanged

(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
   DataGridAutoCompleteColumn control = d as DataGridAutoCompleteColumn;
             if (control != null)
             {
                 control.OnItemsSourceChanged();
             }
         }

         private void OnItemsSourceChanged()
         {
             IValueConverter converter = this.Converter;//this._converter as DataGridAutoCompleteColumnConverter;
  if (converter != null  && converter is DataGridAutoCompleteColumnConverter)
             {
  ((DataGridAutoCompleteColumnConverter)converter).ItemsSource =&nbsp;

this.ItemsSource;
             }
         }

         #endregion                     
     }

DataGridAutoCompleteColumnConverter类实现代码:

   class DataGridAutoCompleteColumnConverter : IValueConverter
     {
         private IEnumerable _itemsSource;
         private PropertyInfo _valuePropertyInfo;
         private PropertyInfo _displayPropertyInfo;
         private Type _elementType;
         private bool _initialized = false;

         public string DisplayMember { get; set; }

         public string ValueMember { get; set; }

         public IEnumerable ItemsSource
         {
             get { return this._itemsSource; }
             set
             {
                 this._itemsSource = value;
                 _initialized = false;
             }
         }

         private void Init()
         {
             if (_initialized) return;

    if (this.ItemsSource != null  && !String.IsNullOrEmpty(this.DisplayMember)
  && !String.IsNullOrEmpty(this.ValueMember))
             {
    IEnumerator enumrator = this.ItemsSource.GetEnumerator();
  enumrator.MoveNext();
                 object current = enumrator.Current;
                 Type type = current.GetType();
                 if (current != null)
     if (!String.IsNullOrEmpty(this.ValueMember))
     {
                         _valuePropertyInfo = type.GetProperty(this.ValueMember);
                     }
                     if (!String.IsNullOrEmpty(this.DisplayMember))
                     {
                         _displayPropertyInfo = type.GetProperty(this.DisplayMember);
                     }
                     _elementType = type;
                     _initialized = true;
                 }
                
             }
             else
             {
   this._valuePropertyInfo = null;
                 this._displayPropertyInfo = null;
             }
         }

     #region IValueConverter Members

         public object Convert(object value, Type targetType, object parameter,

 System.Globalization.CultureInfo culture)
         {
     if (String.IsNullOrEmpty(this.DisplayMember) 

&& String.IsNullOrEmpty(this.ValueMember))
                 return value;
             this.Init();

             if (this._displayPropertyInfo == null) return value;

             if (targetType == this._displayPropertyInfo.PropertyType)
             {
                 if (ItemsSource == null)
                     return value;

                 if (value.GetType() == this._elementType)
                 {
                     return this._displayPropertyInfo.GetValue(value, null);
                 }

                 object item = null;
                 foreach (object o in this.ItemsSource)
                 {
                     if (value.Equals(this._valuePropertyInfo.GetValue(o, null)))
                     {
                         item = o;
                         break;
                     }
                 }

                 if (item != null)
                 {
                     return this._displayPropertyInfo.GetValue(item, null);
                 }
             }
             return value;
         }

  public object ConvertBack(object value, Type targetType, object parameter, 

System.Globalization.CultureInfo culture)
         {
             this.Init();

             if(value == null)return value;

             if (this._displayPropertyInfo != null)
             {
                 object item = null;
                 foreach (object o in this.ItemsSource)
                 {
  if (value.Equals(this._displayPropertyInfo.GetValue(o, null)))
                     {
                         item = o;
                         break;
                     }
                 }

   if (item != null  && this._valuePropertyInfo != null)
                 {
                     return this._valuePropertyInfo.GetValue(item, null);
                 }
                 return item;
             }
   else if(this._valuePropertyInfo != null  && value.GetType() == this._elementType)           
             {
    return this._valuePropertyInfo.GetValue(value, null);
             }
             else
             {
                 if ((targetType != null)  && targetType.IsClass)
                 {
                     string str = value as string;
                     if (str == string.Empty)
                     {
                         return null;
                     }
                 }
                 return value;
             }
         }

         #endregion
     }

  到此我们的DataGridAutoCompleteColumn类基本开发完成.

  使用时我们只需要以下声明就可以:

<local:DataGridAutoCompleteColumn x:Name="currencyColumn"   
     Binding="{Binding Path=CurrencyID}"   
 &nbsp; ItemsSource= "{Binding Source=

{StaticResource currencyDomainDataSource},Path=Data}"   
  ValueMemberPath= "ID&quot; DisplayMemberPath="Name"

Header=&quot;Name" Width="SizeToHeader"/>

  当然在Resource里面还是要定义ItemsSource的数据源的。 


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:网络转载

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP