轉(zhuǎn)帖|其它|編輯:郝浩|2011-03-25 16:26:57.000|閱讀 1406 次
概述:本文介紹為silverlight DataGrid增加AutoCompleteBox列的兩種方法,眾所周知DataGrid有個(gè)模板列 (DataGridTempleteColumn)列,其功能非常強(qiáng)大,在模板列中基本上什么組件都可以放,因此我們不難想到用模板列很容易就可以實(shí)現(xiàn). 下面展示模板列的方式的幾個(gè)步驟。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門(mén)軟控件火熱銷(xiāo)售中 >>
本文介紹為silverlight DataGrid增加AutoCompleteBox列的兩種方法,眾所周知DataGrid有個(gè)模板列(DataGridTempleteColumn)列,其功能非常強(qiáng)大,在模板列中基本上什么組件都可以放,因此我們不難想到用模板列很容易就可以實(shí)現(xiàn).下面展示模板列的方式的幾個(gè)步驟:
1.在Resource中定義AutoCompleteBox的ItemTemplate,定義下拉列表中的每一項(xiàng)的顯示方式及其內(nèi)容.
<data:DataGrid.Resources>
<DataTemplate x:Name="currencyDataTemplate">
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</data:DataGrid.Resources>
2.定義AutoCompleteBox的數(shù)據(jù)源
<data:DataGrid.Resources>
<riaControls:DomainDataSource x:Key=
"currencyDomainDataSource" AutoLoad="True"
d:DesignData="{d:DesignInstance models:Currency, CreateList=true}" Height="0"
LoadedData= "currencyDomainDataSource_LoadedData"
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}}"
ValueMemberPath= "Name" ItemTemplate=
"{StaticResource currencyDataTemplate}" />
</DataTemplate>
</data:DataGridTemplateColumn.CellEditingTemplate>
</data:DataGridTemplateColumn>
3.如果需要,實(shí)現(xiàn)轉(zhuǎn)換器類(lèi),實(shí)現(xiàn)IValueConverter接口,binding表達(dá)式中指定轉(zhuǎn)換器
在上面例子中數(shù)據(jù)源的CurrencyID對(duì)應(yīng)Currency的ID字段,用戶輸入時(shí)輸入Currency的Name字段,因此需要ID和Name之間進(jìn)行轉(zhuǎn)換.
public class CurrencyValueConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
//這里實(shí)現(xiàn)轉(zhuǎn)換成Name
return value;
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
//這里實(shí)現(xiàn)從Name轉(zhuǎn)換成ID
return value;
}
#endregion
4.在Resouces中聲明Converter
5.修改binding語(yǔ)句指定Converter及其Convert的參數(shù)等信息.
經(jīng)過(guò)以上步驟基本完成了AutoCompleteBox列增加.
上述方法有以下問(wèn)題:
1.步驟比較多
2.為每個(gè)使用到AutoCompleteBox列的地方都要以上處理,重復(fù)工作較多
3.為每個(gè)類(lèi)似Key,Value的轉(zhuǎn)換都要寫(xiě)個(gè)Converter類(lèi)
那么我們能否寫(xiě)個(gè)類(lèi)似DataGridTextColumn的DataGridAutoCompleteColumn類(lèi),通過(guò)簡(jiǎn)單的綁定就可以完成以上工作呢?答案肯定是可以的.
下面讓我們來(lái)動(dòng)手實(shí)現(xiàn)這個(gè)DataGridAutoCompleteColumn吧!
設(shè)計(jì)DataGridAutoCompleteColumn類(lèi)面臨幾個(gè)問(wèn)題:
1.為我們的DataGridAutoCompleteColumn選擇一個(gè)合適的基類(lèi),并重寫(xiě)相應(yīng)的方法
2.實(shí)現(xiàn)一個(gè)通用的轉(zhuǎn)換器,完成Key,Value的映射
解決方法:
對(duì)于第一個(gè)問(wèn)題我們選擇DataGridBoundColumn類(lèi)做為基類(lèi),重寫(xiě)GenerateElement,GenerateEditingElement,CancelCellEdit,PrepareCellForEdit等方法.
對(duì)于第二個(gè)問(wèn)題我們指定ValueMemberPath,DisplayMemberPath,利用反射機(jī)制來(lái)實(shí)現(xiàn)這兩個(gè)字段間的映射即可。下面是我實(shí)現(xiàn)的代碼:
DataGridAutoCompleteColumn實(shí)現(xiàn)代碼:
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)//如果沒(méi)指定轉(zhuǎn)換器,指定通用轉(zhuǎn)換器來(lái)轉(zhuǎn)
{
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 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 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 a DependencyProperty as the backing store for ItemTemplate.
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 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 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 =
this.ItemsSource;
}
}
#endregion
}
DataGridAutoCompleteColumnConverter類(lèi)實(shí)現(xiàn)代碼:
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類(lèi)基本開(kāi)發(fā)完成.
使用時(shí)我們只需要以下聲明就可以:
<local:DataGridAutoCompleteColumn x:Name="currencyColumn"
Binding="{Binding Path=CurrencyID}"
ItemsSource= "{Binding Source=
{StaticResource currencyDomainDataSource},Path=Data}"
ValueMemberPath= "ID" DisplayMemberPath="Name"
Header="Name" Width="SizeToHeader"/>
當(dāng)然在Resource里面還是要定義ItemsSource的數(shù)據(jù)源的。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載