Putting Canvas Inside Viewbox in Silverlight With Image - silverlight

All,
I'm trying to make the silverlight app I'm making resize in a reasonable manner. To do this, I thought I would use a dynamic grid. In the center of the grid I need to put an image inside of a canvas because I will dynamically be positioning objects on top of it. Ideally, as the user makes the browser window larger, the center column would be able to resize and grow larger, thereby growing the image.
Here's what I've got:
<Viewbox Grid.Row="0" Grid.Column="1">
<Canvas x:Name="cvsCenterPane">
<Image x:Name="imgFormImage" MouseLeftButtonDown="imgFormImage_MouseLeftButtonDown"
MouseLeftButtonUp="imgFormImage_MouseLeftButtonUp" MouseMove="imgFormImage_MouseMove" />
</Canvas>
</Viewbox>
In the code behind, I then set the image source.
Here's my grid definition:
<Grid x:Name="LayoutRoot" Background="DarkCyan" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="300" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
I think there must be some sort of unhandled exception occurring during the construction of the Viewbox because the image does not display at all. What am I doing wrong here? Am I taking the wrong approach?

There is no exception, the canvas just does not have any set dimensions which is a requirement when you want to use a ViewBox.
I for one would not use a canvas, you can stick with the grid since you can place more than one control in a cell and if you need to move the objects around you can use the Margin or a TranslateTransform in the RenderTransform property.

This does not work because you cannot set the x:Name attribute of children in a Viewbox with silverlight. At least according to a few sources:
http://blog.ningzhang.org/2008/11/viewbox-control-in-silverlight-toolkit.html
http://forums.silverlight.net/forums/p/48535/128830.aspx
http://forums.silverlight.net/forums/p/45789/123941.aspx#123941
this seems to be by design. A few workarounds have been suggested, so I will try them.
Edit: HB seems to be correct, there is no exception, the Canvas needed to have dimensions set.

Related

How do I bind the height of a StackPanel to the height of the containing Grid in WPF?

Im relatively new to WPF so I'm sorry in advance if there is a simple solution to this. However, I am trying to bind the height of a StackPanel to its containing Grid. I understand that a StackPanel automatically resizes to fit its elements but I would like to bind it to the Grid so that it does not do this. Right now the stack panel does not resize with the window since it remains the
size it needs to be in order to fit its elements.
Here is what I have so far:
<Grid x:Name="MainGrid" Grid.Row="2" Margin="1" Drop="Grid_Drop"
AllowDrop="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="175"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel x:Name="SidePanel" Grid.Column="0" Height="{Binding
ActualHeight, ElementName=MainGrid, Mode=OneWay}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition/>
</Grid.RowDefinitions>
<local:DeviceTreeView x:Name="deviceTree" PyngInfo="{Binding
PyngSystemVm.PyngInfo}" Grid.Row="0"/>
</StackPanel>
<-- There is more code here but it is not important for answering this
question -->
</Grid>
I tried binding the height of "SidePanel" to the actual height of "MainGrid" but when I run this code and inspect the elements the Grid resizes with the window but the StackPanel does not. The StackPanel and the Grid even have different heights which doesn't make sense to me as their heights should be bound together.
I have also tried wrapping the entire StackPanel in a border and binding to that but that also did not work.
You don't need to bind the height of the StackPanel, simply setting its VerticalAlignment to Stretch will do it. However... You are still not going to get what I think you want. The StackPanel only stacks its child controls, it does not adjust them (at least not in the "stack" direction). Look into using a different control like Grid or UniformGrid or just expand your existing grid to have rows as well as columns.

Recreating WinForms layout in WPF

