WPF Listbox scroll down - wpf

Lets say i have a listbox with many items so that a vertical scroll comes up, but i have hidden the scroll bar with
ScrollViewer.VerticalScrollBarVisibility="Hidden"
Is there any way i can add a button that would scroll down for me? iv tryed to add
Command="ScrollBar.LineDownCommand"
to a button but that didnt have any effect.

You need to tell WPF where to start looking for the command handler. Without telling it, it will start looking from the Button and not find anything that handles the LineDownCommand. Unfortunately, setting it to the ListBox will not suffice because the ScrollViewer is inside the ListBox as part of its template, so WPF still won't find it.
Setting it to one of the ListBoxItems is naff, but works:
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox x:Name="_listBox" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<ListBoxItem x:Name="_listBoxItem">One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
<ListBoxItem>Three</ListBoxItem>
<ListBoxItem>One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
<ListBoxItem>Three</ListBoxItem>
<ListBoxItem>One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
<ListBoxItem>Three</ListBoxItem>
<ListBoxItem>One</ListBoxItem>
<ListBoxItem>Two</ListBoxItem>
<ListBoxItem>Three</ListBoxItem>
</ListBox>
<Button Grid.Row="1" Command="ScrollBar.LineDownCommand" CommandTarget="{Binding ElementName=_listBoxItem}">Scroll Down</Button>
</Grid>
</Window>
A better way to do this would be to either re-template the ListBox and stick the Button inside the template, or to wire up the CommandTarget in the code-behind.

I had an app where I wanted to manually control the scrolling of a ScrollViewer. Basically, I got a reference to the ScrollViewer and then used the ScrollToHorizontalOffset() method to control the scrolling. Below are the blog posts where I explain the process I used:
http://www.developingfor.net/wpf/fun-with-the-wpf-scrollviewer.html
http://www.developingfor.net/wpf/more-fun-with-wpf-scrollviewer.html

Related

Opening new UserControl in MainWindow erases all empty rows

Once I run the program, it opens a UserControl in my MainWindow. The UserControl is a Menu consisting of 3 buttons.
Image of the UserControl:
Menu
The code behind Main Window:
<Window
...
Title="MainWindow" Height="350" Width="525" SizeToContent="WidthAndHeight" >
<Window.DataContext>
<ViewModels:MainWindowViewModel />
</Window.DataContext>
<ContentControl Content="{Binding CurrentViewModel}"/> //Inserts a UserControl
The code behind Menu UserControl:
<UserControl
...
d:DesignHeight="90" d:DesignWidth="525" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="100*"/> //Problem
<RowDefinition Height="100*"/>
<RowDefinition Height="100*"/> //Problem
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button Grid.Row="1" Margin="30,0" Content="First" Command="{Binding DataContext.SwitchToNextUserControl,
RelativeSource={RelativeSource AncestorType={x:Type local:MainWindow}}, Mode=OneWay}" />
<Button Grid.Row="1" Grid.Column="1" Margin="30,0" Content="Second"/>
<Button Grid.Row="1" Grid.Column="2" Margin="30,0" Content="Third"/>
</Grid>
THE PROBLEM:
Once the menu is opened, the empty rows (those without buttons, first and third) get collapsed (or just height to 0?), as shown: Running program
I can get over it with setting MinHeight for every row, but it works only on pixels. I'd like them to work in the method of stars ("*"). I guess I could set their height from code behind (using stars), but just the thought of it makes me feel like I rub my right ear with left hand.
Also, once I click on the "First" button, some other UserControl is opened in the window, instead of the "Menu" one, and its rows are also collapsed. Just mentioning it.
So the question is, what should I do to make my UserControls appear just as they look in designer?
You should remove to SizeToContent="WidthAndHeight" from your window XAML.
This causes the height of the window to shrink to fit the size of the UserControl (and effectively the height of the middle Button).

WPF XAML treeview in a stack panel - no scrolling?

