Click here to Skip to main content
15,509,322 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I'm developing an opensource application named Media Assistant[^]. I used a ListBox to show the library. ItemsSource is bound to a list of LibraryItem. Here is the XALM.
HTML
<listbox name="Tree" dockpanel.dock="Top">
    ItemsSource="{Binding DataSource.OrderedLibraryItems}" 
    removed="{StaticResource LibraryBackground}"
    Width="220" HorizontalAlignment="Left"
    BorderThickness="0"
    VirtualizingStackPanel.IsVirtualizing="True"
    VirtualizingStackPanel.VirtualizationMode="Standard"
    ScrollViewer.IsDeferredScrollingEnabled="True"
    ItemTemplate="{StaticResource ListLibraryItemTemplate}"
    SelectionMode="Single"
    MouseDoubleClick="HandleMouseDoubleClick"
/>

The problem is when I show any status message at the bottom of my window from a thread by using Dispatcher.

C#
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,new ParameterizedThreadStart(action), state);


The ListBox scrolls to at the top. If I don't show any status message then it works just fine. The datacontext or list items or focus has not been changed. I could not found any reason why it's doing that. It happens when I display any wait screen which is a non modal window. I could not recreate it in a different project. Here is the source code of Media Assistant[^].
You can easily re-create it by un-commenting the return statement of method SetStatusMessage at BackgroundScanner class. Here is the code.

C#
protected void SetStatusMessage(string message)
{
//Note: Because of status message Library scrolled to top. I don't know why.
    return;
    StatusMessageService.SetStatusMessage(message);
}


It's disturbing when I scrolling and suddenly it scrolls to top if the background scanner changes the status bar message. Please let me know how to fix it.
Posted
Updated 21-Aug-11 15:52pm
v2
Comments
Sergey Alexandrovich Kryukov 21-Aug-11 11:55am    
What is "action"?
What does it mean "Because of status message Library scrolled to top"? How a library can be scrolled? :-)
--SA

I found the reason behind this, so the solution.
I used a DockPanel to layout my UI. I put my status bar at the bottom, the ListBox on the Left and other items are on middle and top. There is a TextBlock in my StatusBar which has width and Height set to Auto. So, when I changed text of my StatusBar TextBlock it's width and height gets recalculated and It's parent's recalculates it's layout. Hence the ListBox gets invoked to Measures and Arrange. Even though it's size does not gets changed it resets it's scroll position to top. It happens only if I use ScrollViewer.CanContentScroll="True" at the ListBox. By default it is True. So, even though I did not set this value It was resetting the scroll position. If I disable it by using ScrollViewer.CanContentScroll="False" then it works fine.

HTML
<listbox name="Tree" dockpanel.dock="Top">
        ItemsSource="{Binding DataSource.OrderedLibraryItems}" 
        Background="{StaticResource LibraryBackground}"
        Width="220" HorizontalAlignment="Left"
        BorderThickness="0"
        VirtualizingStackPanel.IsVirtualizing="True"
        VirtualizingStackPanel.VirtualizationMode="Standard"
        ScrollViewer.IsDeferredScrollingEnabled="True"
        ScrollViewer.CanContentScroll="False"
        ItemTemplate="{StaticResource ListLibraryItemTemplate}"
        SelectionMode="Single"
        MouseDoubleClick="HandleMouseDoubleClick"
    /></listbox>


But setting ScrollViewer.CanContentScroll="False" disables virtualization and I want to use virtualization to my ListBox so I set fixed Height and Width to the TextBlock. So, the DockPanel does not re-arrange it's children if I change the status message.

May be it's a bug at ScrollViewer. It should not change the scroll position if the size has not changed.
 
Share this answer
 
Sorry for not addressing your issue immediately; from your question and code sample it's not clear what's going on; please see my comment to the question.

However, there is something you should re-thing first. This line looks just funny:

C#
Application.Current.Dispatcher.BeginInvoke(
    DispatcherPriority.Background,new ParameterizedThreadStart(action), state);


It looks scary. It gives makes me suspect that you have no idea what Dispatcherispatcher.BeginInvoke or Dispatcher.Invoke; otherwise why would you use this strange ParameterizedThreadStart delegate type? All trouble may become apparent if you look at what is "action" in this line of code.

