Es un poco más difícil de hacer lo que estamos tratando de hacer lo que yo prefiero, pero eso es debido a que en realidad no se unen directamente una a una DataGrid
DataTable
.
Cuando enlaza DataGrid.ItemsSource
a DataTable
, realmente lo vincula al valor predeterminado DataView
, no a la tabla en sí. Esta es la razón por la cual, por ejemplo, no tiene que hacer nada para crear filas DataGrid
al hacer clic en el encabezado de una columna: esa funcionalidad está cocida en DataView
y DataGrid
sabe cómo acceder a ella (a través de la interfaz IBindingList
).
El DataView
implementa IEnumerable<DataRowView>
(más o menos), y el DataGrid
llena sus elementos iterando sobre esto. Esto significa que cuando haya vinculado DataGrid.ItemsSource
a DataTable
, su propiedad SelectedItem
será DataRowView
, no DataRow
.
Si sabes todo esto, es bastante sencillo crear una clase contenedora que te permita exponer las propiedades a las que puedes vincular. Hay tres propiedades fundamentales:
Table
, la DataTable
,
- , una de dos vías de propiedad enlazable de tipo
DataRowView
y
SearchText
, una propiedad de cadena que, cuando está activada, se encuentra el primero haciendo coincidir DataRowView
en la vista predeterminada de la tabla, establezca la propiedad y suba PropertyChanged
.
Parece que este:
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; }
}
Y aquí es XAML que lo utiliza:
<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>
¿Está utilizando WPF Toolkit DataGrid? – jsmith
@jsmith Sí, ese es el que estoy usando. –