I've just inherited an old WinForms app with a UI layout like this:
I'm tasked with updating several things about the software one of which is porting it to WPF which I've not previously worked with. I'm also told that the new WPF UI must look identical to the existing UI layout so I'm trying to figure out how to create that layout in WPF. I need a toolbar across the top of the window which stretches the entire width of the fixed-size window. Can I do that in the default grid or do I need a dockpanel to do that? Also, I'm assuming that I would use a grid with 2 columns and 3 rows to layout the six groupboxes?
Anything you can do with a DockPanel can also be done with a Grid -- the DockPanel is just a shortcut. So yes, you can do all this with the default Grid.
As for how to do the layout: it depends on how you want things to resize. Does everything stay proportional when you resize? If so, a single Grid with three columns (and percentage sizes for the ColumnDefinitions) would be fine. You would actually need four rows, though, not three -- the first RowDefinition would be for the ToolBar (using ColumnSpan="3") and would need Height="Auto" so it uses the ToolBar's default size; the remaining rows would be percentage-sized.
Try that, see if it works for you. If the resizing needs to be more complicated than just proportional, then post a second screenshot of the window at a different size, and we could try to help you further.
Personally I would use a DockPanel for the Menu/Content areas, then use a Grid in the Content Area to define the GroupBoxes
<DockPanel>
<Grid x:Name="MenuRegion" DockPanel.Dock="Top" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" />
<Grid Grid.Row="0" Grid.Column="2" />
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" />
<Grid Grid.Row="1" Grid.Column="2" />
<Grid Grid.Row="2" Grid.Column="0" />
<Grid Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" />
</DockPanel>
Of course, you could also make the Menu area part of the Grid and set it to span all rows, but I personally like keeping them separate.
Grid with 3 row (one for the menu). Since you have uneven spacing in the rows just a single column on the main grid. Then grid in the grid for the two column spacings.

How to put image on top of fullscreen

I am creating silverlight video player.
I have organized my player as grid.
First row is video, second and third are control panels with buttons.
When I switch to fullscreen mode I want to set specified image on the top.
So i load image, resize and can't make this image to cover all elements(video,panels).
I try to make this image only visible, and cant do that.
I think there is possible to create an "element" and set it somehow to cover.
I would like do this like splash because i guess collapsing my rows isn't good idea.
Thanks in advance.
You should be able to do this by first making sure your image element is the last child in the Grid and by adding Grid.RowSpan value to it containing the number of rows in the grid:-
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<MediaElement ... />
<StackPanel Orientation="Horizontal" Grid.Row="1">...</StackPanel>
<StackPanel Orientation="Horizontal" Grid.Row="2">...</StackPanel>
<Image Source="SomeImageUrl" Grid.RowSpan="3" />
</Grid>
An alternative to placing the Image at the end of the Grid's child list is to give it a higher ZIndex using rather unintuitively Canvas.ZIndex property.

WPF Layout Performance-Penalty using ColumnSpan

I have a Grid that looks something like the simplified example showed below. There are more elements in the grid but the problem is about the ListBox and the TextBlock.
If the TextBlock (or any other element with the same grid-configuration) has a ColumnSpan of two, every Update to an Item of the ListBox is very slow. I have looked with Perforator and VisualProfiler but could not see any special thing. If I set the second ColumnDefinition to a fixed width, all works as desired. The same happens, if I set the first RowHeight to a fixed height.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2">The column-span of this TextBlock seems to lead to an refresh-problem</TextBlock>
<ListBox Grid.Row="1" Grid.Column="1" ItemsSource="{Binding}"></ListBox>
</Grid>
Has someone a deeper insight into this and can explain me if this construction is a no no or what else here happens.
The problem is that the listbox creates all visual elements in the list to figure out which is the widest since your GridColumn is set to Auto in width. If your list contains many items or has a complicated (heavy) ItemTemplate, you're in trouble.
Normally, the ListBox only creates visual elements for visible elements (this is done by the VirtualizingStackPanel inside the ItemsPanelTemplate.
An alternative is to set a default width that will work 95% of the time - and then use a GridSplitter in the next column for the last 5% (So the user can widden the list). Alternate, you can use another Panel (e.g. a DockPanel) that doesn't ask the ListBox how wide it wants to be... :-)

easiest way to center an image in silverlight?

Say I have a grid with 3 rows. In the center row I'd like to put an image and then center it in that row vertically and horizontally. But since (I think) Silverlight uses upper left corners of an element when it centers, the upper left corner of the image is centered when I tell it to center vertically/horizontally.
I've seen 2 approaches to this:
modify the image position in an event
set the image's margin to a very large number on all sides (500)
Is there an easier way? Seems kinda weird that you'd need to do something hacky like those 2 approaches. I'd prefer to just tell the thing that its anchor is in the center and then tell it to center. Hmmm, could be a good custom control.
Update: the really obnoxious thing about this was when I made a minor change to the page to change how that image was centered and FF3 displayed an old version of the page. Which made me think that it didn't work. Then I pulled it up in IE and it looked right. I flushed FF3's cache and it displayed the right page. Damn annoying.
Why wouldn't this work for you?
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Source="Butterfly.jpg"
Height="50" Width="50"
HorizontalAlignment="Center" VerticalAlignment="Center"
Stretch="UniformToFill"
Grid.Column="1" Grid.Row="1" />
</Grid>

Resources