What's funny, formally you can use this delegate type, but it has nothing to do with the purpose of invocation. The invocation with the use of Dispatcher is a way to delegate a call from some arbitrary thread to a UI thread (UI thread and nothing else).

For this reason, you need to use the dispatcher instance of the Control using the property System.Windows.Threading.DispatcherObject.Dispatcher (as Control is DispatcherObject). It could be your status bar, but it is not really important what exactly control is this. It should be some instance of the Control created and added to you UI by a UI thread.

The delegate type used in Dispatcher.BeginInvoke or Dispatcher.Invoke can be any delegate type with by-value parameters of reference or value types (out or ref parameters also could be used but it makes no sense). The call takes all data needed to a call — handler entry point, "this" reference of the instance of the object where the method is declared (if, any, null for static method), all the values of the call parameters — and queue this data to some queue which is accessible to the UI thread. The call itself is not done be the UI thread using this data from the UI and never by the thread calling InvokeeginInvoke.

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

—SA
 
Share this answer
 
Comments
H. S. Masud 21-Aug-11 13:16pm    
Hi,
The action sets the message property of my status bar control which is a dependency property and it's bounded to a textblock. I used ParameterizedThreadStart to send a message to the action. Why it's so funny is not clear to me. It's a very simple solution to invoke an action to UI thread from another thread. You can have many other solution to this problem. I must have miss understood your answer because I could not found any solution to my problem. Let me explain my problem once again.

When I update anything to my status bar from a thread or show any wait screen my ListBox gets scrolled to top. I tried to re-create it from a simple wpf application where I used the same BeginInvoke method with same ParameterizedThreadStart and the same action. But I could not re-create it. The problem is why does the ListBox scrolled to top automatically when I execute a code which updates a textbox or displays a wait screen. It happens with ListView too.

Thanks
Sergey Alexandrovich Kryukov 21-Aug-11 14:49pm    
Because ParameterizedThreadStart is a delegate type used to start a thread, not to invoke. Usually, Invoke or BeginInvoke use syntax like:

MyControl.Dispatcher.Invoke(
new Action<type1, type2="">((param1, param2) => {
/*use param1, param2*/
}),
paramvalue1, paramvalue2);

Number of parameters may vary. If you use something else, it's a good sign you don't understand what Invoke or BeginInvoke do. Your "used ParameterizedThreadStart to send a message to the action" is gibberish: 1) there are not "messages", 2) not clear what do you call an action and how it can accept "messages"; Invoke or BeginInvoke put call data into the UI thread invocation queue, not "sends message". There is a big difference between the concepts of message and invocation (and there are similarities). Do you simply mean assignment of some text to the status bar?

After all, make a complete code sample which would compile and let's see. Invocation of the delegate which only sets some text in the UI should not affect scrolling of anything. And this code should be really simple. It's hard to imaging where you screw up things without looking at your code. You need to show the invoked code first of all. And get rid of ridiculous ParameterizedThreadStart.

--SA
H. S. Masud 21-Aug-11 13:35pm    
The ListBox scrolls even if I make the Message property to NotifyPropertyChanged instead of using dependency property and change it from a background thread. I could not explain this behavior, that's why I posted this question to codeproject. If you know anything which would solve my problem or explain why it's happening the please let me know.

Thanks
Sergey Alexandrovich Kryukov 21-Aug-11 14:51pm    
This looks even more strange. Make a complete simplified code sample to show the problem, without database and other unrelated stuff. The problem looks very simple, but I can only help if I see it.
--SA
H. S. Masud 22-Aug-11 0:59am    
Sending message means invoking a delegate in UI thread and to set the text property to show message at the status bar. Nothing else.

"Invocation of the delegate which only sets some text in the UI should not affect scrolling of anything." This is the only reason I posted this question. If I don't set the message the ListBox doesn't scrolls. That surprised me. I gave the link of my complete code. Here it is once again http://mediaassistant.codeplex.com/SourceControl/changeset/changes/8705#.
I understand that it's difficult to download the complete code and compile and test it. But I gave this link because I could not re-create in a different project. Something else is happening when I update my UI which makes the ListBox scroll to top. It doesn't matter how did I update the UI. I'm interested to find that.

Thanks

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



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900