dunkleosteus
dunkleosteus

Reputation: 336

Binding DataTables to Datagrids on a WPF Tabcontrol

I have a wpf TabControl and a ListBox. If I click on one of the items in the ListBox I want to get data from a certain table on an SQL Server, add a new tab to the TabControl and display the data on a DataGrid on this new tab. So far I have this:

XAML for the TabControl and the ListBox:

 <Grid>
    <ListBox x:Name="lb"  ItemsSource="{Binding Alltables}" MouseDoubleClick="opendata"/>

    <TabControl x:Name="tabControl"  ItemsSource="{Binding SelectedTables}">
        <TabControl.ContentTemplate >
            <DataTemplate >
                <Grid>
                    <DataGrid x:Name="dataGrid" AutoGenerateColumns="True" ItemsSource="{Binding Tablecontent}"/>                  
                </Grid>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Grid>

My ViewModel:

   public class MainViewModel : INotifyPropertyChanged
    {

        public event PropertyChangedEventHandler PropertyChanged;

        public void OnPropertyChanged(string name)
        {

            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }

        }

        private ObservableCollection<String> selectedtables;
    public ObservableCollection<String> SelectedTables
    {
        get { return selectedtables; }
        set
        {
            if (selectedtables != value)
            {

                selectedtables = value;
                OnPropertyChanged("SelectedTables");
            }
        }
    }

    private ObservableCollection<DataTable> tablecontent;
    public ObservableCollection<DataTable> Tablecontent
    {
        get { return tablecontent; }
        set
        {
            if (tablecontent != value)
            {
                tablecontent = value;
                OnPropertyChanged("Tablecontent");
            }
        }
    }

}

The click event for the ListBox:

   private void opendata(object sender, MouseButtonEventArgs e)
    {
//...
 //Some preparations before querying the data etc.
//...

   DataTable mydata = new DataTable();

        using (connection = new SqlConnection(connectionString))
        {
            SqlCommand command = new SqlCommand(queryString, connection);
            command.Connection.Open();
            SqlDataReader reader = command.ExecuteReader();
            mydata.Load(reader);
        }  

        string tabletoload = lb.SelectedItem.ToString();

        myview2.SelectedTables.Add(tabletoload); //myview2 is the instance of my ViewModel

        myview2.Tablecontent.Add(mydata); //myview2 is the instance of my ViewModel
    }
}

What happens now is that when I click on one of the items in the ListBox there is correctly a new tab created with the text of the selected ListBox Item as Header and also a DataGrid - however the DataGrid remains empty.

Would be really amazing if you could help me. I have looked through all the similar questions here on SO but none of the solutions seems to solve my issue. If I don't use a tab control and simply add a DataGrid directly on the form everything works perfectly. Also creating and adding everything directly in code works fine but I would like to solve this in a more correct way.

Upvotes: 1

Views: 320

Answers (1)

mm8
mm8

Reputation: 169200

SelectedTables should return an IEnumerable<T> where the type T defines the name and the DataTable for the current tab:

public class TabViewModel
{
    public string Header { get; set; }
    public DataTable Tablecontent { get; set; }
}

public class MainViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    private ObservableCollection<TabViewModel> selectedtables;
    public ObservableCollection<TabViewModel> SelectedTables
    {
        get { return selectedtables; }
        set
        {
            if (selectedtables != value)
            {

                selectedtables = value;
                OnPropertyChanged("SelectedTables");
            }
        }
    }
}

You would then add a new T (named TabViewModel in the sample code above) to the MainViewModel in your opendata method:

string tabletoload = lb.SelectedItem.ToString();
myview2.SelectedTables.Add(new TabViewModel() { Header = tabletoload, Tablecontent = mydata });

...and define an ItemTemplate for the TabControl in the view to display the header:

<TabControl x:Name="tabControl"  ItemsSource="{Binding SelectedTables}">
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Header}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
    <TabControl.ContentTemplate >
        <DataTemplate >
            <Grid>
                <DataGrid x:Name="dataGrid" AutoGenerateColumns="True" ItemsSource="{Binding Tablecontent}"/>
            </Grid>
        </DataTemplate>
    </TabControl.ContentTemplate>
</TabControl>

Upvotes: 2

Related Questions