WPF Scrollviewer not scrolling... No thumb, only responds to mousewheel - c#

I have a WPF .Net 4 application which contains a button that when clicked opens a new windows :
CreationWindow creationWindow = new CreationWindow();
creationWindow.Owner = this;
CreationWindow.Show();
The window shows fine, but the listbox that it contains (say 100 images as listboxitems for content) does not have a thumb on the scrollbar.
Heres a sample of the content of this 'CreationWindow'
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"~
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Converters="clr-namespace:Krocr.Client.Converters"
x:Class="Krocr.Client.ComparisonMode"
Title="ComparisonMode" Height="450" Width="700">
<Grid>
<ListBox ItemsSource="{Binding Images}"/>
</Grid>
</Window>
The scrollbar is visible, but I cannot interact with it. The mousewheel does scroll the list.
HOWEVER..
If I add a scrollviewer to my main window, and add some items to it. Subsequent scrollviewers (in new windows) then work correctly...
I haven't altered any styles at all for the listbox or the scrollviewer... Very confused!
Help would be greatly appreciated as it's driving me mad.
EDIT : Added screenshot of problem (cant post images yet as I'm new...)
http://i.stack.imgur.com/XdYSs.png

I figured it out...
It was a crazy visual tree in my mainwindow.xaml, which was breaking the rendering of everything else... Heres the issue :
<Grid Background="#00E5E5E5" Margin="0,75,0,0" Grid.Row="1">
<Viewbox x:Name="docViewBox" Margin="0">
<Grid Margin="5" x:Name="holdingGrid">
<Canvas x:Name="AggLayer" Margin="0" />
<Canvas x:Name="rectCanvas" MouseLeftButtonDown="StartDrag" MouseLeftButtonUp="EndDrag" Background="Transparent"/>
<ListBox x:Name="overlayCanvas" Background="#00FFFFFF" IsHitTestVisible="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Width="{Binding ActualWidth, ElementName=rectCanvas}" Height="{Binding ActualHeight, ElementName=rectCanvas}"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
</Viewbox>
<Canvas x:Name="DialogLayer" Margin="0" />
</Grid>
With that commented, it works fine... Also that xaml completely breaks blend, causing random crazy behaviour...
Time to optimize I feel... Thanks for the input :)
EDIT : Infact, all I needed to do was remove the Viewbox and things worked fine... very odd
EDIT 2 : The culprit was the listbox with a canvas itemspanel, this in particular
<Canvas Width="{Binding ActualWidth, ElementName=rectCanvas}" Height="{Binding ActualHeight, ElementName=rectCanvas}"/>
Binding those width and height values was causing the viewbox to get into an infinite scaling loop, which was breaking other things. Silly me...

It's because a Grid by default doesn't constrain the size of its child controls, and so the ListBox doesn't realize it needs to scroll.
The quickest solution is to replace the Grid with a DockPanel, which will constrain its child, but this may need rethinking if you have more child controls to add later!

Related

VirtualizingStackPanel isn't virtualizing

