WPF control origin point - wpf

After some investigation, I still can't find method to change origin of control.
So, I want just to place one square exactly in center of another square, without margins, so it will be completely independent of first square size.
Theoretically, it can be easily done with HorizontalAlignment and VerticalAlignment set to Center, since it automatically sets Margin of control to half of width and height of parent control. But it is not so simple.
Simplest way to describe problem is next picture
As you can see, margin is counted towards upper left corner. Which is what I call origin. The perfect solution is to change it to center of first square, but this is where I need help - how can I do that?

Point of origin applies when using a transform object, and attaching the transform to your control. It won't actually effect the behaviour of the margin or left, top properties. If using a transform to place your object, point of origin is very useful.
The top, left (if using cavas) and margin (if using say grid) help govern the "auto" placement by the parent control, and this in turn governs where point of origin for the control winds up being relative to the parent control. The transform object then offsets RELATIVE to where that point of origin is.
The other useful thing is that transform overrides the auto placement in the parent control, or rather, forces an offset to where the parent wants to put it, which in some cases is useful - i.e., you might have boxes listed in a grid and want them to "shake" left and right when you hover the mouse over them, their alignment stays in order to the grid, but the transform lets you bump them away from their "forced" position.
For example, attach the same transform object to 2 controls, and set their origins separate, then apply an animation to the transform object - both controls will animate off the one animation object (if you wanted to their movement in perfect sync).

Well, it was weird enough. The given behaviour can be seen only when using Image, and Center alignment. Can be solved by either wrapping Image in Grid, which will be using Center alignment, or using Stretch alignment with Image (which is much simplier).
<Grid Width="500" Height="500">
<Image Width="250" Height="250" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
</Grid>
If you want to reproduce problem I've described in question, replace Stretch with Center in code above.

Probably oversimplifying here but I would just use a Grid to wrap the two items you mentioned like this example (One stretched to fit and one centered):
<Grid>
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" BorderBrush="Black" BorderThickness="10" Margin="4"/>
<Button HorizontalAlignment="Center" VerticalAlignment="Center" Padding="10">InnerButton</Button>
</Grid>

Related

Usercontrol, resize inside the grid

I have a typical user control with some drawing on the canvas.I have plugged that user control in a grid with following code
<Routine:FlashUserControl x:Name="FlashControl" Grid.Row="0" Grid.Column="2" Grid.RowSpan="9" Grid.ColumnSpan="2" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" />,
but the user control overflow above the grid region (as specified in the attached image) rather than fitting into the region (2 Coloumns x 9 rows)
Even Though VerticalAlignment, HorizontalAlignment, HorizontalContentAlignment and VerticalContentAlignment defined as stretch in user control, why it is happening?
UPDATE:
If I summarize the issue, my drawing entities inside the usercontrol exceeds the canvas limits, I think I need to re-scale the drawings
There can only be two reasons why a UI element that has been set into a particular section of a Grid might exceed its bounds. The fist reason might be that as mentioned in the comments, the UI element has had its Width and/or Height property values explicitly set to values that are too big for its available area. The fix for this is obviously to not explicitly set these values.
The second reason might simply be that you Grid has not been declared correctly. Perhaps you have the wrong number of rows and/or columns? Again, the fix for this is simple. Please show your Grid so that we can verify this point.

WPF item panel that keeps aspect ratio

