问题
I was struggling moving to Wpf,I am just stuck while trying out databinding to a lsitview.I want to databind a listview to a dataset(dataset because the data i want to display in columns belongs to different tables).I am attaching a sample code that i am trying with.It works alright but the listliew only shows one row.What could be wrong.Can anyone guide me through.All the samples available are using datatables.None specifies about binding to a dataset.Pls help..any input will be highly appreciated...thanks in advance
My Xaml
<Grid>
<TextBox Text="" Height="20" Width="100" HorizontalAlignment="Left" Margin="15,13,0,0" VerticalAlignment="Top"></TextBox>
<TextBox Text="" Height="20" Width="100" HorizontalAlignment="Left" Margin="15,42,0,0" VerticalAlignment="Top"></TextBox>
<ListView Margin="15,89,63,73" Name="lst" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=T1/Name}"></GridViewColumn>
<GridViewColumn Header="Place" DisplayMemberBinding="{Binding Path=T2/Name}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<!--<Button Height="19" HorizontalAlignment="Right" Name="button2" VerticalAlignment="Top" Width="46" Margin="0,42,63,0" Click="button2_Click">Add</Button>-->
<Button Height="19" HorizontalAlignment="Right" Name="button1" VerticalAlignment="Top" Width="46" Click="button1_Click" Margin="0,43,63,0">Add</Button>
My Code
Dt1 = new DataTable("T1");
Dt1.Columns.Add("Name");
Dt1.Rows.Add("abc1");
Dt1.Rows.Add("abc2");
Dt2 = new DataTable("T2");
Dt2.Columns.Add("Name");
Dt2.Rows.Add("xyz1");
Dt2.Rows.Add("xyz1");
Ds = new DataSet();
Ds.Tables.Add(Dt1);
Ds.Tables.Add(Dt2);
lst.DataContext = Ds;
回答1:
Hi am in full accord with Andy and Thomas. They both have explained the concept elegantly.
I am only showing the steps of doing the same only with dataset.
The MVVM (ModelView ViewModel) I am not discussing here.
The Xaml looks like this
<Grid Name="myGrid" ShowGridLines="False">
<Label Height="28" Margin="12,5,0,0" Name="lblName" VerticalAlignment="Top" HorizontalAlignment="Left" Width="55">Name</Label>
<TextBox Height="23" Margin="73,8,85,0" Name="txtName" VerticalAlignment="Top" />
<Label Height="28" Margin="12,39,0,0" Name="lblPlace" VerticalAlignment="Top" HorizontalAlignment="Left" Width="55">Place</Label>
<TextBox Height="23" Margin="73,44,85,0" Name="txtPlace" VerticalAlignment="Top" />
<Button Height="23" HorizontalAlignment="Left" Margin="20,82,0,0" Name="btnAddRecord" VerticalAlignment="Top" Width="75" Click="btnAddRecord_Click">Add Record</Button>
<ListView Margin="31,119,27,45" Name="listView" *ItemsSource="{Binding}"*>
<ListView.View>
<GridView>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
<GridViewColumn Header="Place" DisplayMemberBinding="{Binding Place}"/>
</GridView>
</ListView.View>
</ListView>
</Grid>
In the .CS file create a dataset
private DataSet MyDataSet()
{
DataTable dtInformation1 = new DataTable();
dtInformation1.Columns.Add("Name");
dtInformation1.Columns.Add("Place");
dtInformation1.Rows.Add(txtName.Text, txtPlace.Text);
DataTable dtInformation2 = new DataTable();
dtInformation2.Columns.Add("Name");
dtInformation2.Columns.Add("Place");
dtInformation2.Rows.Add(txtName.Text + "2", txtPlace.Text + "2");
DataSet Ds = new DataSet();
Ds.Tables.Add(dtInformation1);
Ds.Tables.Add(dtInformation2);
return Ds;
}
Next in the Button's click event write the following
private void btnAddRecord_Click(object sender, RoutedEventArgs e)
{
**listView.ItemsSource = MyDataSet().Tables[0].DefaultView;
- OR -
listView.ItemsSource = MyDataSet().Tables[1].DefaultView;**
}
N.B.~ You cannot assign the source of the ListView a dataset.
Why ? You may ask? A dataset, in simple terms , is a collection of data tables.
Suppose you have 5 different datatables. And say none of their column names as well as column numbers are same.
Now you have assigned all those to your dataset. How will the controls source know that which source it has to bind?
Inorder to overcome such a situation, either make a custom datatable that will have all the columns of those discreet datatables and assign the values to this custom one and then bind to the source.
Or you need to explicitly specify the datatable in the datasource
But I always prefer to use MVVM pattern for this kind of operations.
回答2:
I'm not sure what you're trying to do here... Is that the result you expect ?
abc1 xyz1
abc2 xyz2
There is no relation between your tables, so the binding system can't guess which row of T1 you want to associate with which row of T2... You should either put all data in the same table, or use a DataRelation between the two tables (but that would require extra fields for the join). You would then set the DataTable as the ItemsSource, not the DataSet.
Alternatively, you could create a dedicated class to hold the data, as suggested by Andy
回答3:
WPF Binding works off of properties. For example, consider the following Person
object:
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
You could then modify the XAML for your ListView
to display a collection of Person
objects by doing the following:
<ListView Margin="15,89,63,73" Name="lst" ItemsSource="{Binding}">
<ListView.View>
<GridView>
<GridViewColumn Header="First Name"
DisplayMemberBinding="{Binding Path=FirstName}" />
<GridViewColumn Header="Last Name"
DisplayMemberBinding="{Binding Path=LastName}" />
</GridView>
</ListView.View>
</ListView>
This will display the object's first name in the first column, and their last name in the second column (assuming that the DataContext
of the ListView
is a collection of Person
objects).
In theory, to bind the values in a DataTable
to a ListView
, you could set the ItemsSource
to the DataTable
's Rows
property. The problem becomes that the DataRow
class doesn't expose properties for its columns - there is only the Item
property that takes an argument specifying the row. To my knowledge, XAML does not support properties that take arguments, so I don't think that it is possible to use a DataTable
as the ItemsSource
for a ListView
.
You do have some other options, however. You could create a strongly typed DataSet
, which would expose a DataTable
with a property for each column. You can then bind each GridViewColumn
to the correct property.
Another approach would be to not use a DataTable
at all. Your data layer would still load the data from your source into the DataTable
, but it would then convert that data into normal objects. You could create an instance of ObservableCollection, add each of the objects into it, and then bind the ListView
to that. Each GridViewColumn
would just bind to the corresponding property of the objects.
Updated:
In answer to OP's further question:
Can I use the xsd for the purpose?.It holds a property for each datatable..
You need more than just a property for a DataTable. You'd also need a property for each value in each row of the DataTable. Otherwise there is no property for the ListView's columns to bind to.
回答4:
This worked for me.
public partial class MainWindow : Window
{
public ObservableCollection<DataTable> _observableCollection =
new ObservableCollection<DataTable>();
public MainWindow()
{
InitializeComponent();
DataTable dt1 = new DataTable();
dt1.Columns.Add("OrderID");
dt1.Columns.Add("CustomerID");
dt1.Columns.Add("ProductID");
dt1.Rows.Add("test1", "test2", "test3");
DataTable dt2 = new DataTable();
dt2.Columns.Add("OrderID");
dt2.Columns.Add("CustomerID");
dt2.Columns.Add("ProductID");
dt2.Rows.Add("test4", "test5", "test6");
_observableCollection.Add(dtInformation1);
_observableCollection.Add(dtInformation2);
}
public ObservableCollection<DataTable> _Collection
{ get { return _observableCollection; } }
ListView XAML
<ListView Height="Auto"
HorizontalAlignment="Stretch"
Name="somename"
ItemsSource="{Binding _Collection}" VerticalAlignment="Stretch" Width="Auto" >
<GridViewColumn Header="OrderID" Width="auto" >
<GridViewColumn.CellTemplate>
<DataTemplate>
<Button Tag="{Binding OrderID}" Content="{Binding OrderID}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Width="auto" DisplayMemberBinding="{Binding CustomerID}" Header="CustomerID" />
<GridViewColumn Width="auto" DisplayMemberBinding="{Binding ProductID}" Header="ProductID" />
来源:https://stackoverflow.com/questions/961877/binding-a-wpf-listview-to-a-dataset-possible