Let 2 Controls automatic fill space with same size - wpf

I want two texboxes fill the available Space in a panel. But both have to contain the same width. So DockPanel lastchildfill doesn't works here.
I have an image where u can see, i simply created 2 textboxes without any width. The empty Space should be filledby both textboxes like the above (the above is made with manual Width="xxx". But I dont' want to hardcore it like this.
I want it like Grid.Column width="*"
Do I have to create a Grid for each panel? (There will be much more textboxes)
my XAML is simple because I dont know how to realize my idea:
<DockPanel LastChildFill="False">
<TextBox DockPanel.Dock="Left" x:Name="nachname_textbox"/>
<TextBox DockPanel.Dock="Right" x:Name="vorname_textbox"/>
</DockPanel>

UniformGrid control might suit your needs : it automaticaly places all controls in cells with the same amount of width en height for each ones. And you can define how many rows and columns you want.
<UniformGrid Columns=2>
<TextBox />
<TextBox/>
</UniformGrid>

If you want two elements to fill 50% each of the avalable width of a Panel, you should put a Grid with two ColumnDefinitions in each Panel, i.e. simply replace the DockPanel with a Grid:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBox />
<TextBox Grid.Column="1" />
</Grid>
If you want to decrease the amount of XAML, you could create your own custom Grid class:
public class My2x2Grid : Grid
{
public My2x2Grid()
{
ColumnDefinitions.Add(new ColumnDefinition());
ColumnDefinitions.Add(new ColumnDefinition());
}
}
...and use this one:
<local:My2x2Grid>
<TextBox />
<TextBox Grid.Column="1" />
</Grid>

Related

Limit width of TextBox to the width of the ListView that contains it

I am working on a MVVM app (the examples here are not very MVVM though, its just a mockup).
I have a ListView, that binds to a collection of TextItemViewModel instances, the view for these are defined in TextItemView. Each TextItemView contains a Grid with one Auto column and on * column to fill. The fill column contains a TextBox where the user can enter text.
I want the TextItemViews to fill the horizontal space of the ListView (this works), like so:
However, when a user enters long text in a box, I want it to expand in Height but not in Width. At the moment, the Width increases and the ListView gets a scrollbar, like so:
My ListView code looks like this: (I've taken out the MVVM Binding code and set the ItemsSource in the code-behind for this example)
<ListView Name="listview"
SelectionMode="Single"
Margin="5"
MinHeight="50"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch" />
And my TextItemView code looks like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button Content="SomeButton"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="5"
Grid.Column="0" />
<TextBox Text="{Binding Path=NoteText}"
TextWrapping="Wrap"
AcceptsReturn="True"
AcceptsTab="True"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
HorizontalAlignment="Stretch"
Margin="5"
Grid.Column="1" />
</Grid>
Can anyone advise me on how to force the TextItemView to fill the width of the ListView (as it does), but to then wrap the TextBox and expand TextItemView in Height when the TextBox fills up?
OK I got this now thanks to WPF - How to stop TextBox from autosizing?
Trick is to add the following to ListView definition:
ScrollViewer.HorizontalScrollBarVisibility="Disabled"

WPF ListView TextBlock TextWrapping

I am building a ListView that needs to have five columns - the first one needs to have text that can be any length and needs to wrap whenever the window size changes (in addition to changing the row height so the wrapped text is visible) and the other four columns are a static width of 45. I've been searching for hours on this and every solution I come across either requires a static width or doesn't work.
Solutions tried:
Column widths of auto, 1*, 2*, etc. (settings ignored)
DockPanel (settings ignored)
WrapPanel (ignored)
Setting Width to RelativeSource of parent for ActualWidth (ignored)
Any ideas? It seems like a significant number of people have had this same problem, but I would highly prefer to not have to go the static width route for this column. Especially since the content just gets cut off when I do that anyway (even with height="Auto" for the row). The width of the overall window could be as small as 1024, but could also be 1600+ which is why I want dynamic sizing. That way smaller screens will have the content wrap and larger screens will just show the one line since the content fits.
Here is the XAML:
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
<ColumnDefinition Width="45" />
</Grid.ColumnDefinitions>
<!-- This is the TextBlock that needs to wrap its content (and
change the height of the row (so the full content is still
visible) to whatever the available space is, but should not
make overall ListView wider than the parent's width. -->
<TextBlock Text="{Binding Content}" Padding="20,6,6,6" />
<!-- These four blocks will have other content eventually, but only need
to be 45 wide -->
<TextBlock Text="X" Grid.Column="1" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="2" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="3" HorizontalAlignment="Center" />
<TextBlock Text="X" Grid.Column="4" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Not so easy...but it can be done.
I wrote a solution for you. In short, use Expression Blend to create a copy of the ListView Template and delete the ScrollViewer surrounding the ItemPresenter.
Here is a more indepth explanation:
How to have the TextBlock in a left column of a Grid in a ListView Template expand or shrink with text wrapping?
<ListView HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
...
</ListView.ItemTemplate>
</ListView>
I'd add TextWrapping="Wrap" to the first TextBlock element.

UserControl Dimensions Ignored in MainPage Layout

I have a Canvas with a Grid on it. The Grid contains 3 columns. The first column contains another Grid, the second contains nothing, the third contains an Image (a box). (I have the blank column for animation purposes unrelated to this question.)
In my child Grid I have 2 rows. The first row contains a UserControl (shelves of boxes), the second contains an Image (a barcode).
The problem is that the layout engine seems to completely ignore the dimensions of the user control. In the preview I see my UserControl and directly on top of it the two other images. Granted Canvas doesn't automatically size its children, but I have that resolved with some resize statements in the SizeChanged event of the page.
As it is, the box shows up at runtime in the bottom right corner of my window as it should, however the barcode appears positioned as if the UserControl doesn't exist.
For an illustration of my issue please see http://www.wynright.com/temp/Problem.png
The following is my XAML code:
<Canvas x:Name="MainCanvas" Background="Silver">
<Grid Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid Name="LayoutChild" Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<LightPickDemo:Picker x:Name="PickZone" ZoneCleared="PickZone_ZoneCleared" HorizontalAlignment="Left" VerticalAlignment="Top" />
<Image Name="BarCode" Source="/LightPickDemo;component/Images/BarcodeScan.png" HorizontalAlignment="Center" Stretch="None" VerticalAlignment="Center" Grid.Row="1" />
</Grid>
<Image Name="imgShippingBox" Source="/LightPickDemo;component/Images/Empty-Box.png" VerticalAlignment="Bottom" Stretch="None" Grid.Column="2" />
</Grid>
</Canvas>
So I wonder what do I need to do to get the UserControl to offer its size for the layout engine. I can see in my designer the size of the control, so clearly the compiler knows that there is size to this control.
I would like the barcode to show centered below the UserControl.
Here is the XAML for the UserControl:
<Canvas>
<Image Name="ImageBase" Source="/LightPickDemo;component/Images/BayShelves.png" />
<LightPickDemo:ZoneLight x:Name="ZoneLight" Canvas.Left="345" Canvas.Top="0" ButtonPress="ZoneLight_ButtonPress" />
<LightPickDemo:PickerModule x:Name="pickerCalculator" Canvas.Left="74" Canvas.Top="266" OnPicked="Picker_PickChanged" />
<LightPickDemo:PickerModule x:Name="pickerCalendar" Canvas.Left="207" Canvas.Top="266" OnPicked="Picker_PickChanged" />
<LightPickDemo:PickerModule x:Name="pickerPaperClip" Canvas.Left="521" Canvas.Top="266" OnPicked="Picker_PickChanged" />
<LightPickDemo:PickerModule x:Name="pickerRuler" Canvas.Left="649" Canvas.Top="266" OnPicked="Picker_PickChanged" />
<LightPickDemo:PickerModule x:Name="pickerScissor" Canvas.Left="75" Canvas.Top="532" OnPicked="Picker_PickChanged" />
<LightPickDemo:PickerModule x:Name="pickerStapler" Canvas.Left="250" Canvas.Top="532" OnPicked="Picker_PickChanged" />
<LightPickDemo:PickerModule x:Name="pickerStapleRemover" Canvas.Left="435" Canvas.Top="532" OnPicked="Picker_PickChanged" />
<LightPickDemo:PickerModule x:Name="pickerTapeDispenser" Canvas.Left="635" Canvas.Top="532" OnPicked="Picker_PickChanged" />
</Canvas>
Most likely the ActualHeight of your user control is zero. Looking at your XAML for the user control you should be able to just set Height and Width in the XAML of the user control.
I can't determine what is the UserControl from your image, but if you set the property to 'collapsed' the engine won't read the size I don't think. If the UserControl isn't visible, but you want to show the dimensions, animate the opacity property instead of visibility. The barcode is in Row 1 which is the top row, should it be in row 2?
Am I correct in assuming the barcode needs to be below the image with the 2 rows of boxes? Where is the UserControl? What is it?
An answer to my question seems to be to put the following code in my UserControl, however, I can't imagine this is the best answer and I know it doesn't allow for screen scaling at all. So please, if anyone knows how to do this correctly, please let me know.
Thanks to Wallstreet Programmer for leading me to this workaround.
Protected Overrides Function MeasureOverride(ByVal availableSize As System.Windows.Size) As System.Windows.Size
Dim bmp As BitmapImage
bmp = BaseImage.Source
Return New Size(bmp.PixelWidth, bmp.PixelHeight)
'Return MyBase.MeasureOverride(availableSize)
End Function

WPF Listbox wont scroll Vertical

Within a Groupbox I have a Listbox, ListboxItems are defined in the XAML as well. The Listbox is defined:
<ListBox Name="lvAvoidCountry" Margin="5,5,5,5"
Background="Transparent"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
Items are defined like this:
<ListViewItem >
<CheckBox Name="chkAlbanien" Tag="55">
<StackPanel Orientation="Horizontal">
<Image Source="images/flag_albania.png" Height="30"></Image>
<TextBlock Text="Albanien" Margin="5,0,0,0"></TextBlock>
</StackPanel>
</CheckBox>
</ListViewItem>
If I remove the Scrollviewer Settings I get horizontal scrolling and the Items are well formatted - correct width. If I use the scrollviewer settings the items get cut off so that all items are placed on the listbox. (eg. the flag is shown, the checkbox is shown but the text is just "Alba").
Thanks for any hints!
As the name implies, ScrollViewer.HorizontalScrollBarVisibility="Disabled" disables horizontal scrolling. If you do that, but your ListBoxItems are too long, they'll get cut off. The StackPanel won't grow or shrink to fit into the ListBox, and it won't "wrap" your items to fit into the ListBox if it's too narrow, even if you add TextWrapping to the TextBlock. It's very stubborn. I think your main problem is that StackPanel.
Instead of a StackPanel, try using a Grid with 2 columns defined like so:
<ListViewItem >
<CheckBox Name="chkAlbanien" Tag="55">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="images/flag_albania.png" Height="30"/>
<TextBlock Grid.Column="1"
TextWrapping="Wrap"
Text="Albanien" Margin="5,0,0,0"/>
</Grid>
</CheckBox>
</ListViewItem>
Auto will "shrinkwrap" the image columns, and * will give the text all remaining space. Then add TextWrapping to your textblock in case it's still too long.
Edited: added more complete code example and changed my answer slightly.
if you want vertical scrolling in a listbox then don't put it in a stackpanel,instead use a grid.

Align items in a stack panel?

I was wondering if I can have 2 controls in a horizontal-oriented StackPanel so that the right item should be docked to the right side of the StackPanel.
I tried the following but it didn't work:
<StackPanel Orientation="Horizontal">
<TextBlock>Left</TextBlock>
<Button Width="30" HorizontalAlignment="Right">Right<Button>
</StackPanel>
In the snippet above I want the Button to be docked to the right side of the StackPanel.
Note: I need it to be done with StackPanel, not Grid etc.
You can achieve this with a DockPanel:
<DockPanel Width="300">
<TextBlock>Left</TextBlock>
<Button HorizontalAlignment="Right">Right</Button>
</DockPanel>
The difference is that a StackPanel will arrange child elements into single line (either vertical or horizontally) whereas a DockPanel defines an area where you can arrange child elements either horizontally or vertically, relative to each other (the Dock property changes the position of an element relative to other elements within the same container. Alignment properties, such as HorizontalAlignment, change the position of an element relative to its parent element).
Update
As pointed out in the comments you can also use the FlowDirection property of a StackPanel. See #D_Bester's answer.
Yo can set FlowDirection of Stack panel to RightToLeft, and then all items will be aligned to the right side.
For those who stumble upon this question, here's how to achieve this layout with a Grid:
<Grid>
<TextBlock Text="Server:"/>
<TextBlock Text="http://127.0.0.1" HorizontalAlignment="Right"/>
</Grid>
creates
Server: http://127.0.0.1
Could not get this working using a DockPanel quite the way I wanted and reversing the flow direction of a StackPanel is troublesome. Using a grid is not an option as items inside of it may be hidden at runtime and thus I do not know the total number of columns at design time. The best and simplest solution I could come up with is:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Orientation="Horizontal">
<!-- Right aligned controls go here -->
</StackPanel>
</Grid>
This will result in controls inside of the StackPanel being aligned to the right side of the available space regardless of the number of controls - both at design and runtime. Yay! :)
This works perfectly for me. Just put the button first since you're starting on the right. If FlowDirection becomes a problem just add a StackPanel around it and specify FlowDirection="LeftToRight" for that portion. Or simply specify FlowDirection="LeftToRight" for the relevant control.
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" FlowDirection="RightToLeft">
<Button Width="40" HorizontalAlignment="Right" Margin="3">Right</Button>
<TextBlock Margin="5">Left</TextBlock>
<StackPanel FlowDirection="LeftToRight">
<my:DatePicker Height="24" Name="DatePicker1" Width="113" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit" />
</StackPanel>
<my:DatePicker FlowDirection="LeftToRight" Height="24" Name="DatePicker1" Width="113" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit" />
</StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Left" />
<Button Width="30" Grid.Column="1" >Right</Button>
</Grid>
If you are having a problem like the one I had where labels were centered in my vertical stack panel, make sure you use full width controls. Delete the Width property, or put your button in a full-width container that allows internal alignment. WPF is all about using containers to control the layout.
<StackPanel Orientation="Vertical">
<TextBlock>Left</TextBlock>
<DockPanel>
<Button HorizontalAlignment="Right">Right</Button>
</DockPanel>
</StackPanel>
Vertical StackPanel with Left Label followed by Right Button
I hope this helps.
for windows 10
use relativePanel instead of stack panel, and use
relativepanel.alignrightwithpanel="true"
for the contained elements.
Maybe not what you want if you need to avoid hard-coding size values, but sometimes I use a "shim" (Separator) for this:
<Separator Width="42"></Separator>

Resources