Click here to Skip to main content
12,406,124 members (40,972 online)
Rate this:
 
Please Sign up or sign in to vote.
See more: C# WPF C#4.0 threads
In My WPF application, I have One Mainwindow with two user controls.

My Mainwindow.xaml like this
<Grid Name="MainGrid">
<my:Usercontrol1 HorizontalAlignment="Left" Margin="70,132,0,0" Name="dummy1" VerticalAlignment="Top" />
</Grid>

Then my UserControl.Xaml

Here I am having one grid contains controls which is connecting to the database, it will take time to load, for that I am using one loadingUserControl like loading rotating image.

<Grid Height="300" Width="770" >
    <Grid Height="223" Width="334"  Margin="10,80,346,-20">
 
        <Label Width="90" Height="24" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontFamily="Verdana" FontWeight="Normal" Margin="10,37,6,5" Grid.Column="1">Sql Server</Label>
        <Grid Grid.Column="2" Width="200" removed="White" Height="20" Margin="1,39,20,7">
            <ComboBox VerticalAlignment="Top" HorizontalAlignment="Left" removed="Transparent" Style="{StaticResource StyleForWidth200}" Margin="0,0,0,0" Name="cmbServerName" Width="200" Height="20" FontFamily="Verdana" IsEditable="True" StaysOpenOnEdit="True" ClipToBounds="False">
 
            </ComboBox>
        </Grid>
        <RadioButton Content="Trusted Connection" Grid.Column="2" Height="20" HorizontalAlignment="Left" Name="rbTrustedConnection" VerticalAlignment="Stretch" Width="200" FontFamily="Verdana" FontWeight="Normal" Margin="0,6,0,16" Grid.Row="1" Grid.RowSpan="2" FontSize="10" IsChecked="True" />
        <RadioButton Content="SQL Server Authentication" Grid.Column="2" Grid.Row="2" Height="16" HorizontalAlignment="Left" Name="rbSQLServerAuthentication" VerticalAlignment="Stretch" Width="200" FontFamily="Verdana" FontWeight="Normal" Margin="0,5,0,0" FontSize="10" />
        <Label  Width="90" Height="24" Grid.Row="3" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontFamily="Verdana" FontWeight="Normal" Grid.Column="1" Margin="10,9,6,9">User Name</Label>
        <TextBox Grid.Column="2" Grid.Row="3" Name="txtUserName" Width="200" Height="20" HorizontalAlignment="Left" Text="" FontFamily="Verdana" FontWeight="Normal" Margin="0,11"></TextBox>
        <Label  Width="90" Height="24" Grid.Row="4" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" FontFamily="Verdana" FontWeight="Normal" Grid.Column="1" Margin="10,2,6,2">Password</Label>
        <PasswordBox Grid.Column="2" Grid.Row="4" Width="200" Height="20" HorizontalAlignment="Left" FontFamily="Verdana" Name="txtPwdWord"/>
        <Button Grid.Column="2" Grid.Row="5" Name="btnConnect" Width="70" Height="30" Margin="131,0,20,5" Content="Connect" FontFamily="Verdana" FontWeight="Normal" Focusable="True" Style="{StaticResource NormalStyle11}" Click="btnConnect_Click"></Button>
 
        <my:LoadingControl x:Name="loadingControl1" Margin="0,70,0,0" Visibility="Visible" />
    </Grid>
</Grid>

In My code behind UserControl1.cs
here I am using threading
when its loading database, LoadingControl should be rotate,once database loaded loadingControl should be hidden, for that I implemented the following code.

here my problem is LoadingControl is not roatating and application get hangs, but when the database loaded lodingcontrol being hidden.

can you please figure out what I missed here.

private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            BindInstances = new Thread(new ThreadStart(ServerConnection));
            BindInstances.Start();
 
        }
private void ServerConnection()
        {
 
            if (Dispatcher.CheckAccess())
            {
                BindDefaultInstances(); 
                loadingControl1.Visibility = Visibility.Hidden;
            }
            else
            {
                Dispatcher.BeginInvoke(DispatcherPriority.Normal,new Action(ServerConnection));
            }
 
private void BindDefaultInstances()
        {
            DataAccess objIED_DAL = new DataAccess();
          
            DataTable dtInstanceList = new DataTable();
            dtInstanceList = objIED_DAL.GetInstances();
            if (dtInstanceList.Rows.Count > 0)
            {
                foreach (DataRow dr in dtInstanceList.Rows)
                {
                    cmbServerName.Items.Add(dr["ServerName"]);
                }
            }
        }
Posted 6-Mar-13 15:41pm
D-Kishore4.2K
Updated 6-Mar-13 17:38pm
v4
Comments
   
Yes, using the dispatcher is the way to go. Now, what's the problem? Hangs? Where?
I would really advise you to provide more detailed description: what did you try to achieve; description of key points of the code: why and what you expected them to do? what did you observer instead?
—SA
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 1

What are you doing?! You are dispatching ServerConnection from ServerConnection! This is your bug.

That's it. Just think about it. You probably don't understand what Dispatcher does. You should be doing something nearly opposite: the delegate instance passed to Dispatcher.Invoke or Dispatcher.BeginInvoke should be a quick method showing something in the UI. This method will be actually called in the UI thread.

Please see my past answers for more information:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^],
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

