1

I am not that good in multithreading. But this is what I need to do.

I have a datagrid. I want one method to fill the datagrid with only first 50 rows. In the mean time I want a thread to fetch the next 20 rows and update the datatable so that when the 50 rows has been displayed the next 20 rows gets attached to the datatable object. In this way I can work huge amount of data without making my datatable go slow. But I am stuck with resource sharing (sharing the datatable object) in multithreading.

The have the code below

public partial class InsertAndUpdateData : Window
{
    DataTable dt = new DataTable();

    public object lockOn = new object();

    public InsertAndUpdateData()
    {
        InitializeComponent();
        Thread oThread = new Thread(new ParameterizedThreadStart(FillGrid));
        oThread.Start(dt);
        oThread.Join();

        Thread.Sleep(1000);
        oThread.Abort();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        string name = txtName.Text;
        int salary = Convert.ToInt32(txtSalary.Text);

        using (var context = new NewtonEntities())
        {
            Employee emp = new Employee();
            emp.name = name;
            emp.salary = salary;

            context.AddToEmployees(emp);
            context.SaveChanges();
        }

        FillGridLastRowInserted();
    }

    public void FillGrid(object dtx)
    {
        lock (lockOn)
        {
            dt = (DataTable)dtx;
            var db = new NewtonEntities();
            var dataTable = (from c in db.Employees
                             select new
                             {
                                 c.id,
                                 c.name,
                                 c.salary
                             }).Take(20);

            dt.Columns.Add("id", typeof(int));
            dt.Columns.Add("name", typeof(string));
            dt.Columns.Add("salary", typeof(int));

            foreach (var item in dataTable)
            {
                DataRow dr = dt.NewRow();
                dr["id"] = item.id;
                dr["name"] = item.name;
                dr["salary"] = item.salary;
                dt.Rows.Add(dr);
            }

            myGrid.ItemsSource = dt.DefaultView;
        }
    }

    public void FillGridLastRowInserted()
    {
        var db = new NewtonEntities();
        var dataTable = (from c in db.Employees
                         orderby c.id descending
                         select new
                         {
                             c.id,
                             c.name,
                             c.salary
                         }).First();

        DataRow dr = dt.NewRow();
        dr["id"] = dataTable.id;
        dr["name"] = dataTable.name;
        dr["salary"] = dataTable.salary;
        dt.Rows.Add(dr);

        myGrid.ItemsSource = dt.DefaultView;
    }
}

I have a datatable in the main class. I want the dt object to be shared by two threaded methods.

But every time I am hit with the following error.

enter image description here

Cœur
  • 37,241
  • 25
  • 195
  • 267

3 Answers3

0

The reason why you are not able to update the Itemsource is that the mygrid is owned by main thread and you cannot update controls present in main thread from a separate thread.

You should return a value from thread and then bind - Returning a value from thread?

If all you want to do is some background work , it is better for you to use BackgroundWorker http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

Community
  • 1
  • 1
Naresh Jois
  • 834
  • 11
  • 18
0

there is a simpler solution. you just need to utilize the WPF DataGrid virtualization.

Use Snoop to make sure your grid has virtualization on: http://snoopwpf.codeplex.com/

Boppity Bop
  • 9,613
  • 13
  • 72
  • 151
  • I still don't know how this tool is going help me. Just downloaded it and found it to be super-cool. Thanks Bobb. – Newton Sheikh Jan 31 '13 at 05:37
  • the tool is to make sure that the virtualization is on. when it is on you will find a control inside your grid called something like VirtualizationPanel... – Boppity Bop Jan 31 '13 at 05:53
  • hey bob I have never used this Virtualization thing. Just to make one thing clear, if I implement datagrid Virtulization will the grid fetch limited number of data from the database or will it pull all the data and just show me limited data on the grid? – Newton Sheikh Jan 31 '13 at 06:20
  • which version of wpf/toolkit you use? they have different features. the virtualized grid will not attempt to use resources (memory, graphic card etc) for the rows which arent on the screen... but to be honest i am thinking now - this is helpful but doesnt solve the data virtualization which is what you are currently doing. because .net has no solution for this. **you still will have to do it in code**. my advice to use snoop to make sure that datagrid is virtualizing still is good thing. but *you should use my other answer or background worker to feed the datagrid items source.* – Boppity Bop Jan 31 '13 at 11:23
  • no this will not solve all of my problem. Right now what I need to do is fetch a limited amount of rows from the database and then show them in the grid. In the mean time a backgrnd process(may be a thread) will keep fetching the remaining rows. Next I can implement DataVirtulization after all the data-have been fetched. Now the challenge for me is to implement all of these at once. And I m struggling out here :( Thanks a lot for ur help though. – Newton Sheikh Jan 31 '13 at 11:38
  • you need very small things to do to make it work - use ObservableCollection instead of data table, set the ItemSource somewhere in the beginning (for example in the Page/UserControl constructor write myGird.ItemsSource = myCollection... this must be in the UI thread... then when you have data coming in other threads - you write *this.Dispatcher.BeginInvoke(new Action(() => { myCollection.Add(dataItem); }));* .. OK? so instead of adding rows to the table and then reloading the grid you just add the data into a collection and dont touch the grid! – Boppity Bop Jan 31 '13 at 12:11
0

If you want to stick with multi-threading though. Here is another way:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <ListBox x:Name="lst">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

public partial class MainWindow : Window
{
    Thread th;
    static ObservableCollection<string> data;

    public MainWindow()
    {
        InitializeComponent();

        data = new ObservableCollection<string>();
        lst.ItemsSource = data;

        th = new Thread(() =>
        {
            while (true)
            {
                Thread.Sleep(500);

                this.Dispatcher.BeginInvoke(new Action(() =>
                { data.Add("zzzzzz"); }));
            }
        });

        th.Start();
    }
}
Boppity Bop
  • 9,613
  • 13
  • 72
  • 151