Binding a wpf listview to a Dataset…Possible..?

2020-07-17 16:32发布

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;

4条回答
霸刀☆藐视天下
2楼-- · 2020-07-17 16:58

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楼-- · 2020-07-17 17:14

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" />

查看更多
叼着烟拽天下
4楼-- · 2020-07-17 17:18

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.

查看更多
小情绪 Triste *
5楼-- · 2020-07-17 17:24

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.

查看更多
登录 后发表回答