(Sorry, some information in my answers is related to System.Windows.Forms, some for WPF, some for both. In you case, ignore anything related to Forms.)

—SA
  Permalink  
Comments
D-Kishore 6-Mar-13 23:58pm
   
Yes Sergey, here I am confused.

Actually my problem is when the database loading I want to display like loading..(running image) on the UI.

Kindly suggest me.
   
Do all the database work in a separate thread. (By the way, take a look at my answers on thread wrapper.)
Now, let's say, you create a UI method Show(string data, TextBlock textBlock) { textBlock.Text = data; }.
But you call this method only from UI thread. So you need to invoke it.

Make something like Action<string,> action = new Action<string, TextBlock>((data, textBlock) => { Show(data, textBlock); }).
You got the delegate instance to be passed to Dispatcher.Invoke, followed by actual parameters for data and textBlock.
Do it in your "database" thread... Dispatcher.Invoke won't call your Show method in this thread, it will queue it into the UI thread, which has the mechanism to actually call in from the main event loop of the UI thread...

—SA
D-Kishore 7-Mar-13 0:31am
   
Thanks Sergey, find and intimate the bug in my code
   
You are welcome. I answered now. Are you accepting this answer formally (green button)?
Anyway, your follow-up questions are welcome...
—SA
Shmuel Zang 7-Mar-13 0:33am
   
5'ed. I added a suggestion for how the code can be fixed.
   
Thank you Shmuel.
—SA
Rate this: bad
 
good
Please Sign up or sign in to vote.

Solution 2

As Sergey wrote, your mistake is that you invoke the ServerConnection method in the UI thread. That connection work is done on the UI thread and, that what hangs your UI. Try to change the ServerConnection method to only invoke the UI changes in the UI thread. Something like:

private void ServerConnection()
{
    DataAccess objIED_DAL = new DataAccess();
 
    DataTable dtInstanceList = new DataTable();
    dtInstanceList = objIED_DAL.GetInstances();
 
    if (dtInstanceList.Rows.Count > 0)
    {
        foreach (DataRow dr in dtInstanceList.Rows)
        {
            Dispatcher.BeginInvoke(new Action(() => cmbServerName.Items.Add(dr["ServerName"])));
        }
    }
 
    Dispatcher.BeginInvoke(new Action(() => loadingControl1.Visibility = Visibility.Hidden));
}
  Permalink  
v2
Comments
D-Kishore 7-Mar-13 0:30am
   
Thank you so much Zang, Now I can see what mistake I did.
mine 5+
   
Sorry, this code has big problem. I voted 2. Sorry again.
D-Kishore, please don't use it.
This is creation of a thread on a loop! Wow! very bad. And a thread does not have to be created from UI thread. This BeginInvoke is just bad.
You need only one separate thread for all database operations, creating from the very beginning.
This code, too, shows big misunderstanding of invocation. The delegate instance under Invoke or BeginInvoke should only call fast UI methods...

Please, read all my referenced past answers, they are very useful...
—SA
Shmuel Zang 7-Mar-13 2:14am
   
Which thread is created on a loop? ThreadStart is a delegate and, the operation that is preformed is: adding a delegate to the UI queue.
   
Sorry, my mistake. But why do you use ThreadStart delegate while not creating a thread. I was confused, sorry, but you really have to use delegate System.Action.
—SA
   
I re-voted by 4, but please fix it; you really need to use System.Action instead.
—SA
Shmuel Zang 7-Mar-13 2:36am
   
OK. I accept the comment. The solution changed to use Action instead of ThreadStart.
   
Appreciate it...
—SA
D-Kishore 7-Mar-13 5:51am
   
Yes you are correct sergey, I also wondered when I saw Threadstart,

At the same when I was altering my code I have used Action instead of Threadstart.

Thanks Sergey and Zang.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
Top Experts
Last 24hrsThis month


Advertise | Privacy | Mobile
Web02 | 2.8.160726.1 | Last Updated 7 Mar 2013
Copyright © CodeProject, 1999-2016
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100