How to organize elements inside a Button - wpf

i'm new to wpf .
i got a wpf button ,
in it i need to place 2 elements a textblock and a viewbox encapsulating a canvas
the problem is i can't seem to see the canvas at all , unless i give it static values for its size
<Button Margin="10,30,10,10" Padding="0">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="Me" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></TextBlock>
<Viewbox Margin="0,0,0,5">
<Canvas Background="red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="1" >
<Ellipse HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="Black" StrokeThickness="4" ></Ellipse>
</Canvas>
</Viewbox>
</Grid>
</Button>
iv'e also attempted this using a stack panel with an horizontal orintation
in any case the canvas does not show
any thoughts of what i'm doing wrong ?
thanks.

Attached Grid properties only work when at the Grid-child-level, i.e. the properties set on the canvas do not take effect they should be set on the container, the ViewBox which is a direct child of the Grid.
Viewboxes only work if the content has a concrete size, you probably need neither the ViewBox nor the Canvas. If you want the Ellipse to be a circle set Stretch="Uniform"
The contents of Buttons do not stretch by default you should set HorizontalContentAligment and its vertical counterpart to Stretch.
e.g.
<Button Margin="10,30,10,10" Padding="0" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Me" Grid.Row="0" Grid.Column="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"></TextBlock>
<Ellipse Stretch="Uniform" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Stroke="Black" StrokeThickness="4"></Ellipse>
</Grid>
</Button>

Related

Layout problem with autogenerated DataGrid in WPF/XAML

I've got a problem with WPF/XAML. I can't figure out how to let the left Grid (with a centered image inside and backgroud color) grow its height, depending on the autogenerated height on the datagrid on the right.
They both are presented in a global grid. If I set a fixed height on the corresponding row, the autogenerated datagrid shows a cruel vertical line, depending on the fixed row-height I set before.
layout with row-height on auto
layout with fixed row-height, but with ugly line at the bottom
<!--ElementR0C1-->
<Grid Name="test">
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!--Width ElementsC1-->
<ColumnDefinition Width="160"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="500"/>
</Grid.ColumnDefinitions>
<!--START-->
<Label Grid.Row="0" Grid.Column="0" Style="{StaticResource L1}" VerticalAlignment="Top">Process</Label>
<Grid Grid.Row="1" Grid.Column="0" Background="DDDDDD">
<Image Margin="0,30,0,0" Height="64" Width="64" Source="../../Resources/ok.png" Name="imgJobs" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
<DataGrid x:Name="grdJobs" Grid.Row="0" Grid.Column="2" Grid.RowSpan="2" Width="500">
-- some stuff here
</DataGrid>
</Grid>

How to position WPF nested controls absolutely in a window

I have some controls nested in some panels.
The panels themselves are not arranged with the same x position within a window.
I'd like the controls inside the panels to have a fixed position relative to the window, not the panel (so they all line up vertically, in this case).
To be clear, the Panels themselves have an arbitrary position in the window. One can imagine that the user should be able to effect the Panel positions, but the nested controls would stick to the same X coordinate relative to the window.
I don't think I can use a Canvas, because that's positioning relative to the edges of the canvas.
Any ideas?
Many thanks.
Don't use Panels... instead, use Grids. If you use Grids, then you can take advantage of the Grid.IsSharedSizeScope Attached Property and the ColumnDefinition.SharedSizeGroup Property. Using these, you can line up columns from different Grids, as long as you have a parent Grid with the IsSharedSizeScope property set to true.
Here is an example taken from the first linked page on MSDN:
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<Grid ShowGridLines="True" Margin="0,0,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>
<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0" Width="200" Height="100"/>
<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0" Width="150" Height="100"/>
<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>
<Grid ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="FirstColumn"/>
<ColumnDefinition SharedSizeGroup="SecondColumn"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
</Grid.RowDefinitions>
<Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0"/>
<Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0"/>
<TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
<TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>
</StackPanel>

How do I retrieve column width in a WPF Grid using a GridSplitter?

I need to display to the user two listboxes - one on either side of the window - and allow the user to choose how much screen space is devoted to each. I have achieved that much with the following code:
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding FirstColumnWidth}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ListBox Name="FirstColumn" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="0" />
<GridSplitter Name="gridSplitter1" Width="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="1" />
<ListBox Name="SecondColumn" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Grid.Row="0" Grid.Column="2" />
</Grid>
However, whilst the binding will retrieve an initial width for the first column and size them both accordingly, using the GridSplitter to resize them simply replaces the binding with the new value. How can I retrieve the new value so that I can persist it?
Ideally, the solution needs to play nicely with MVVM - I'm using Caliburn and trying to keep the code as clean as possible (my view model contains the FirstColumnWidth property that is currently being bound).
There are two solutions that I can think of.
1. Use the different binding modes available and the Width and ActualWidth properties.
Example
<Grid VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Path=FirstColumnWidth, Mode=OneTime}" />
<ColumnDefinition Width="3" />
<ColumnDefinition Width="{Binding Path=SecondColumnWidth, Mode=OneTime}" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid Grid.Column="0" ActualWidth="{Binding Path=FirstColumnWidth, Mode=OneWayToSource}">
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
<GridSplitter Grid.Column="1" Width="3" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid Grid.Column="2" ActualWidth="{Binding Path=SecondColumnWidth, Mode=OneWayToSource}">
<ListBox HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
</Grid>
</Grid>
or
2. Override the current/default behaviour of the grid splitter using the attached behaviour pattern (tutorial on CodeProject). I will post of code sample for this tomorrow when I'm at my desk.