I have a virtualizing stack panel in my ItemsControl, in a scroll viewer. It doesn't seem to be virtualizing:
<Page
x:Class="IWalker.Views.FullTalkAsStripView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:IWalker.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ScrollViewer x:Name="theScrollViewer" VerticalScrollMode="Disabled" HorizontalScrollMode="Auto" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto">
<ItemsControl x:Name="SlideStrip">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:PDFPageUserControl Margin="0 0 5 0" Height="{Binding Path=ActualHeight, ElementName=SlideStrip, Mode=OneWay}" ViewModel="{Binding}" RespectRenderingDimension="Vertical" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Page>
The PDFPageUserControl prints out a little debug message when it is instantiated - and I always get one even when I get more than 50 items. The SlideStrip.ItemsSource is databound, so I don't think that is the problem (via ReactiveUI):
this.OneWayBind(ViewModel, x => x.Pages, y => y.SlideStrip.ItemsSource);
Where Pages is a ReactiveUI list.
What have I missed? Do I need to set IsVirtualizing to true? Where is that attached property in this case (since this isn't a ListBox)?
BTW, I will never have a large number of controls. The issue is that each control holds onto an image, and a large one at that (e.g. full screen on a high DPI display). All I really want to do is release the image when each PDF control is not visible, and re-load when it is. So there may be a better way to solve my problem.

XAML WP8 and making a 'TextBlock' scroll down

Alright, so I have a XAML page with a TextBlock in a Windows Phone 8 application. My dilemma is this:
I pragmatically add more content (formatted lines with Inlines.Add(new Run...) to the TextBlock. The text block is currently filled from bottom to up because of the ScrollViewer in the sense that a line appears in the bottom after another. I would also be fine with them starting to appear from the top as long as the TextBlock would continue to scroll down (actually this might look better) once it is full. My TextBlock is inside a ScrollViewer as below:
<Popup x:Name="send_message_xaml" Grid.Row="1" VerticalOffset="0" Width="750" Height="auto">
<StackPanel Orientation="Vertical" Margin="0,0" Width="auto" Height="auto">
<ScrollViewer Height="345" HorizontalAlignment="Left" Margin="0,0,0,0" Name="scrollViewer1" VerticalAlignment="Bottom" Width="420" VerticalScrollBarVisibility="Auto">
<TextBlock x:Name="message_log" Margin="40,50,0,0" TextWrapping="Wrap" Width="420" VerticalAlignment="Top" FontSize="22"/>
</ScrollViewer>
<TextBox x:Name="message_to_send" InputScope="Chat" Width="480" KeyDown="message_to_send_KeyDown" Margin="15,0"/>
</StackPanel>
</Popup>
How can I get the textblock to scroll so that the newest appended message is always at the bottom? I found a bunch of these threads but none seem to solve my problem so far. Do I need to add some code somewhere with the appending?
You need to update the VerticalOffset based on the ScrollableHeight. When you add new inlines to the TextBlock, its height is going to change and that will notify the parent ScrollViewer. So, after you add new items to the inlines, run the Measure method and update the VerticalOffset.
Here is an example.

Keeping controls in the visible area

I've got a grid with several TextBoxes in it. I want to keep this grid fixed at the bottom of my main window. So if the user scrolls down the grid should basically stay in it's place.
One way I thought of doing this was to get some sort of value from the ScrollViewer and add it to the grids Canvas.TopProperty. However I am not sure which value changes when the user scrolls up or down.
Then don't put the scroll on the main window. Put ScrollViewer only on the content (rows) that you want to scroll. Careful not to use an auto for the height of the rows with the ScrollViewer or the container will grow to support all the content and the Scroll does not come into play.
One way:
<Window x:Class="Sample.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>
<ListBox>
<!--Hardcoded listbox items just to force the scrollbar for demonstration purposes -->
<ListBoxItem>Item1</ListBoxItem>
<ListBoxItem>Item2</ListBoxItem>
<ListBoxItem>Item3</ListBoxItem>
<ListBoxItem>Item4</ListBoxItem>
<ListBoxItem>Item5</ListBoxItem>
<ListBoxItem>Item6</ListBoxItem>
<ListBoxItem>Item7</ListBoxItem>
<ListBoxItem>Item8</ListBoxItem>
<ListBoxItem>Item9</ListBoxItem>
<ListBoxItem>Item10</ListBoxItem>
<ListBoxItem>Item11</ListBoxItem>
<ListBoxItem>Item12</ListBoxItem>
<ListBoxItem>Item14</ListBoxItem>
<ListBoxItem>Item15</ListBoxItem>
<ListBoxItem>Item16</ListBoxItem>
<ListBoxItem>Item17</ListBoxItem>
<ListBoxItem>Item18</ListBoxItem>
<ListBoxItem>Item19</ListBoxItem>
<ListBoxItem>Item20</ListBoxItem>
<ListBoxItem>Item21</ListBoxItem>
<ListBoxItem>Item22</ListBoxItem>
</ListBox>
<Grid Panel.ZIndex="5" VerticalAlignment="Bottom" Background="DarkGray">
<StackPanel>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Center">Text box 1</TextBox>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Center">Text box 2</TextBox>
<TextBox HorizontalAlignment="Left" VerticalAlignment="Center">Text box 3</TextBox>
</StackPanel>
</Grid>
</Grid>

C# WPF - ScrollViewer + TextBlock troubles

I have a TextBlock within a ScrollViewer that aligns with stretch to its window. I need the TextBlock to behave as the following:
Resizes with window, no scrollbars
When resized below a certain width the TextBlock needs to keep a MinWidth and scrollbars should appear
TextWrapping or TextTrimming should work appropriately
How can I get this functionality?
I have tried several ways, involving bindings to ActualWidth & ActualHeight, but can't get it to work.
This can't be that difficult, what am I missing?
Here is a code sample to put in XamlPad (no MinWidth is set yet):
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<TextBlock TextWrapping="Wrap" Text="Some really long text that should probably wordwrap when you resize the window." />
</ScrollViewer>
</Window>
This works:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ScrollViewer HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Name="Scroller">
<TextBlock HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
MinWidth="100"
Width="{Binding ElementName=Scroller, Path=ViewportWidth}"
TextWrapping="Wrap"
Text="Some really long text that should probably wordwrap when you resize the window." />
</ScrollViewer>
</Window>
Without more detail, the best I can do is provide the standard way of doing this. Basically, host your element (which has a minimum size) in a scroll viewer; when the scrollviewer is resized small enough such that the element cannot wholly fit inside it, it will automatically display scroll bars. Example:
<ScrollViewer>
<Button MinWidth="100" MinHeight="50"/>
</ScrollViewer>

How do I build a WPF application where I can drag and drop a user control between windows?

I'm building a simple Todo List application where I want to be able to have multiple lists floating around my desktop that I can label and manage tasks in.
The relevant UIElements in my app are:
Window1 (Window)
TodoList (User Control)
TodoStackCard (User Control)
Window1 looks like this:
<Window x:Class="TaskHole.App.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:t="clr-namespace:TaskHole.App.Controls"
xmlns:tcc="clr-namespace:TaskHole.CustomControls"
Title="Window1" Width="500" Height="500" Background="Transparent" WindowStyle="None" AllowsTransparency="True" >
<Canvas Name="maincanvas" Width="500" Height="500" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<ResizeGrip SizeChanged="ResizeGrip_SizeChanged" />
<t:TodoList Canvas.Top="0" Canvas.Left="0" MinWidth="30" Width="50" Height="500" x:Name="todoList" TaskHover="todoList_TaskHover" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Canvas>
</Window>
TodoList looks like this:
<UserControl x:Class="TaskHole.App.Controls.TodoList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:t="clr-namespace:TaskHole.App.Controls"
xmlns:tcc="clr-namespace:TaskHole.CustomControls"
Background="Transparent">
<StackPanel VerticalAlignment="Bottom" HorizontalAlignment="Stretch" MinWidth="1" Grid.Row="2" Height="Auto" AllowDrop="True">
<ItemsControl Name="todolist" ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Name="stackPanel" VerticalAlignment="Bottom">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<t:TodoStackCard x:Name="card" TaskHover="card_TaskHover" Orientation="Vertical" VerticalContentAlignment="Top" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</UserControl>
I have multiple instances of these windows, and I want to be able to drag any of the controls between the windows. I have tried using a Thumb control and, while this works, it only allows me to drag a control around the containing canvas.
How do I mimic the behaviour of, say, Windows Explorer, where I can drag a file outside of the application and onto another application, all the while seeing a ghosted representation of the file under the cursor.
Can I accomplish this purely in C# and WPF? If so/if not, how?
You have to call DoDragDrop to initialize the Drag And Drop framework. Jaime Rodriguez provides a guide to Drag and Drop here
Just as an FYI, there's a big difference to "dragging controls" around, and doing what Explorer does, which is Drag and Drop, specifically with files. That's what you'll want to look up, how to do drag and drop from a WPF app to something else. You'll need something that creates a Data Object (IDataObject) or whatever they call that in WPF world, and then you need to call DoDragDrop (again, or whatever is analogous to this in WPF) to start the dragging. Doing what explorer does is also possible, put I suspect you need ot make some lower level calls to accomplish this. Take a look at http://www.codeproject.com/KB/wtl/wtl4mfc10.aspx to see the stuff you need ot look for. WPF may in fact wrap all this up, but if it doesn't these are some of the things you need to look into, especially IDragSourceHelper.

Categories

Resources