Perfect Center on WPF Canvas - wpf

Since the canvas requires a Top/Left for placement, if you want to center something, is adding a grid at the proper Canvas.Top with HorizontalAlignment="Center" the best way to do it, or is there a better way?
This snip is a 150X300 canvas, with some content centered in a grid ....
<Canvas Width="150" Height="300">
<Grid Canvas.Top="75" Width="106" HorizontalAlignment="Center">
{whatever you want centered}
</Grid>
</Canvas>

Guy's solution works, but you may have to tweak z-order and visibility if you're juggling hit testing.
Another alternative is having the Grid inside the Canvas (as you've specified in your XAML) with the Height/Width set to (or bound to) the Height/Width of the Canvas. Then setting HorizontalAlignment/VerticalAlignment to Center for the contents of your Grid.

I'm not sure if this will meet your exact requirement, but if you put both the canvas and the content inside a grid as peers, it will get you a centered result:
<Grid>
<Canvas Width="150" Height="300"/>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Width="106" Content="Click"/>
</Grid>

Related

How do I properly draw and scale a Canvas as a WPF background to a control?

I have a StackPanel that needs to contain drawn background. Specifically, my StackPanel needs to have the ability to grow and the rectangle must grow with the StackPanel, but must remain pseudo-anchored to each side at a fixed position.
I've attempted to use the Canvas.Left, Canvas.Right, Canvas.Top and Canvas.Bottom attached properties, but so far they've not worked. Furthermore, this does seem to work when drawing within Canvas objects, just not when they are embedded within a VisualBrush set as a background. How can I accomplish drawing this resizable, rectangular background within my StackPanel?
Below is the state of my current code. I've tried various approaches but none seem to work.
My Code:
<StackPanel DockPanel.Dock="Right" Orientation="Vertical" VerticalAlignment="Center">
<StackPanel.Background>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<Canvas Background="Magenta" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
Rectangle Fill="#FFDDECF7" Canvas.Left="20" Canvas.Top="20" Canvas.Bottom="20" Canvas.Right="0"/>
</Canvas>
</VisualBrush.Visual>
</VisualBrush>
</StackPanel.Background>
...
</StackPanel>
This currently doesn't render anything. I set the canvas background to magenta just so I could see if it were drawing, and I'm not even seeing that. Other attempts have drawn the canvase, however, the blue rectangle is always stretched to fill the window, regardless of attached canvas property settings.
Sample:
The image below is a sample of what I want. Again, I'm using an ugly Magenta color to show the offset of the internal, blue rectangle. As the StackPanel grows or shrinks, the rectangle needs to be affixed to the top, left, right and bottom.
My suggestion is to place the stackpanel inside a grid:
<Grid DockPanel.Dock="Right" VerticalAlignment="Center" Background="Magenta">
<Rectangle Margin="20" Fill="#FFDDECF7"/>
<StackPanel Orientation="Vertical">
no background...
</StackPanel>
</Grid>
Wrap Canvas into a ViewBox, then work on a ViewBox. As far as I know Canvas doesn't support scalling too well.

Changing Height of ScrollViewer Content dynamically through code

I'm stuck at a point where I have to change the height of scroll viewer content irrespective of the size the contents inside it need.
The reason is that I will have a very long Image and I don't want to slow my GUI while scrolling. So,I cut the long image and I render stitched images of it depending on current scrollviewer vertical offset.
I tried to achieve it by putting a Hidden Long image so that it won't render on scroll and there won't be any lag. But I don't feel good about it.
Can someone help me to dynamically increase the ScrollViewer content Height?
The code is here:
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="9" Grid.RowSpan="12" Margin="10,60,10,0" >
<Image x:Name="StitchedImage" SnapsToDevicePixels="True" HorizontalAlignment="Stretch" Stretch="Fill"/>
<ScrollViewer x:Name="ImageScrollViewer" Background="Transparent" ScrollChanged="ImageScrollViewer_ScrollChanged" VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Disabled">
<Grid VerticalAlignment="Top" HorizontalAlignment="Left" >
<Image x:Name="longImageHidden" SnapsToDevicePixels="True" Visibility="Hidden"/>
</Grid>
</ScrollViewer>
</Grid >
I think It would be really cool if I can just give a blank image specifing just height and width without any source. Is that even possible?
Yes, it is:
<Image Height="1000" />
You could also set the Height of a ScrollViewer and any other FrameworkElement derived type.

WPF: Using Grids

I created a grid and inside this grid it contains a TextBlock. When I maximize or adjust the size of the window the content of the TextBlock doesn't stay in the center of the Grid.
Tried to keep this as short as possible. :>
<Grid>
<Grid HorizontalAlignment="Left" Height="46" VerticalAlignment="Top" Width="515">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Welcome! Use the functionalities below.</TextBlock>
</Grid>
</Grid>
Grids, by default, auto expand. That is, they take up as much area as they are allowed. Your outer grid will take up the entire client area of the window while the inner grid will stick to the top left of the outer grid, just as you have coded it to. If you want the inner grid to be centered, then do something like
<Grid>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="46" Width="515">
<TextBlock VerticalAlignment="Center" HorizontalAlignment="Center">Welcome! Use the functionalities below.</TextBlock>
</Grid>
</Grid>
You don't even have to include the horizontal and vertical alignment as grids will automatically centre.
If you just want to centre the TextBlock ...
<Grid>
<Grid>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Height="46" Width="515">Welcome! Use the functionalities below.</TextBlock>
</Grid>
</Grid>
The text can be centred using the TextAlignment property.
I hope this helps

Why ZIndex is not considered in arrange override of a stackpanel

Here is what I tried to to:
Added a stackpanel to my window (Orientation: Horizontal)
Added a set of buttons to it
Set the first button's ZIndex to be higher than the second one
Increased the width of the first button
What I expected:
I expected the first button to be on top of the second button (atlest overlay)
StackPanel's width should not change unless the width of the first button is no more sufficient
What is happening actually:
First button's width increases and the second button moves towards the right accordingly. They stay on the same plane
StackPanel's width increases with increase in the first button's width
Here is my question:
I know that stackpanel has not considered ZIndex while arranging the items within itself, BUT WHY?? Shouldn't it consider the ZIndex of its children while arranging them???
The Stackpanel 'stacks' its children based on their widths, i.e. if you increase the width of an item (or increase its margin), the stackpanel will simply expand to accomodate this. If you want to force items within a stackpanel to overlap, you will have to change their location after the layout has been computed. You can perform this using a RenderTransform. See the example below:
<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
<Button Content="One" Canvas.ZIndex="10">
<Button.RenderTransform>
<TranslateTransform X="10"/>
</Button.RenderTransform>
</Button>
<Button Content="One"/>
<Button Content="One"/>
<Button Content="One"/>
</StackPanel>
And yes, the ZIndex is respected. This is an attached proepry of Canvas, however, it seems to be used by the rendering engine directly rather than by Canvas, hence it works in the above code.
I tried to find some relevant info about how to set the z index of wpf layout elements and panels. Using a Canvas comes with a different set of positioning issues which I simply hadn't the time to investigate. Here is a simple solution using the Panel.ZIndex property in xaml.
<Grid>
<Border Width="100" Height="100" Margin="0,0,50,50" Panel.ZIndex="1" Background="Navy" Opacity="0.3"
VerticalAlignment="Top" HorizontalAlignment="Left">
</Border>
<Border Width="100" Height="100" Margin="50,50,0,0" Background="Fuchsia" Opacity="0.3">
</Border>
The resulting two square border elements will overlap. One can use stackpanels instead of borders and use this logic to overlap anything easily.
Here is the same code adapted to the button problem:
<Grid>
<StackPanel Panel.ZIndex="10" Margin="20,20,0,0" HorizontalAlignment="Left">
<Button Content="One" Width="50" Height="40">
</Button>
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="50,0,0,0" >
<Button Content="Two" Width="50" Height="40"/>
<Button Content="Three" Width="50" Height="40"/>
<Button Content="Four" Width="50" Height="40"/>
</StackPanel>
</Grid>

WPF <StatusBar> is not positioned at the bottom of the window

We have a WPF executable that creates a and then dynamically loads several assemblies. Each assembly represents a screen (.xaml) that is displayed in one of the tabs. The Problem is that the is right under the and not at the bottom of the window. How do I force the to always be at the bottom of the
window? Thx!
UserControl
DockPanel
CheckBox
StatusBar
DockPanel
UserControl
In addition to ArsenMkrt's answer about including the DockPanel.Dock="Bottom" attribute, don't forget that the LAST element in a DockPanel will fill the area unless you explicitly tell it otherwise using a height command (regardless of the DockPanel.Dock attribute provided).
my suggestion is to do thus:
<UserControl>
<DockPanel>
<StatusBar DockPanel.Dock="Bottom" />
<CheckBox />
</DockPanel>
</Usercontrol>
I had the same problem just now. Thanks to Stephen Wrighton's tip that the last element added to a DockPanel fills the area left over, I figured out how to set up my Window. It was a bit weird since I added the Grid last but it was positioned in the middle.
<Window>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
</MenuItem>
</Menu>
<StatusBar DockPanel.Dock="Bottom">
<StatusBarItem Content="Filler" />
</StatusBar>
<Grid x:Name="rootGrid">
</Grid>
</DockPanel>
</Window>
Did you try?
<StatusBar DockPanel.Dock="Bottom" ... />
In my case adding DockPanel.Dock="Bottom" was not enough I was forced to add VerticalAlignment="Bottom" as well.
<StatusBar DockPanel.Dock="Bottom" VerticalAlignment="Bottom" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0"/>
<StackPanel Grid.Row="1">
<StatusBar>Status Text</StatusBar>
</StackPanel>
If a StatusBar control in WPF is not positioned at the bottom of the window, there are several potential causes for this issue:
The StatusBar is not placed inside the bottommost container of the window: Make sure the StatusBar is inside the bottommost container of the window, such as a Grid or StackPanel, and that it is placed in the last row of the container.
The container's vertical alignment is not set to "Bottom": Ensure that the container that holds the StatusBar has its VerticalAlignment property set to "Bottom".
The window's height is not being set correctly: Make sure that the window's height is being set correctly, and that it is large enough to accommodate the size of the StatusBar.
The layout of the window is not correct: Check that the layout of the window is correct and that all elements are positioned correctly. You can use the Snapping and Guides feature of the Visual Studio Designer to align elements correctly.
The window is using a template that does not include the StatusBar, if you are using a custom template for the window, check that it includes the StatusBar and that it is positioned correctly.
By troubleshooting these potential causes, you should be able to resolve the issue and position the StatusBar at the bottom of the window.
In my case the order of how I put the children into the Dockpanel had an influence. So, this was the correct order to fill proberly:
<Button DockPanel.Dock="Top" Height="50">Top</Button>
<Button DockPanel.Dock="Bottom" Height="50">Bottom</Button>
<Button DockPanel.Dock="Left" Width="50">Left</Button>
<Button DockPanel.Dock="Right" Width="50">Right</Button>

Resources