WPF: Problem with overlapping controls and grid column widths

I have a problem regarding a parent grid with a control in it that overlaps a tabcontrol.
I need the child grid (in the tab control) to resize its columns according to the overlapping control.
Specifically, when the overlapping control is resized (due to resize of the window for example) the child grid inside the tabcontrol needs to resize its columns so that the child controls inside the tabcontrol grid isn't overlapped by the control that overlaps the tabcontrol.
I sincerely hope someone here knows a solution for this problem, I've been fighting with it for days :)
Thanks in advance!
Best regards,
Req
edit: In response to the comments below:
Absolutely - I figured I should have, but seeing that I was/am at work I didn't have the code handy. But I can write up a similar example of the XAML.
<Grid Name="parentGrid" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<TabControl Name="tabCtrl" Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="1" Grid.RowSpan="2">
<TabItem Name="tabItem1">
<Grid Name="tabCtrlGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" /> <!-- This is the column I want to resize according to the overlapping image control below -->
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Button Name="someChildControl" Grid.Column="1" Grid.Row="0" />
</Grid>
</TabItem>
</TabControl>
<Image Name="overlappingImg" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Grid.RowSpan="2" /> <!-- whenever the screen/window is resized, the parentGrid resizes, and thus resizing this overlapping image. -->
</Grid>
What needs to happen is that column 0 in the tabCtrlGrid needs to resize its width to fit the width of the overlapping area of the image. That way someChildControl is never overlapped by the image, regardless of how it's resized.
Hopefully that makes it a little more clear :)
How does this look?
<Grid Name="parentGrid" Background="LightGray">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Rectangle HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Aqua"/>
<TextBlock Text="Tab controller" HorizontalAlignment="Stretch" VerticalAlignment="Bottom"/>
<Rectangle Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="Aqua"/>
<TextBlock Text="Up down nav" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
<Grid Grid.ColumnSpan="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Rectangle HorizontalAlignment="Left" VerticalAlignment="Top" Width="130" Height="160" Fill="BlanchedAlmond"/>
<TextBlock Text="CoverArt" HorizontalAlignment="Left" VerticalAlignment="Top" Width="130" Height="160"/>
<Rectangle Grid.Column="1" Fill="LightGray" />
<TextBlock Text="Tab content" Grid.Column="1" />
</Grid>
</Grid>

Drag N drop images in a viewbox

I have a usercontrol with 6 viewbox, each can have an image. I have not set the width or height of the usercontrol(not even the viewboxes). At first the viewboxes are empty.I can add the images dynamically.
<Grid x:Name="DashBoardGrid" DockPanel.Dock="Right">
<Grid.RowDefinitions>
<RowDefinition Height="20"></RowDefinition>
<RowDefinition Height="200*"></RowDefinition>
<RowDefinition Height="10"></RowDefinition>
<RowDefinition Height="200*"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"></ColumnDefinition>
<ColumnDefinition Width="200*"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="200*"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="200*"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Border Grid.Row="1" Grid.Column="1">
<DockPanel x:Name="dockPanel1" Margin="10,30,10,10" >
<TextBlock x:Name="TitleTxtblk1" DockPanel.Dock="Top" FontSize="10pt" TextWrapping="Wrap">screen 1</TextBlock>
<Viewbox x:Name="Viewbox1" MouseDown="Viewbox_MouseDown" MouseEnter="ScaleUp" MouseLeave="ScaleDown"
PreviewMouseLeftButtonDown="DockPanel_PreviewMouseLeftButtonDown" PreviewMouseMove="dockPanel_MouseMove"
Drop="dockPanel_Drop" DragEnter="dockPanel_DragEnter" AllowDrop="True">
</Viewbox>
</DockPanel>
</Border>
<Border Grid.Row="1" Grid.Column="3" >
<DockPanel x:Name="dockPanel2" Margin="10,30,10,10" >
<TextBlock x:Name="TitleTxtblk2" DockPanel.Dock="Top" FontSize="10pt" TextWrapping="Wrap">screen 2</TextBlock>
<Viewbox x:Name="Viewbox2" MouseDown="Viewbox_MouseDown" MouseEnter="ScaleUp" MouseLeave="ScaleDown"
PreviewMouseLeftButtonDown="DockPanel_PreviewMouseLeftButtonDown" PreviewMouseMove="dockPanel_MouseMove"
Drop="dockPanel_Drop" DragEnter="dockPanel_DragEnter" AllowDrop="True">
</Viewbox>
</DockPanel>
</Border>
I want to drag and drop the images from one viewbox to any other empty viewbox. But when the viewbox is empty, it is not visible at all. because it does not have a height or width. So i am not able to drop the image on it.
So what will i have to to such that when any one view box has an image all the view box have the same height and width? any other solution is welcome.
You could handle the drag/drop events in a parent control like the Border. And then you probably need a reference to your viewbox in your drag/drop methode. Try this:
<Border Tag="{Binding ElementName=Viewbox2,Path=.} … >
and in your drag/drop methode
ViewBox v = (sender as Border).Tag as ViewBox;

Resources