I have an ItemsControl which may contain an arbitrary number of items (unknown at design time). Each of these items is basically represented as an infinitely-scalable image with a fixed aspect ratio (ie. the image will draw itself in whatever space is given to it -- it does not dictate its own size except that the aspect ratio must be preserved). The aspect ratio for each item might differ but is usually the same.
I want to:
Draw a border around each image, ideally of uniform thickness regardless of image scaling.
Draw each image as large as possible within the window, while maintaining its order, aspect ratio, and margins external to the border.
At least two of the four sides of an image must always touch the invisible boundaries of the cell it is within. The other two sides should be centred if not touching. (Assuming that some sort of uniform cell layout is used.)
Not overlap or clip any images.
Automatically re-layout as the containing window is resized.
Waste the minimum amount of non-image space.
Cope as well as possible if the aspect ratios of the items differ. (But it's ok if this increases the wasted space of other items, as long as they rescale to fit the result.)
The general consensus that I've found seems to be to wrap each image in a Stretch.Uniform Viewbox, and then put those into a UniformGrid. I've tried that approach but it doesn't appeal to me because:
Given two items, the UniformGrid always wants to create a 2x2 grid layout even when the window shape would make a 2x1 or 1x2 grid more suitable, which results in over-scaling and wasted space.
If I put the Border within the Viewbox then it scales the border thickness. If I put it outside then it distorts the aspect ratio.
Is there a better way to do this? (Note that the "image" is actually my own custom-draw FrameworkElement, so I can put custom measure/arrange code in here or in a custom container panel if it will help.)
<UniformGrid>
<Rectangle Fill="Red" Margin="4" Width="500" Height="281.25" />
<Rectangle Fill="Blue" Margin="4" Width="500" Height="281.25" />
</UniformGrid>
Here's a simple example. Put this into a window, then try resizing the window. The rectangles change size to fit the window (good), but they also change shape/aspect (bad), and they stop resizing once the window is sufficiently large (bad). Also it leaves space for an entire 2x2 grid even when the window itself is sized such that 1x2 or 2x1 would work better.
<UniformGrid>
<Viewbox Stretch="Uniform" Margin="4"><Rectangle Fill="Red" Width="500" Height="281.25" /></Viewbox>
<Viewbox Stretch="Uniform" Margin="4"><Rectangle Fill="Blue" Width="500" Height="281.25" /></Viewbox>
</UniformGrid>
This works marginally better in that the rectangles continue to stretch when the window gets large, and they no longer distort their shape, but there's still the needless second row when the window is wide or second column when the window is narrow. And I would prefer that the elements line up from the top left (like a WrapPanel) rather than centering, but that's a minor detail.
(And now try adding a Border, both inside and outside of the Viewbox, and see what I mean there.)
Actually a WrapPanel almost does what I want, except that it auto-sizes the items too large when the window gets smaller.

Get Width Available for Children in a Scrollviewer

How do I get the width available for the children of a scroll viewer in XAML? Thanks.
There's no direct way of doing this that I know of, since WPF automatically passes the available space in to the child controls' Measure() function so that they size to fit the available space.
Note that, by default, it passes in infinity for the vertical direction, since content can scroll forever vertically. You can change the visibility of the scroll bars in both the vertical and horizontal direction to affect whether infinity is passed vertically, horizontally, or both.
The best way of figuring out how wide the child controls actually have to layout in pure XAML would be to create an empty control - for instance, an empty grid - and then bind to its ActualWidth property:
<ScrollViewer>
<StackPanel>
<Grid x:Name="MeasureGrid"/>
<TextBox Text="{Binding ElementName=MeasureGrid, Path=ActualWidth}"/>
</StackPanel>
</ScrollViewer>
Aside from displaying the width that is actually available to controls, I don't see any other use for this information in XAML, though - all of the other scenarios I can think of can use this information implicitly. Can you give us more information on what you are trying to accomplish?

Tiling rectangles seamlessly in WPF

I want to seamlessly tile a bunch of different-colored Rectangles in WPF. That is, I want to put a bunch of rectangles edge-to-edge, and not have gaps between them.
If everything is aligned to pixels, this works fine. But I also want to support arbitrary zoom, and ideally, I don't want to use SnapsToDevicePixels (because it would compromise quality when the image is zoomed way out). But that means my Rectangles sometimes render with gaps. For example:
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Black">
<Canvas SnapsToDevicePixels="False">
<Canvas.RenderTransform>
<ScaleTransform ScaleX="0.5" ScaleY="0.5"/>
</Canvas.RenderTransform>
<Rectangle Canvas.Left="25" Width="100" Height="100" Fill="#CFC"/>
<Rectangle Canvas.Left="125" Width="100" Height="100" Fill="#CCF"/>
</Canvas>
</Page>
If the ScaleTransform's ScaleX is 1, then the Rectangles fit together seamlessly. When it's 0.5, there's a dark gray streak between them. I understand why -- the combined semi-transparent edge pixels don't combine to be 100% opaque. But I would like a way to fix it.
I could always just make the Rectangles overlap, but I won't always know in advance what patterns they'll be in (this is for a game that will eventually support a map editor). Besides, this would cause artifacts around the overlap area when things were zoomed way in (unless I did bevel-cut angles on the underlapping portion, which is an awful lot of work, and still causes problems at corners).
Is there some way I can combine these Rectangles into a single combined "shape" that does render without internal gaps? I've played around with GeometryDrawing, which does exactly that, but then I don't see a way to paint each RectangleGeometry with a different-colored brush.
Are there any other ways to get shapes to tile seamlessly under an arbitrary transform, without resorting to SnapsToDevicePixels?
You might consider using guidelines (see GuidelineSet on MSDN) and overriding the Rectangles' OnRender methods so that their boundaries line up with the pixel boundaries of the device. WPF uses guidelines to determine whether and where to snap drawings.
Internally, it's exactly what SnapsToDevicePixels is using to ensure that objects line up with the device's pixels, but by placing guidelines manually you'll be able to control when the snapping behaviour is applied and when it is not (so when your image is zoomed all of the way out, you can avoid drawing guidelines, or only draw guidelines where your shapes lie next to other shapes, and rely on WPF's anti-aliasing to take care of the rest). You might be able to do it with an attached property so that you can apply it to any element, though if it's only one type of element (e.g. Rectangle) that you need this behaviour on, it's probably not worth the extra effort.
It seems like Microsoft is aware of this problem, too - WPF 4.0 is expected to feature Layout Rounding, which, like the version in Silverlight, rounds off non-integer values at the Render pass when layout rounding has been enabled.
I guess the gaps are not actual gaps but the stroke that is painted. When you scale it down than you just make the stroke smaller to a point where it is not visible anymore. I tried to paint the stroke in the color of the rectangle wich works just fine on any scale.
&ltPage xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Background="Black"&gt
&ltCanvas SnapsToDevicePixels="False"&gt
&ltCanvas.RenderTransform&gt
&ltScaleTransform ScaleX="0.5" ScaleY="0.5"/&gt
&lt/Canvas.RenderTransform&gt
&ltRectangle Canvas.Left="25" Width="100" Height="100" Fill="#CFC" Stroke="#CFC"/&gt
&ltRectangle Canvas.Left="125" Width="100" Height="100" Fill="#CCF" Stroke="#CCF"/&gt
&lt/Canvas&gt
&lt/Page&gt