so I have a TreeView control in my XAML. It works fine. If I extend the treeview to be larger than the user control it resides in, I get a scroll bar, which is good. However, inside this user control I want some other things. So I put the treeview in a stack panel with some other things, and this time I don't get the scroll bar if the treeview expands to be larger than the user control it's in.
Is this something other people have come across, and is there a fix for it?
Embed your stackpanel inside a ScrollViewer: stackoverflow.com/a/6250287/7517676. You also might have to explicitly set VerticalScrollBarVisibility and HorizontalScrollBarVisibility, depending on your need.
Here's a code sample:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<StackPanel ... />
</ScrollViewer>
Based on this answer a StackPanel isn't the right container for a TreeView, but a Grid is. So this will enable scrolling inside the TreeView, by mouse and scrollbar:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label>Some descriptive label.</Label>
<TreeView Grid.Row="1" ItemsSource="{Binding SomeSource, Mode=OneWay}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:MyNodeType}" ItemsSource="{Binding Children}">
<Label Content="{Binding NodeName}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>

WPF TabControl Children

This is my current Scenario: I have several UserControls inside different TabItems on a single TabControl in a WPF Window. Something Like:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="S.C.A.R" WindowState="Maximized">
<TabControl Name="MainTabControl">
<TabItem Name="TabOps">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition Height="20"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="30"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Local:ServiceList Height="Auto" CanInsert="True" CanCollapse="True" Grid.ColumnSpan="3" x:Name="SL" RecordState="Edit"/>
<Local:ReservationList CanCollapse="True" Grid.Row="1" RecordState="Edit" x:Name="RL"/>
<Local:DriverList CanDelete="False" CanInsert="False" CanCollapse="True" Grid.Row="1" Grid.Column="2" RecordState="Edit" x:Name="DL"/>
<Local:CustomerForm CanDelete="False" CanInsert="False" Grid.Row="2" Grid.ColumnSpan="3" RecordState="View" x:Name="CL"/>
</Grid>
</TabItem>
<TabItemItem Name="TabCodes">
<Local:CustomerList x:Name="CustomerCRUD" RecordState="View"/>
</TabItem>
<Button Grid.Row="1" Content="TEST" Click="Button_Click"/>
</Grid>
</Border>
</Window>
Sorry for the indentation. For some reason I can't get the code properly indented here :(
What I need to do is to determine (preferably in the TabControl.Load Method, which of my different UserControls are currently visible. I need to do this in a dynamic way, I cannot hardcode the relationship between the TabItems and their children, something like:
if (TabControl.SelectedItem is XXXX)... is not possible here, because this is a Dynamic UI and I have no way to know which controls are there up front.
I've been digging a little bit and found out that the TabItem controls do not appear in the Visual tree of their "children". I only see a ContentPresenter, and then the TabControl itself. It looks like the tabItems do not "contain" their own content, so I could not, for example, do a FindAncestor to the Tab Items.
Another interesting fact is that the Loaded event of my usercontrols is being called on startup. Regardless of whether or not they're visible on screen.
An ideal scenario will be to find an event that is only fired on my Usercontrols when the TabItem they are under gets selected.
Appreciate any ideas. Thanks in advance
You should be able to leverage the VisualTreeHelper and consequentrly this answer on SO to provide the TabItem.Content returned object and look for the your specified type, UserControl in this instance.
NOTE:
For additional details please see the comments which transpired in the SO's question.

Having trouble getting contents of ListBox to resize with it

I tried the suggestion here regarding Stretching, but it didn't work for me.
I have a TabItem that hosts a UserControl that is essentially just a ListBox with an ItemsPanel. The ItemsPanel forces the ListBox to display its contents horizontally. The contents of the ListBox are databound to an ObservableCollection<StackPanelContents>, which is another UserControl. StackPanelContents itself basically just contains a List of objects with some visual representation (they contain a UIElement for visualization).
In general the code works properly in that it renders all of the data that I have contained in the ObservableCollection, but the problem is that the items don't resize as the window is enlarged or shrunk.
Here's an overview of what the class hierarchy looks like:
And here are the results:
The XAML for the main window just has the TabControl and TabItem:
<Window x:Class="ResizeStackPanelInListBox.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<TabControl>
<TabItem Header="Test" x:Name="MyTabItem">
<!-- contents are set in code behind -->
</TabItem>
</TabControl>
</Window>
The ListBoxContainer XAML that displays the StackPanelContents looks like this:
<UserControl x:Class="ResizeStackPanelInListBox.ListBoxContainer"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<TextBlock>ListBox with StackPanels as its ListBoxItems:</TextBlock>
<ListBox Grid.Row="1" ItemsSource="{Binding StackPanels}" HorizontalContentAlignment="Stretch">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Width="Auto" Height="Auto" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
</UserControl>
And the StackPanelContents UserControl looks like this:
<UserControl x:Class="ResizeStackPanelInListBox.StackPanelContents"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="Auto" Width="Auto">
<StackPanel>
<TextBlock Text="StackPanel"></TextBlock>
<StackPanel x:Name="MyStackPanel">
</StackPanel>
</StackPanel>
</UserControl>
Can anyone explain why this isn't resizing automatically, and how I can go about resolving this? Am I going to have to write my own custom panel to deal with this, and use MeasureOverride and Arrange?
The problem is that you're using StackPanels to arrange items in both directions so you're losing any sort of stretching. StackPanel allows its children to stretch only in the direction opposite the Orientation. The other direction will only be given as much space as it needs in order to allow the rest of the items as much space as possible. So for a default Vertical StackPanel anything you put inside will stretch horizontally but squeeze toward the top vertically. Since you have Vertical StackPanels inside a Horizontal StackPanel you're items are getting squeezed both ways.
There are a few options depending on what you want your items to do. Changing to a DockPanel will allow the last item to stretch and fill the space (the vertical one would need to set DockPanel.Dock=Top in the ItemContainerStyle). A Grid with * sized Rows and Columns works well for normal layouts but not in the case of ItemsControls since the Row and Column need to be set for each item (it can be done using ItemsControl.AlternationIndex but it's a pain and fragile). Using a 1 row/column UniformGrid (as in the answer you referenced) will evenly divide the available space and doesn't require any additional settings on the items.
If you need some more complex layout strategy with different items getting different amounts of space or stretching behavior you'll need a custom Panel.
try set in window
SizeToContent="WidthAndHeight"

wpf - window to be tight round user control

I've got a user control that I'm loading into a Window dynamically - I wanted to set the Window so that it didn't have a size and then I thought the window to resize accordingly depending on the UserControl. However it dosn't - can anyone assist please?
I've made a very basic example - I've cut out the dynamic bits and just put a UserControl in a Window. What do I need to do to get the window to be tight around the UserControl?
Thanks,
Andy
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300" Background="LightBlue">
<Grid>
</Grid>
</UserControl>
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfApplication1="clr-namespace:WpfApplication1" Title="Window1" >
<Grid>
<WpfApplication1:UserControl1>
</WpfApplication1:UserControl1>
</Grid>
</Window>
Try setting SizeToContent to WidthAndHeight on your Window.
See MSDN Page
Try setting either Width and Height to Auto, or setting SizeToContent = WidthAndHeight.
Once you know the size of the control, you will then have to update the size of the window. I'm unsure of any way to force the window to resize itself automatically unless you have code doing it.
Check this out for all you need to know, plus some, in order to do this.
Not sure if this will help, but I'd start by making the Window :
Height="Auto" Width="Auto"
If this alone doesn't do the trick I would add a Grid Row and Column
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
And then I would set the
<WpfApplication1:UserControl1 Grid.Row="0" Grid.Column="0" />
Not 100% sure if this will work but its worth a try as this is what I'm doing on my side and it works.

Resources