Scrolling content with negative margins - c#

I have generated XAML file from Windows Forms, and with the process calculated right and bottom margins because they do not exist in Forms. I have this output:
<Grid>
<TextBox Width="129" Height="18" Margin="36,46,278,686" />
...
<TextBox Width="54" Height="18" Margin="345,705,83,31" />
<TextBox Width="54" Height="18" Margin="345,728,83,8" />
<TextBox Width="54" Height="18" Margin="345,770,83,-34" />
...
</Grid>
The problem is that Content of Grid is too large, even for the designer, so scroll bar is generated in win forms. However, this is not case in WPF, so I try adding ScrollViewer around it. But it only scrolls down to content with positive bottom margin. Controls with negative margins are not shown anywhere.
Any idea how to solve this is appreciated.

The Grid is the wrong thing for this task. If you're going to do the positioning yourself, you should use a Canvas and then use Canvas.Left and Canvas.Top to position it. You don't need the Bottom or Right values since you seem to know the Width and Height.
I believe you should be able to use the ScrollViewer around the Canvas object too.

Related

WPF vertical scrollbar aligns with text and not with textbox width

For an application written in C# using WPF I have the following issue:
I have a textbox with text that is being pulled from a database. The length and format of the text can vary from being a short remark, to a long text of multiple paragraphs. In some edge cases, we get text which consists of many short lines 1. Because space is limited vertically and horizontally, we need to define the dimensions of the textboxes to fit the UI 1. As you can see, in the case where the textbox has to display more than 5 lines, with the lines being very short, we get a situation where the scrollbar doesn't align with the right side of the textbox, but aligns with the text itself.
I have tried to put the textbox inside of a Scrollviewer and tried to fix the issue this way, but this resulted in the scrollbar being outside of the textbox, with the thumb of the scrollbar not showing and the dimensions of the scrollbar itself being completely off.
The final result should be a scrollbar that is always aligned to the right side of the textbox, no matter the length of the text that is being displayed.
Examples of textboxes, top one being an edge case which comes up sometimes
<Label Grid.Row="0"
Content="{StaticResource NominationInfo_OperatorRemarks}"
Style="{StaticResource UnderlineLabel}" />
<TextBox Width="500"
Grid.Row="1"
HorizontalAlignment="Left"
MaxLines="5"
IsReadOnly="True"
Text="{Binding OperatorRemarks, Mode=OneWay}"
TextWrapping="Wrap"
ScrollViewer.VerticalScrollBarVisibility="Auto">
</TextBox>
<Label Grid.Row="2"
Content="{StaticResource NominationInfo_LoadingInstructions}"
Style="{StaticResource UnderlineLabel}" />
<TextBox Grid.Row="3"
MaxLines="5"
IsReadOnly="True"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Text="{Binding OperatorInstructions, Mode=OneWay}"
TextWrapping="Wrap"
Width="500"
HorizontalAlignment="Left" />
I suppose you have confounded HorizontalAlignment and HorizontalContentAlignment.
Putting the following code to the TextBox should do the trick.
HorizontalAlignment="Stretch" HorizontalContentAlignment="Left"

Adding border to entire grid when I'm trying to add it to only a TextBlockC#

I'm trying to add a border to only a TextBlock but instead it is creating it around the entire grid. Here is the code :
<Border BorderBrush="Black" BorderThickness="6">
<TextBlock x:Name="txtInputUsername" HorizontalAlignment="Left" Margin="65,54,0,0" TextWrapping="Wrap" Text="Username" VerticalAlignment="Top" TextAlignment="Center" FontFamily="Open Sans" FontSize="20" Background="#FFF3F3F3" OpacityMask="Black"/>
</Border>
This is happening because child elements of a Grid will assume the Height and Width of the Grid (or the Grid cell) they are placed in, unless otherwise specified. The Border just looks like it is wrapping around the grid, because it is using it to infer its size.
There are a few ways to fix this, with the easiest being to specify the HorizontalAlignment and VerticalAlignment of the Border to Center. This causes the Border to snap around the bounds of the TextBlock instead of inferring its size.
In your case, it still produces some odd results because of your use of Margin to position the label. The Margin is still counted as being part of the control, so anything the wraps around the control will have to be larger to accommodate it. You should avoid that if at all possible, but if you really want to do it that way, more the Margin to the Border.
<Grid>
<Border
Margin="65,54,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
BorderBrush="Black"
BorderThickness="6">
<TextBlock
x:Name="txtInputUsername"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Background="#FFF3F3F3"
FontFamily="Open Sans"
FontSize="20"
OpacityMask="Black"
Text="Username"
TextAlignment="Center"
TextWrapping="Wrap" />
</Border>
</Grid>
A better way to handle this though, is to learn about the different layout containers, and how to use them to position your controls, instead of Margin. These can be nested within each other to create almost any layout you can imagine, in a fairly nice, clean way.

How to set a control's position according to another in windows 8 app?