In WPF, What is the best way to create toolbar buttons so that the images are properly scaled?

Specifically, I'm looking to use the 16*16 32-bit png images included with the VS2008ImageLibrary. I've tried manually setting the Height and Width attributes of the image, adjusting margins and padding, adjusting Stretch and RenderOptions. My attempts to create toolbar buttons have all led to either Improper Scaling (blurry icons), the bottom row of pixels on the icon being truncated, or the toolbar button being improperly sized - not to mention the disappearing icons already mentioned Here. Has anyone found the best way to make standard, VisualStudio/WinForms-style toolbar buttons that display properly in WPF?
First, change the image resolution to 96DPI, this can done with the free Paint.net ( http://www.getpaint.net ) by opening the file, Selecting Image->Canvas Size from the menu and adjusting the "resolution" to 96 and saving.
If this doesn't help you can then use the solution I wrote about in my blog here http://www.nbdtech.com/blog/archive/2008/11/20/blurred-images-in-wpf.aspx
Best way would be using Vector graphics instead of png. I know the following is not exactly what you asked for, but imho there is no way for better looking icons. Also it would help you get rid off margins and paddings. (Ok, if you want to use photos you're screwed)
Bad News is you probably need to repaint all your icons. You could do this using MS Expression Blend(it's capable to save painted Images as .xaml) or you make them on our own with a texteditor.
I prefer the Border.Background instead of the Image.Source for placing the icon, this allows me to put text over the image. This would look samething like that:
<Window.Resources>
<ResourceDictionary Source="Resources/Icons.xaml"/>
</Window.Resources>
<!--
...
-->
<Button>
<Border Background="{StaticResource IconName}" Height="16" Width="16" />
</Button>
The best workaround I can come up with is this:
<Image x:Key="TB_NewIcon" Source="Toolbar Images/NewDocumentHS.png" Height="16" Width="16" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
...
<Button Command="ApplicationCommands.New" Content="{StaticResource TB_NewIcon}" Padding="2,2,2,1"/>
Or Alternatively:
<BitmapImage x:Key="TB_NewIcon" UriSource="Toolbar Images\NewDocumentHS.png"/>
...
<Button Command="ApplicationCommands.New" Padding="2,2,2,1">
<Image Source="{StaticResource TB_NewIcon}" Height="16" Width="16" SnapsToDevicePixels="True" RenderOptions.BitmapScalingMode="NearestNeighbor"/>
</Button>
For the Button Tag, the Padding attribute is needed to ensure that the image isn't truncated at a height of 15 pixels, and that the button isn't resized to fit the image. Alternatively, we could specify Padding="1", but then we must manually set Height="21" and Width="22" to ensure the button isn't resized to fit the image
On the Image Tab, the Height and Width are needed to ensure that the image isn't stretched. SnapsToDevicePixels and RenderOptions.BitMapScalingMode are both needed to ensure that there is no blurring. I can't promise that this will work nicely for all resolutions.
Note:
For the NewDocumentHS.png icon, the one that causes the most issues,as it takes up the full 16 pixels of height, you may want to adjust the padding to "1,1,3,2", so that the bottom aligns more properly with other icons.
You may want to consider trying a new property available now in WPF4.
Leave the RenderOptions.BitmapScalingMode to HighQuality or just don't declare it.
On your root element (i.e. your main window) add this property: UseLayoutRounding="True".
A property previously only available in Silverlight has now fixed all Bitmap sizing woes. :)
Please Note - a few of the effects layout rounding
can have on exact layout:
width and or height of elements may grow or shrink by at most 1 pixel
placement of an object can move by at most 1 pixel
centered elements can be vertically or horizontally off center by at most
1 pixel
More info found here: http://blogs.msdn.com/text/archive/2009/08/27/layout-rounding.aspx

Resources