E 'un po' più complicato di fare ciò che si sta cercando di fare che preferisco, ma è perché non si ha realmente associare direttamente un DataGrid
ad un DataTable
.
Quando si associa DataGrid.ItemsSource
a DataTable
, lo si sta effettivamente vincolando al valore predefinito DataView
, non al tavolo stesso. Questo è il motivo per cui, ad esempio, non devi fare nulla per creare una riga di ordinamento DataGrid
quando fai clic sull'intestazione di una colonna - quella funzionalità viene infornata in DataView
e DataGrid
sa come accedervi (tramite l'interfaccia IBindingList
).
Gli strumenti DataView
IEnumerable<DataRowView>
(più o meno), e lo DataGrid
riempie i suoi elementi ripetendo su questo. Ciò significa che quando hai associato DataGrid.ItemsSource
a DataTable
, la sua proprietà SelectedItem
sarà DataRowView
, non DataRow
.
Se si conosce tutto questo, è abbastanza semplice creare una classe wrapper che consente di esporre le proprietà alle quali è possibile eseguire il binding. Ci sono tre proprietà fondamentali:
Table
, il DataTable
,
- , a due vie proprietà associabile di tipo
DataRowView
, e
SearchText
, una proprietà stringa che, quando è impostato, troveranno il prima corrispondenza DataRowView
nella vista predefinita della tabella, impostare la proprietà e aumentare PropertyChanged
.
Ecco come si presenta:
public class DataTableWrapper : INotifyPropertyChanged
{
private DataRowView _Row;
private string _SearchText;
public DataTableWrapper()
{
// using a parameterless constructor lets you create it directly in XAML
DataTable t = new DataTable();
t.Columns.Add("id", typeof (int));
t.Columns.Add("text", typeof (string));
// let's acquire some sample data
t.Rows.Add(new object[] { 1, "Tower"});
t.Rows.Add(new object[] { 2, "Luxor" });
t.Rows.Add(new object[] { 3, "American" });
t.Rows.Add(new object[] { 4, "Festival" });
t.Rows.Add(new object[] { 5, "Worldwide" });
t.Rows.Add(new object[] { 6, "Continental" });
t.Rows.Add(new object[] { 7, "Imperial" });
Table = t;
}
// you should have this defined as a code snippet if you work with WPF
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler h = PropertyChanged;
if (h != null)
{
h(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
// SelectedItem gets bound to this two-way
public DataRowView Row
{
get { return _Row; }
set
{
if (_Row != value)
{
_Row = value;
OnPropertyChanged("Row");
}
}
}
// the search TextBox is bound two-way to this
public string SearchText
{
get { return _SearchText; }
set
{
if (_SearchText != value)
{
_SearchText = value;
Row = Table.DefaultView.OfType<DataRowView>()
.Where(x => x.Row.Field<string>("text").Contains(_SearchText))
.FirstOrDefault();
}
}
}
public DataTable Table { get; private set; }
}
Ed ecco XAML che lo utilizza:
<Window x:Class="DataGridSelectionDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dg="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
xmlns:DataGridSelectionDemo="clr-namespace:DataGridSelectionDemo"
Title="DataGrid selection demo"
Height="350"
Width="525">
<Window.DataContext>
<DataGridSelectionDemo:DataTableWrapper />
</Window.DataContext>
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label>Text</Label>
<TextBox Grid.Column="1"
Text="{Binding SearchText, Mode=TwoWay}" />
</Grid>
<dg:DataGrid DockPanel.Dock="Top"
ItemsSource="{Binding Table}"
SelectedItem="{Binding Row, Mode=TwoWay}" />
</DockPanel>
</Window>
Si sta utilizzando il WPF Toolkit DataGrid? – jsmith
@jsmith Sì, è quello che sto usando. –