How to expand a control beyond the parent's bounds? - wpf

I'm trying to popup a list box when a toggle button is clicked. In the code behind I work with the Visibility property and set it to Visibility.Visible. However, although the list box appears on the screen, it gets cropped to the size of the toggle box (30x30), instead of, as I wish it to, its own size (99x99).
<ToggleButton HorizontalAlignment="Left" Margin="0,0,0,0"
VerticalAlignment="Top" Width="30" Height="30"
Click="ButtonBase_OnClick">
<ListBox x:Name="listBox1"
ClipToBounds="False"
Visibility="Collapsed"
HorizontalAlignment="Left"
Height="99"
VerticalAlignment="Top"
Width="99">
<CheckBox x:Name="checkBox3" Content="CheckBox"/>
<CheckBox x:Name="checkBox4" Content="CheckBox"/>
</ListBox>
</ToggleButton>
I've tried setting the property ClipToBounds to false but it didn't give much change. I also tried setting the height of the combo box to Auto. That made a scroll bar appear (a horizontal one, though, which itself was a bit unexpected) but everything was still cropped to the toggle box's bounds.
What do I need to set more? Or am I approaching it the wrong way (as in: should I define the combo box inside the toggle button's child tags for templates, trigger and what not)?

If you don't want the listbox inside the toggle button, you should not place it inside the toggle button. Place it outside of the toggle button and it should work. Maybe you should have a look at the Expander control, that seems to do what you need. It will still not make the expanders body larger than the expander.
Something else to note: it's bad style to set fixed sizes. Try to partition your window using the containers like Grid and the various Panels and you will not need fixed sizes. If your toggle button does not have a fixed size, it could expand when the contents need expansion.

Related

Max Height for a dynamically sized WPF Textbox

I'd like to make a TextBox in XAML that is dynamically sized to the content, but that has a max height that keeps it from growing forever if that text is very long. If that max height is reached, the TextBox should stop growing and instead show a scroll bar. Ideally, that scrollbar does not exist when the text fits. How would I go about that?
I gain the dynamic resizing property by simply not setting an explicit Height on the TextBox (and possibly turning on text wrapping). But achieving the max height and scroll bar is a mystery to me.
Currently I have a setup that always shows a scroll bar and that grows forever. How would I change this?
<ScrollViewer>
<TextBox Text="{Binding Path=Selection.SummeryDescription, UpdateSourceTrigger=PropertyChanged}" />
</ScrollViewer>
You can do that just by setting the ScrollViewer.VerticalScrollBarVisibility to Auto and the MaxHeight. See example below:
<TextBox Text="..." TextWrapping="Wrap" ScrollViewer.VerticalScrollBarVisibility="Auto" MaxHeight="500" />
This will only show a vertical scrollbar when needed.
Please notice that in my example the ScrollViewer element is omitted as I enable the ScrollViewer via the ScrollViewer.VerticalScrollBarVisibility property instead.

Control the width of child in Stackpanel

I'm trying to implement a certain layout.
I have two elements that I want to stack vertically (I need them to follow each other closely). I am currently trying to achieve it using a Stackpanel.
The problem is that I want the first element to have a limited width and the other to use all the width available in the StackPanel. Ideally, I would like that the first element have a width equals to the width of four columns from the grid that contains the StackPanel, here is my code.
<Grid>
<!-- Colums and Rows definition go here -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="8">
//The first element
<Viewbox Name="viewbox_choix" Margin="160,0,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.Column="0" Grid.ColumnSpan="4" Grid.Row="3" Grid.RowSpan="4">
//The second element
<StackPanel Grid.Column="0" Grid.ColumnSpan="5">
<Border></Border>
etc...
</StackPanel>
</StackPanel>
</Grid>
The grid attributes are referring to the parent grid of the stackpanel. But the Grid.Column and Grid.ColumnSpans seem to have no effect when I try to use them inside the StackPanel.
The problem of that code is that the first element also uses all the width of the StackPanel but that isn't what I want...
Can anybody help me ? I precise that I'm still learning WPF and I don't really know how bindings work...
In WPF, a StackPanel does not work like a Grid. There is no maximum width... it will happily let content disappear out of its right side. If you want automatic resizing, just replace the StackPanels with `Grid
UPDATE >>>
In the Grid class, there is an attached property called IsSharedSizeScope. Add this to the parent Grid and set it to true. Then in your RowDefinitions, you can add SharedSizeGroup properties to the columns that you require.
These examples may help you:
Grid's SharedSizeGroup and * sizing (SO post)
Grid.IsSharedSizeScope Attached Property (MSDN)
You may need to experiment a bit, but you should be able to get the desired effect using these properties.

Problems with using Controls.Popup as error adorner in WPF

My (simplified) validation template is
<Grid>
<Border x:Name="ErrorAdorner"
BorderBrush="Red">
<AdornedElementPalceHolder />
</Border>
<Popup x:Name="ErrorPopup"
PalcementTarget="{Binding ElementName=ErrorAdorner}"
Placement="Bottom"
StaysOpen="false"
IsOpen="true">
<Grid>
<TextBloxk Text="Error!!!" />
</Grid>
</Popup>
</Grid>
The adorned element is typically a textbox
The problem I have with this approach is that, as soon as I click inside the textbox, the ErrorPopup disappears and the ErrorAdorner remains visible. Desired behavior is that both should stay visible.
Things tried:
Set StaysOpen to true on ErrorPopup. Problem: when you resize/move the parent window when the error is visible, the ErrorPopup remains at the same location, it doesnt move along with the textbox
Use a StackPanel around the textbox (adorned element) and the error message text block. Problem: Popup comes with positioning capabilities ie., if there is not enough screen area below the textbox for the adorner, it automatically relocates it. But if a stack panel is used, error message just cuts off if there is no space or it changes the textbox layout(not desired)
So in essence, I want to use the popup for its positional capabilities, but somehow want to fix the visibility problem
The problem here is that you can resize the window even if the cursor is inside the TextBox, you cannot get any useful state information out of that, so if you make the IsOpen dependent on that you still get dislocated popups.
Possibly this related question can help you with the placement.

WPF ListBox scrolls to top when I change status message or show wait screen

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.
<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"
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.
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.
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.
<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"
/>
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.
In reply to #user904627's answer, here is an enhanced version of his workaround. The issue with just fixing Width and Height is the ListBox keeps the same position even if the user resizes the Window. This is not acceptable.
This is why I created this tiny behavior which fixes Width and Height but listens to the parent element's SizeChanged event to let the ListBox resize itself when the container's size changes.
The code is here: VirtualizedListBoxFixBehavior
When the parent element is resized, I restore Width and Height to double.NaN (so the control can resize itself) and I queue the bit of code which fixes the size properties to actual values in the Dispatcher for later execution.
But this still is an ugly working workaround...
Try this:
listBox1.ScrollIntoView(listBox1.Items.GetItemAt(listBox1.Items.Count - 1));
Since the layout is being reset, it is expected that the list box to select the first item (0).
Can you try to set the selected item to the number of existing items in the list box:
Tree.SelectedIndex = Tree.Items.Count;
I did not test this solution on your code but I have used it in another project of mine where I had a similar problem.
Hope it helps.

ListBox with ItemTemplate (and ScrollBar!)

I have a databound and itemtemplated ListBox:
<ListBox x:Name="lbLista"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Deleteable, Mode=TwoWay}" />
<Label Content="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The ites show fine and they come from an ObservableCollection.
The problem is the scrollbar which appears but is not usable - it does not have a handle to grab. I've tried setting some ScrollView attached properties on ListBox, but they do not affect the situation.
I pasted your code into test project, added about 20 items and I get usable scroll bars, no problem, and they work as expected. When I only add a couple items (such that scrolling is unnecessary) I get no usable scrollbar. Could this be the case? that you are not adding enough items?
If you remove the ScrollViewer.VerticalScrollBarVisibility="Visible" then the scroll bars only appear when you have need of them.
ListBox will try to expand in height that is available.. When you set the Height property of ListBox you get a scrollviewer that actually works...
If you wish your ListBox to accodate the height available, you might want to try to regulate the Height from your parent controls.. In a Grid for example, setting the Height to Auto in your RowDefinition might do the trick...
HTH
I have never had any luck with any scrollable content placed inside a stackpanel (anything derived from ScrollableContainer. The stackpanel has an odd layout mechanism that confuses child controls when the measure operation is completed and I found the vertical size ends up infinite, therefore not constrained - so it goes beyond the boundaries of the container and ends up clipped. The scrollbar doesn't show because the control thinks it has all the space in the world when it doesn't.
You should always place scrollable content inside a container that can resolve to a known height during its layout operation at runtime so that the scrollbars size appropriately. The parent container up in the visual tree must be able to resolve to an actual height, and this happens in the grid if you set the height of the RowDefinition o to auto or fixed.
This also happens in Silverlight.
-em-
Thnaks for answer. I tried it myself too to an Empty Project and - lo behold allmighty creator of heaven and seven seas - it worked. I originally had ListBox inside which was inside of root . For some reason ListBox doesn't like being inside of StackPanel, at all! =)
-pom-

Resources