WPF DataGrid inside a ScrollViewer - c#

I have a StackPanel with a header control and a DataGrid Inside a Scrollviewer; like so:
<ScrollViewer>
<StackPanel Orientation="Vertical">
<Canvas x:Name="header"
Height="300" />
<DataGrid x:Name="dataGrid">
</DataGrid>
</StackPanel>
</ScrollViewer>
The scoll behavior should fulfill these requirements:
Scrolling while MouseOver the DataGrid should scroll the outer ScrollViewer
The header control (symbolized by Canvas) is scrolled by the ScollViewer.
The horizontal scrollbar at the bottom of the DataGrid should be preserved on screen at any time.
The horizontal scrollbar should not scroll the header control, only the DataGrid.
I tried various settings for the DataGrid.ScrollViewer but none have the desired effect, nor does changing the StackPanel to a WrapPanel or even Grid help any.
Is this possible? Any help and resources to read are appreciated.

I've been struggling with your first problem for some time as well - having an inner ScrollViewer (or DataGrid in this case) scroll the outer ScrollViewer. But I think I have a pretty elegant solution. You have to add an event handler to the PreviewMouseWheel event of the DataGrid (and a name to the ScrollViewer):
<ScrollViewer x:Name="scroll_viewer">
<StackPanel Orientation="Vertical">
<Canvas x:Name="header"
Height="300" />
<DataGrid x:Name="dataGrid" PreviewMouseWheel="mousewheel">
</DataGrid>
</StackPanel>
</ScrollViewer>
Then the event handling method:
private void mousewheel(object sender, MouseWheelEventArgs e)
{
//what we're doing here, is that we're invoking the "MouseWheel" event of the parent ScrollViewer.
//first, we make the object with the event arguments (using the values from the current event)
var args = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
//then we need to set the event that we're invoking.
//the ScrollViewer control internally does the scrolling on MouseWheelEvent, so that's what we're going to use:
args.RoutedEvent = ScrollViewer.MouseWheelEvent;
//and finally, we raise the event on the parent ScrollViewer.
scroll_viewer.RaiseEvent(args);
}
Hope this helps!

It's a very complicated question, it probably requires a man-week to complete! But here's a start which solves half of your problem:
<ScrollViewer x:Name="scroll">
<DataGrid x:Name="dataGrid">
<DataGrid.Template>
<ControlTemplate>
<StackPanel Orientation="Vertical">
<Canvas x:Name="header" Height="300" />
<ItemsPresenter/>
</StackPanel>
</ControlTemplate>
</DataGrid.Template>
</DataGrid>
</ScrollViewer>
If you put the canvas inside the datagrid's template it will consider it as a part of the datagrid so canvas and datagrid will be scrolled as one.
Obviously, the datagrid template will be blank this way, showing no headers. Therefore you need to rewrite it from the scratch. You may use the default source code for this purpose.
To find the template just search for <ControlTemplate TargetType="{x:Type DataGrid}">
in the given link.

Related

How to scroll the datagrid in stackpanel?

I want to scroll the datagrid when it's length exceeds the stackpanel, so I tried this:
<StackPanel Orientation="Horizontal">
<ScrollViewer VerticalScrollBarVisibility="Auto" CanContentScroll="True">
<DataGrid Name="dgConfig" VerticalAlignment="Stretch" AutoGenerateColumns="False">
<DataGrid.Columns>
...
</DataGrid.Columns>
</DataGrid>
</ScrollViewer>
</StackPanel>
But this doesn't work, I have searched on this web and failed to find any avaiable solutions. So how should I fix this? Thanks!
ScrollViewers and StackPanels don't work very well together since a StackPanel measures its child elements with infinite horizontal space if its Orientation property is set to Horizontal and infinite vertical space if it is set to Vertical.
So you will either have to specify a height for the StackPanel:
<StackPanel Orientation="Horizontal" Height="100">
If you don't it will have an infinite height and that's why you see no scrollbars.
The other, and much better option, would be to get rid of the StackPanel and use another Panel that doesn't measures its child elements with an infinite space.
The DataGrid has its own ScrollViewer built-in, so you don't need to put it inside a ScrollViewer element yourself. Get rid of the StackPanel(s) and the ScrollViewer:
<DataGrid Name="dgConfig" VerticalAlignment="Stretch" AutoGenerateColumns="False"
VerticalScrollBarVisibility="Auto">
<DataGrid.Columns>
...
</DataGrid.Columns>
</DataGrid>
DockPanel instead of StackPanel works for me.
try adding VerticalScrollBarVisibility="Auto", ScrollViewer.CanContentScroll="True" to datagrid property.

WPF: UserControl with Expander leave blank space after Expander collapsed

