I want to know if there is a way to resize the frame and the elements inside of it when the window size change. I always want to have the same proportion in the size of the elements inside the frame.
Example:
1- Windowsize = 100(in x) and Imagesize = 50(in x) locationx = 25
2- Windowsize = 50(in x) and Imagesize = 25(in x) location x = 12.5(~12)
In this case, the windowsize is "something", imagesize is 1/2 of "something" and locationx of the image is 1/4 of something. I wan't to do something like this but with every element inside the frame.
Thanks!
You can use the <ViewBox/> control which does exactly that.
<Page>...
<Grid>
<ViewBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<StackPanel>
<Button Content="test" HorizontalAlignment="Left"/>
<TextBlock Text="some text"/>
</StackPanel>
</ViewBox>
</Grid>
</Page>
In the example below, the ViewBox is placed inside a Grid and stretched both Horizontally and Vertically which causes it to stretch with the Page resize.
Reference docs here.
Related
I have seen several similar questions to this, but no solution works for me, probably because my Grid is set to Stretch . This is the result I am trying to achieve. Basically, I have one Grid and I'd like to draw an X-Axis line( like in the picture at the end of this question).
My XAML
<Grid x:Name="MainGrid" HorizontalAlignment="Stretch" Background="#FF4A70F1">
My CodeBehind
Line XAxis = new Line();
XAxis.Stroke = System.Windows.Media.Brushes.Black;
XAxis.StrokeThickness = 1;
XAxis.X1 = 0;
XAxis.X2 = MainGrid.RenderSize.Width;
XAxis.Y1 = MainGrid.RenderSize.Height / 2;
XAxis.Y2 = MainGrid.RenderSize.Height / 2;
MainGrid.Children.Add(XAxis);
My Problem
I 'd like this line to span the whole window, even if I resize/maximize the window. However, the calculations above for X2,Y1,Y2 don't work( all evaluate to 0, hence NO LINE shown) , whether I use ActualSizeor *RenderSize* . Can someone please point out how to fix that? Thank you
This XAML creates a vertically centered line that stretches horizontally:
<Grid>
<Line HorizontalAlignment="Left" VerticalAlignment="Center" Stroke="Black"
X2="{Binding ActualWidth,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Grid}}"/>
</Grid>
How to find the child elements positions in a stack panel.
<StackPanel Orientation="Horizontal">
<ToggleButton Width="20"
Height="20"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Visibility="Visible" />
<TextBlock Margin="5"
VerticalAlignment="Center"
FontSize="15"
Text="Selection Mode" />
</StackPanel>
How to find the X,Y position of Toggle button and Text block?
You could always use TranslatePoint to translate coordinates relative to one UIElement to coordinates relative to another UIElement:
var toggleButtonPosition = toggleButton.TranslatePoint(new Point(0, 0), stackPanel);
var textBlockPosition = textBlock.TranslatePoint(new Point(0, 0), stackPanel);
The above code translates the point (0, 0) relative to the respective control to coordinates relative to the containing StackPanel, and hence gives the position of each control inside the StackPanel.
Basically, the position of a control is determined by the control which holds it, the margin property, the alignement and such.
You could use this to determine the position of the child control.
Is there any way to exclude certain UIElement from a certain scroll effect? I have a grid element below a columns header element. while I'd like to have full scrolling over the grid, I want the header to be affected only by the horizontal scrolling. so that it will always stay at the top when scrolling down.
Here is a mspaint I made to explain in case my explenation didn't make sense.
Why not move your scroll viewer inside the green rows and then have a different scroll viewer for the header.
Then wrap it all in a parent container
So like
<Grid>
<HeaderControl>
<ScrollViewer />
</HeaderControl>
<BodyControl>
<ScrollViewer />
</BodyContent>
</Grid>
Wrapping them together in one scroll viewer is overly complicated. Splitting it into two distinct scroll viewers will simplify the problem IMO.
What if you used 2 separate scroll viewers - an outer one that contains both the header and the grid, and that only handles the horizontal scrolling.
Then the grid itself can be wrapped in a separate scroll viewer that handles just the vertical scrolling on of the grid. E.g:
<ScrollViewer VerticalScrollBarVisibility="Disabled">
<!-- Header -->
<Grid>
</Grid>
<ScrollViewer HorizontalScrollBarVisibility="Hidden">
<!-- Content -->
<Grid>
</Grid>
<ScrollViewer />
</Grid>
Although I'm not 100% sure about the two visibility settings - you might have to play around with them to see what works
I just wanted to do the same. My solution would be using a Canvas for the header and Scrollviewer for the body.
<Canvas>
<Grid Canvas.Left="{Binding ElementName=ValueScrollViewer, Path=HorizontalOffset, Converter={StaticResource DoubleMultiplyingConverter}, ConverterParameter=-1}">
Header
</Grid>
</Canvas>
<ScrollViewer Name="ValueScrollViewer" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" >
<Grid>
Table
</Grid>
</ScrollViewer>
With converter:
public class DoubleMultiplyingConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var factor = System.Convert.ToDouble(parameter, CultureInfo.InvariantCulture);
var val = System.Convert.ToDouble(value);
return val * factor;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
To handle all the situations, you should separate static part (header) and scrollable part (body) and wrap body with ScrollViewer. This solution is perfect in everything, except the situation when your control is wider than screen (or outer control), so horizontal scroll should be allowed too and header should be also scrolled. You can't just use inner scrollviwer for this, because vertical scrollbar will only be visible when horizontal scroll is at right edge.
You can't exclude header from only vertical scroll, but you can simulate horizontal one. You can do it with just translation transform.
<Grid>
<!-- body part. place it first to make it go to the background -->
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" x:Name="scrollbar">
<!-- the body control itself -->
<Canvas x:Name="PART_Body"/>
</ScrollViewer>
<!-- header part. Border and margin are used to make it not overlap vertical scrollbar -->
<Border Margin="0,0,18,18" ClipToBounds="True">
<Canvas x:Name="PART_Header">
<Canvas.RenderTransform>
<!-- bind X to the scrollbar X position -->
<TranslateTransform X="{Binding ElementName=scrollbar, Path=ContentHorizontalOffset, Converter={StaticResource InvertDoubleConverter}}"/>
<!-- InvertDoubleConverter is just a value converter which multiples incmoing double value by -1 -->
</Canvas.RenderTransform>
</Canvas>
</Border>
</Grid>
I have created a Rectangle inside of a ScrollViewer like this
<ScrollViewer ManipulationMode="Control" x:Name="songScrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled" Height="270" VerticalAlignment="Center" Width="728" Canvas.Top="20" d:LayoutOverrides="HorizontalMargin" >
<Rectangle x:Name="musicBG" Fill="#FF0692FD"/>
</ScrollViewer>
During the use of the app, the size of MusicBg changes, sometimes to something around 3,000 pixels width.
musicBG.Width = _songLength*PixelsPerSecond
However, while scrolling the scrollViewer, it allows me to scroll the rectangle all the way off the screen.
For example this line of code gives me the following values when I have moved the rectangle as far as I want to move it.
if (songScrollViewer.HorizontalOffset > songScrollViewer.ScrollableWidth)
HorizontalOffset has a value of ~1200 and ScrollableWidth has a value of about ~2900.
How can I get this to be done properly so that the rectangle is not scrolled completely off the screen?
I would expect a HorizontalOffset of about 1200 to only push the rectangle about halfway through to it's destination, and not make it start going off screen.
ANSWER:
After much frustration, I was able to solve this problem by using Canvas instead of Border or Rectangle.
I'll award points if anyone can explain why this problem happened, and if there is a less processor intensive control that would work better than canvas.
Edit: Screen shots:
Bad Code:
<ScrollViewer ManipulationMode="Control" x:Name="songScrollViewer" Width="720" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled" Height="270" VerticalAlignment="Top" Canvas.Top="20" HorizontalAlignment="Left" >
<Border x:Name="musicBG" Background="#FF0692FD" VerticalAlignment="Top" HorizontalAlignment="Left" Height="270" />
</ScrollViewer>
Image of bad scroll with bad code:
Good working code:
<ScrollViewer ManipulationMode="Control" x:Name="songScrollViewer" Width="720" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Disabled" Height="270" VerticalAlignment="Top" Canvas.Top="20" HorizontalAlignment="Left" >
<Canvas x:Name="musicBG" Background ="#FF0692FD" Height="270" >
<Border Background="#FF0692FD" VerticalAlignment="Top" HorizontalAlignment="Left" Height="270" />
</Canvas>
</ScrollViewer>
Good Scroll: Notice it says 170 seconds on the bottom right instead of the smaller number of 118 seconds in the bad scroll.
I believe your right, wp7 won't render shapes that are bigger then 2048 pixels. So the reason it's scrolling of the page is because it's treating it as if it were bigger then 2048 but you can only see up to a width of 2048px and its just scrolling over to the "ghost" part of the rectangle.
I'm not sure if you can override this but the best solution I could come up with (without overriding) is by splitting up your rectangle into chucks that are smaller then 2000 (just to be safe) and then displaying them seamlessly in a horizontal stack panel inside the scroll viewer. The problem with this is that depending on how you've coded it, this solution might be hard to implement; but you might just be able to split it in your ViewModel when displaying it and your logic would only see it as one big chunk.
I have a grid inside a canvas on a tab.
The grid contains a large bitmap image,
I have(tried to) bound the size of the grid to the size of the tab and also have a five pixel margin around the grid.
imageTab.cs
public ImageTab(SendInfo sendInfo, int numImge, int numAccs)
{
imageDisplay = new ImageDisplay(sendInfo, numImge, numAccs);
imageDisplay.ClipToBounds = true;
CreateCanvas();
}
private void CreateCanvas()
{
Canvas canvas = new Canvas();
canvas.Children.Add(imageDisplay);
this.AddChild(canvas);
}
ImageDisplay.xaml
<UserControl x:Class="MyProj.ImageDisplay">
<Grid Margin="5,5,5,5" Height="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=TabControl, AncestorLevel=1}, Path=ActualHeight}">
<Image/>
</Grid>
</UserControl>
The grid comes off the bottom of the tab area slightly causing the bottom of the image to be cut off.
Is there a problem with my databinding, do I need to apply some sort of offset to it? (size of tab - 10pixels for the margin?)
You don't need to set the Height property at all (also realize that it is incorrect to do so as you have it when you consider the 5 pixel margin, i.e., it would be off by 10 pixels).
Just leave VerticalAlignment and HorizontalAlignment at their default values (which is Stretch) to get the effect you are after here.
Try this on a new Window to see what I mean:
<Window x:Class="WpfApplication9.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="438" Width="587" Background="Pink">
<Grid Background="Black" Margin="5">
</Grid>
</Window>
The grid here will be black and will always stretch to the size of the window, using a 5 pixel margin which you will see because the Window's back color is pink.