Size-to-content-layout problem in WPF - wpf

This is supposed to be a no brainer but I still can’t figure it out.
In my sample app there’s a button and a textbox in a dockpanel. If the content of the textbox is smaller than the content of the textbox the window is as big as it needs to be to display the content of the button. That’s what I want. But if I put more text into the textbox the window gets wider :-(
The behavior I want is that the window gets the width according to the buttons content and the textbox wraps its content (or/and shows scrollbars if necessary).
Thank you!
Some sample code:
<Window x:Class="SO1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" SizeToContent="Width" FontSize="20">
<DockPanel>
<Button DockPanel.Dock="Top">A rather long text</Button>
<TextBlock TextWrapping="Wrap">Short text</TextBlock>
</DockPanel>
</Window>

Having tried it, it seems that binding the TextBlock's MaxWidth to the ActualWidth of the Button achieves the effect you're after:
<Button x:Name="btn" DockPanel.Dock="Top">Short text</Button>
<TextBlock TextWrapping="Wrap"
MaxWidth="{Binding ElementName=btn,Path=ActualWidth}">A rather long text</TextBlock>

Related

WPF: Textblock text in Popup goes outside of the main window

In my example wpf app I've added one button and one popup to the window. The button is in the bottom right corner and the popup has set "PlacementTarget" property to it and "Placement" set to top. The popup consists of one very long textblock.
What I expect this popup will behave is not to go outside of the window and therefore automatically set his "HorizontalOffset" to the appropriate value, but the popup behaves against my intentions.
Here's my xaml file:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1" x:Name="window" x:Class="WpfApplication1.MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:Converters x:Key="Converters"/>
</Window.Resources>
<Grid>
<Button x:Name="button" Content="Button" VerticalAlignment="Bottom" Width="75" HorizontalAlignment="Right"/>
<Popup Placement="Top" PlacementTarget="{Binding ElementName=button, Mode=OneWay}" IsOpen="True">
<TextBlock TextWrapping="Wrap" Text="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" Background="White"/>
</Popup>
</Grid>
Do anyone know how to fix it?
I've read that this should be default popup behavior to take care of going out of the boundaries, but not in my case. Thanks in advance.
Have you tried to set the width of the Popup or Textblock ?
Sorry, I can't write this poor answer as a comment..

WPF Button Content VerticalAlignment on default button

I'm not able to center text vertically on a default button (no styles or templates used)
I saw threads like
Text content in a WPF button not being centred vertically
^^ I'm not setting any text height atleast in button 1.
Not sure what causes this behavior and how to get rid of it efficiently when localisation comes in.
I do get I can set a -ve margin to align text exactly, however that might screw things up for another language. Is this some limitation based on the Default Font Family Expression blend seems to impose?
Any help with this would be great. Seems trivial but cant seem to find a decent explanation for what's causing this behavior.
Xaml code is as follows:
<Window x:Class="TestButton.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Button Content="ButtonFFAH" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" VerticalContentAlignment="Center"/>
<Button Content="ButtonAH" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75"
Margin="80,0,0,0" Height="15.627" VerticalContentAlignment="Center"/>
</Grid>
It`s how it works internally. If you want some more control, just fill button content with more customizable things that just a string. Like this:
<Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="75"
Margin="80,0,0,0" Height="15.627" VerticalContentAlignment="Center">
<TextBlock VerticalAlignment="Center">ButtonAH</TextBlock>
</Button>
The apparent vertical misalignment is due to the fact that all kinds of accents or other diacritical marks add to the total font height. Although the actual Button content may not contain such characters, the vertical alignment has to take this into account to ensure a common baseline alignment with other Buttons with the same "outer" alignment, for example in the same Grid row.

Label word wrap in Textblock not working

I have a WPF page with quite a few objects. At the bottom of all these items, I have a label that needs to have textwrapping in the content. That answer is simple, with the use of a Textblock this should be a cinch. However, even though I use those items, I still can't get th e text to wrap. So I'm assuming that there must be other settings in the other objects that I need to check/modify. In pseudo code, my XAML looks like
<Page>
<Stackpanel vertical>
<Border>
<Stackpanel vertical>
<label></label>
<Stackpanel horizontal>
<label></label>
</stackpanel>
<label>
<textblock TextWrapping="Wrap">
</label>
</border>
</stackpanel>
</page>
What am I missing here? Should I be checking other elements? I have already made sure that none of the nesting elements have any height specified - they are all set to auto.
I'm going to go ahead and post this as an answer in case someone else gets stuck on this.
When you set the Width and Height properties of the TextBlock control, it will first horizontally increase in size to accommodate as much text as it can before wrapping the text (if the TextWrapping property is set to Wrap). Once it decides it needs to wrap the text, if the Height is set to Auto, the text box will resize vertically to accommodate the text (until it hits the bottom of whatever UI container you put it in). If you do not want the text box to resize past a certain point, you will need to set values for the MaxWidth and MaxHeight properties. This will force the TextBlock to wrap at a certain width.
With my XamlPadX, this wraps:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Vertical">
<Label>L1</Label>
<StackPanel Orientation="Horizontal">
<Label>L2</Label>
</StackPanel>
<Label>
<TextBlock TextWrapping="Wrap">
This text wraps.
This text wraps.
This text wraps.
This text wraps.
This text wraps.
This text wraps.
This text wraps.
</TextBlock>
</Label>
</StackPanel>
</StackPanel>
</Page>
So the problem must be somewhere else.

WPF: Focus in a Window and UserControl

I'm trying to get a UserControl to tab properly and am baffled. The logical tree looks like this.
|-Window
-Grid
-TabControl
-TabItem
-StackPanel
-MyUserControl
|-StackPanel
-GroupBox
-Grid
-ComboBox
-Textbox1
-Textbox2
Everything works fine, except when the visibility converter for the ComboBox returns Visibility.Collapsed (don't allow user to change database mode), then when textbox1 is selected, instead of being able to tab through the controls in the UserControl, the focus shifts to a button declared at the bottom of the window. Nothing else apart from the controls displayed has TabIndex or FocusManager properties set.
I'm banging my head against a brick wall and I must be missing something. I've tried IsFocusScope=True/False, played with FocusedElement and nothing works if that ComboBox is invisible (Visibility.Collapsed).
<Window x:Class="MyNamespace.Client.WinInstaller"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FocusManager.FocusedElement="{Binding ElementName=tabWizard}">
<Window.Resources>
<props:Settings x:Key="settings" />
</Window.Resources>
<Grid Grid.IsSharedSizeScope="True">
<!-- row and column definitions omitted -->
<loc:SmallHeader Grid.Row="0" x:Name="headerBranding" HeaderText="Setup" />
<TabControl x:Name="tabWizard" DataContext="{StaticResource settings}" SelectedIndex="0" FocusManager.IsFocusScope="True">
<TabItem x:Name="tbStart" Height="0">
<StackPanel>
<TextBlock Text="Database Mode"/>
<loc:DatabaseSelector x:Name="dbSelector" AllowChangeMode="False" TabIndex="1"
AvailableDatabaseModes="SQLServer" IsPortRequired="False"
DatabaseMode="{Binding Default.DbMode,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
DatabasePath="{Binding Default.DatabasePath,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
</TabItem>
...
The top of the user control is below:
<UserControl x:Class="MyNamespace.Client.DatabaseSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="root"
FocusManager.IsFocusScope="True"
FocusManager.FocusedElement="{Binding ElementName=cboDbMode}">
<UserControl.Resources>
<conv:DatabaseModeIsFileBased x:Key="DatabaseModeIsFileBased"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
</UserControl.Resources>
<StackPanel DataContext="{Binding}">
<GroupBox>
<Grid>
<!-- row and column definitions omitted -->
<Label Content="Database Mode"/>
<ComboBox x:Name="cboDbMode" SelectedValue="{Binding ElementName=root,Path=DatabaseMode,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Value" SelectedValuePath="Key" TabIndex="1" Visibility="{Binding AllowChangeMode,ElementName=root,Converter={StaticResource BooleanToVisibilityConverter}}" />
<!-- AllowChangeMode is a DependencyProperty on the UserControl -->
<Grid><!-- row and column definitions omitted -->
<Label "Host"/>
<TextBox x:Name="txtDBHost" Text="{Binding ElementName=root,Path=DatabaseHost,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TabIndex="2" />
<TextBox x:Name="txtDBPort" Text="{Binding ElementName=root,Path=DatabasePortString,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TabIndex="3" />
I know this response is quite late... but have you tried:
<UserControl ... KeyboardNavigation.TabNavigation="Local">
Doing so will ensure once your UserControl has recieved focus, you will navigate only through TabStop within your UserControl (instead of worring about conflicting TabIndex values throughout your app). After looping through the TabStops of your UserControl, TabNavigation will resume to the TabStop outside of it.
http://msdn.microsoft.com/en-us/library/system.windows.input.keyboardnavigationmode.aspx
Maybe the problem is that you hide the FocusManager.FocusedElement.
Anyway, you could make life easier by just eliminating some complicating factors:
Remove FocusManager.FocusedElement...
the ComboBox is the first control within anyway.
Remove FocusManager.IsFocusScope...
I suppose it's ok if everytime you enter the usercontrol the first control within will be focussed, not the one that was focussed when you left it before. Just let the usercontrol be "inlined" in the surrounding controls.
Remove the explicit TabIndices in the UserControl. Your layout already implies the same ordering.
If you eliminate these three complicating factors, you might already be done.
Maybe you also have to set your UserControl Focusable=False, s.t. the focus is passed to the first focussable Control within - comboBox or TextBox1.

Scrollbar in Listbox not working

I have a ListBox that displays a list of WPF controls.
My problem is that the vertical scrollbar is show but is disabled even when there are enough items that the ListBox should be scrollable.
One other possibly relevant fact is that this is contained in an Integration.ElementHost.
WPF noobie, Jim
Here is the XAML for the ListBox:
// for brevity I removed the Margin and Tooltip attributes
<Grid x:Class="Xyzzy.NoteListDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Name="stackPanel" Orientation="Vertical"
ScrollViewer.VerticalScrollBarVisibility="Visible">
<StackPanel Orientation="Horizontal">
<CheckBox Name="AllRecent" IsChecked="False" >View All Recent</CheckBox>
<CheckBox Name="AscendingOrder" IsChecked="False">Descending Order</CheckBox>
<Button Name="btnTextCopy" Click="btnCopyText_Click">Copy All</Button>
</StackPanel>
<ListBox Name="NoteList"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible">
</ListBox>
</StackPanel>
</Grid>
And the XAML for the control displayed in each ListBox item:
<UserControl x:Class="Xyzzy.NoteDisplay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Name="Heading" FontSize="10">Note Heading</TextBlock>
<Button Name="btnCopyText" Height="20" FontSize="12"
Click="btnCopyText_Click">Copy
</Button>
</StackPanel>
<TextBlock Name="Body" FontSize="14">Note Body</TextBlock>
</StackPanel>
</Grid>
</UserControl>
I have had problems with scroll bar visibility when using a StackPanel. I think it is because the StackPanel is always as big as it needs to be to contain all of its children. Try reorganizing the layout to remove the StackPanel (use a Grid instead) and see if that helps.
You just need to introduce Height property, like this:
<ListBox Height="200"
Name="NoteList"
ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Visible">
</ListBox>
Heya, I suspect what might be happening is that your ListBox is expanding enough for every item however the ListBox is actually disappearing off the bottom of the Containing Control.
Does the ListBox actually stop properly or does it just seem to disappear? Try setting a MaxHeight on the ListBox and see if that makes the scrollbar appear. You should be able to set the VerticalScrollBarVisibility to Auto to have it only appear when needed.
If the list box is inside a StackPanel, try these steps for your ListBox
Set ScrollViewer.VerticalScrollBarVisibility="Auto"
Setting the Height property of a ListBox to some height that you expect to see.
That should force the scroll bar to show up.
This is pretty late, but anyone using ListBox probably shouldn't have it in a StackPanel. Once I switched the parent control of my Listbox from StackPanel to DockPanel with LastChildFill=True (Where the listbox was the last control), my scrollbar worked perfectly.
Hope this helps someone who's problem was not solved by the above answer.
Another solution to this problem that works well is to put a ScrollViewer around the StackPanel.
Another solution with a modification to Dave's is to use the ScrollViewer only. You only be able to scroll by placing your mouse on the ScrollView's ScrollBar. I use it this way because I don't like how ListBox jumps from item to item and sometimes missing items from the Top. Little bit hard on the eyes too. I like ScrollViewer's smooth scrolling.
I just ran into the same issue, and here's a little code demo on code project that visually shows it.
(If you want to save yourself the time of writing the code to see the differences yourself :) )
http://www.codeproject.com/Tips/659066/ListBox-and-Panels-in-WPF

Resources