I have UserControl with Expander. And I use it in main window in ListBox like this:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding MyCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<local:MyUserControl />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
After form loaded UserControls fill space normally.
After child user control expanded parent container's height grows, as expected.
After child user control expanded
If I collapsed UserControl, there are the blank space left in the parent container.
Blank space left after child user control collapsed
If main window gets resize event, all blank space are gone.
I'd tried use Element.InvalidateVisual and Element.InvalidateMeasure in code, and also UpdateLayout, and wrap ListBox with DockPanel + DockPanel.Dock="Top" for panel's child. It was not effect.
At other hand, when I add the same UserControl in the code, this artefact disappears: parent control collapsed as I need after child UserControl collapsed. But I need exactly XAML and UserControl as DataTemplate.
Please, help me. I sure there must be some easy solution, but I'm new to the XAML and so I have difficulty with this.
Finally, i've solved this problem. The solution is set ScrollViewer.CanContentScroll property of ListBox element to True.
The solution is to set the parent FrameworkElement with a HorizontalAligment like in the following example.
<StackPanel Background="Green" VerticalAlignment="Top" >
<Expander>
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<local:SomeUserControl></local:SomeUserControl>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Expander>
</StackPanel>
This works on my solution.
Your FrameworkElements behaviour around your expander is a bit weird. If you still have some issues you should show more information about it.

How do I wrap ListView and GridView inside ScrollViewer without breaking scrollViewer scrolling

I have this layout:
<ScrollViewer>
<StackPanel>
<ListView>
<ListView.View>
<GridView>
<!-- Content -->
</GridView>
</ListView.View>
</ListView>
<!-- Filtering Controls -->
</StackPanel>
</ScrollViewer>
The screen doesn't have a fixed or max height. The Scrollbar shows fine and works fine, but when the mouse is over the items in the List/GridView, the ScrollViewer doesn't receive the event and doesn't scroll.
I've read about how I can implement an extension, but that seems overdoing it, what's the simplest solution to make the List/GridView either pass the mouse wheel scroll event to the ScrollViewer or ignore them?
This happens because listview handles the scroll event, the simplest I can suggest is to override content of listview and insert a itemsPresenter which has no scroll properties inside it.
I solved such problem by using something like this..
<ListView>
<ListView.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ListView.Template>
</ListView>
Have a look here for detailed discussion on this topic

ScrollBar Disabled

I was trying to implement a ScrollViewer like so;
<Height="auto" Width="auto"
MaxHeight="500" MaxWidth="400"
ResizeMode="NoResize" WindowStyle="None">
<Grid>
<StackPanel>
<ScrollViewer Name="scrlBr">
<StackPanel Orientation="Vertical">
<TextBlock Name ="txtBlock" Margin="10" Height="auto"
Width="auto" TextWrapping="Wrap"></TextBlock>
<Button Name="btnOk" Click="btnOk_Click" Width="80"
HorizontalAlignment="Center">Close!</Button>
</StackPanel>
</ScrollViewer>
<Label HorizontalAlignment="Center" FontSize="3"
Name="lblScrollDown">\/</Label>
</StackPanel>
</Grid>
</Window>
The problem I'm having is that the scroll bar appears disabled, while the text obviously goes down off the window and I can't see the btnOk. Surely if the window has a fixed height and the TextBlock and Button, which are contained in the Scrollviewer, are bigger than the window then the ScrollBar should be enabled, no?
UPDATE
I worked out that the problem lies in having the ScrollViewer within a StackPanel. Might try it with a Grid instead... Update to come.
SOLUTION
I was right about the Stackpanel being the problem and went with Heinzi's suggestion of using the DockPanel and all's workin' fine. :) Thanks!
The problem is your StackPanel. It always takes all the vertical space it needs, so the container of the ScrollPanel is much larger than the window itself, and the ScrollViewer sees no need to scroll.
Solution: Replace the StackPanel with a DockPanel. Move the <Label> declaration to the top and dock it to the bottom of the DockPanel. The last child in a DockPanel (which is the ScrollViewer in this case) always fills the remaining space:
<Grid>
<DockPanel>
<Label DockPanel.Dock="Bottom" ... Name="lblScrollDown">\/</Label>
<ScrollViewer Name="scrlBr">
...
</ScrollViewer>
</DockPanel>
</Grid>
Try setting the CanContentScroll property on True from the ScrollViewer and set a fixed height of the StackPanel, as a StackPanel is designed to grow indefinitely in one direction. Or better, use a different panel to stack your items in.
Maybe you need write something like this
<ScrollViewer Name="scrlBr" VerticalScrollBarVisibility="auto" HorizontalScrollBarVisibility="auto">
...
</ScrollViewer>

Scroll bar, if Items exceed inside itemControl

I have ItemControl
It displays one panel for each record inside ObservableCollection.
My Problem is….
When size of ObservableCollection increase window can’t accommodate more panels so it displays only first six panels.
So criteria, One panel for each record inside ObservableCollection,couldn't be accomplish.
So, I need to have scroll bar so I can access each panel.
How does it can be implement?
See one screen shot below and Code of It Here
Thanks......
You need to host your panel within a ScrollViewer. This allows it to grow beyond the space available to it, whilst the ScrollViewer adds a Scrollbar.
You can do this by modiyfing the ItemsControl template:
<ItemsControl>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer>
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
Put any controls you want to have scrollbars into the ScrollViewer. Example taken from MSDN:
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<StackPanel VerticalAlignment="Top" HorizontalAlignment="Left">
<TextBlock TextWrapping="Wrap" Margin="0,0,0,20">Scrolling is enabled when it is necessary.
Resize the window, making it larger and smaller.</TextBlock>
<Rectangle Fill="Red" Width="500" Height="500"></Rectangle>
</StackPanel>
</ScrollViewer>

Categories