I have a page like this:
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
here are contents
they are forever absolutely in the center of the screen
no matter of the resolution/size
</StackPanel>
</Grid>
Everything is working fine. But now I want to add a back button in the top-left corner.
And I don't want to split the grid into 2 columns and 2 rows like this:
the contents are no longer absolutely centered, even we can split the grid by percent, because the contents are sometimes very wide and sometimes very narrow.
I want to know how can I keep the contents horizontal/vertical aligned "Center", and then set the back button's position relatively to the content.
I would suggest using a grid layout with 3 columns to ensure the content is centered with the columns widths set to *,Auto, *. This will ensure the main content is always centered and not care about the size of the button. You can then use margins to set the seperation as required. This is a techinique I have used in SL, WPF & Metro.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button HorizontalAlignment="Right" VerticalAlignment="Top" Content="Do Something"/>
<ContentControl VerticalAlignment="Top" Content="My custom content"/>
</Grid>
slightly hacky ansewer
You might be able to achieve by positioning your stackpanel in the center, and then set a negative left margin the width of the button to shift everything left by the required amount...
<Grid>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="-45,0,0,0">
<button with width and padding totalling 45px />
here are contents
they are forever absolutely in the center of the screen
no matter of the resolution/size
</StackPanel>
</Grid>

Issue with ScrollViewer in WPF

I am working on a WPF application and using a scrollViewer to view the content that is offlimit the screen area. Working fine, no issues.
But if my window contains a Listbox or Grid or anything like that and that control has many records then instead of adding a scrollbar to itself, it just increase the height of the control and window itself because scrollviewer believes it needs to extend.
I don't want to hardcode the listbox's height, because that make it same in different resolutions, i want to make it increase its height but not always as scrollviewer make it do so.
Thanks
You can't include a variable height/width object inside a ScrollViewer without setting the height/width of the viewer.
The scroll viewer effectively has infinite height so the grid expands to fill the "available" space - hence the effect you are seeing. As #JoeWhite says in his comments, the ScrollViewer is a container that can be as tall as it needs to be to hold all of its content. Anchoring wouldn't help - in effect, your ListBox already is anchored, it's just anchored to something that says "oh, I'll be whatever size you need me to be".
You'll need to either restrict the height, move the ListBox outside the ScrollViewer or use something other than a ScrollViewer.
Again quoting #Joe "These are the hazards of putting a scrolling area inside another scrolling area - it's poor usability and it's hard to define the behaviour."
You can wrap ScrollViewer into Grid, and bind scrollviewer's Width and Height properties to grid's ActualWidth and ActualHeight. So the scrollviewer will have fixed size equal to the size of the grid which will change when window resize.
Example:
<Grid x:Name="LayoutRoot" Background="White">
<Grid Background="#FFF1F1F1" Height="49" VerticalAlignment="Top">
<Button Content="Обзор" Margin="0,13,175.25,0" VerticalAlignment="Top" FontSize="14.667" HorizontalAlignment="Right" Width="95.147">
</Button>
<Label Content="{Binding DocPath, Converter={StaticResource FileNameConverter}, FallbackValue=Выберите файл, TargetNullValue=Выберите файл}" HorizontalAlignment="Left" VerticalAlignment="Top" Width="342.603" Margin="10,10,0,0" Height="33"/>
<Button Content="Загрузить данные" HorizontalAlignment="Right" Margin="0,13,10,0" VerticalAlignment="Top" Width="151.147" FontSize="14.667">
</Button>
</Grid>
<Grid x:Name="scrollBorder" Margin="10,54,10,10">
<ScrollViewer x:Name="LogScroller" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="{Binding ActualHeight, ElementName=scrollBorder}" Width="{Binding ActualWidth, ElementName=scrollBorder}" >
<ItemsControl ItemsSource="{Binding Log}" />
</ScrollViewer>
</Grid>
</Grid>

Resize WPF application

Have tried searching google but I'm struggling to find an answer to this.
I have a basic WPF application with a few controls on. When I maximise the application the controls on the screen stay the same size and I get a lot of wasted space.
Is there a way to get the controls to grow and shrink dynamically with the size of the main window?
Kind Regards
Ash
Don't set a fixed Height and Width properties for your controls.
Instead set, horizontal and vertical alignment to stretch. And make sure your controls are contained inside an appropriate layout panel.
For example-
Fixed size grid:
<Grid Background="Red" Width="50" Height="50"/>
Dynamically expending grid:
<Grid Background="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
what you need is not resize, it's called scaling (or zooming) ;-)
Read this article; the task is very trivial with WPF.
(used to be much more complicated in Windows Forms...).
UI Scaling (UI Zooming) with WPF
basically all you need to add to the XAML is this:
<ScaleTransform
CenterX="0" CenterY="0"
ScaleX="{Binding ElementName=uiScaleSlider,Path=Value}"
ScaleY="{Binding ElementName=uiScaleSlider,Path=Value}"
/>
after that you can use mouse wheel or a slider or any other way (like in your case detect form maximized), to modify the Value of the ScaleTransform.
Where there's a will, there's a way. You will have to do some work yourself however, WPF can't automagically decide for you exactly how you want the resizing to be done.
Some relevant sources:
Layout containers
Data Binding
You can use content decorator that can stretch and scale a single child to fill the available space - Viewbox .
http://www.wpftutorials.com/2011/04/wpf-viewbox.html
this is no problem. The behavior of your controls depends on the container you use and the Horizontal and Vertical Alignment. For Example, if you use a Grid, a TextBox and a Button with Horizontal and Vertical Alignment: Stretch and width and height auto, the Textfield and Button will grow and shrink dynamically.
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WpfApplication.MainWindow"
x:Name="Window"
Title="MainWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<TextBox Margin="8,8,8,104.96" TextWrapping="Wrap" Text="TextBox" Height="auto" Width="auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Button Content="Button" Margin="8,0,8,8" VerticalAlignment="Bottom" Height="92.96" Width="auto" HorizontalAlignment="Stretch"/>
</Grid>
Use a resizable control like Grid and put all the controls in Rows/Columns. Also set HorizontalAlignment to stretch for each control.

Categories