Canvas overlaps parent border - c#

I'm struggling with a layout problem. My usercontrol contains a border, with a canvas as a child.
This canvas contains a grid, and that grid contains 2 canvas (1 column and 2 rows with different colors).
My problem is that the grid overlaps the border on his right side, and I don't know why. I tried to set the ClipToBounds property of my main canvas to "True", but with no effect.
Can you help me ?
Here is the problem :
And here is the code :
<Border Name="MainBorder" BorderBrush="Black" BorderThickness="1">
<Canvas Name="MainCanvas" Height="30" ClipToBounds="True">
<Grid Width="{Binding ElementName=MainCanvas, Path=ActualWidth}">
<Grid.RowDefinitions>
<RowDefinition Height="5" />
<RowDefinition Height="5" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Canvas Name="CanvasTop" Grid.Row="1" Grid.Column="0" Background="Beige" />
<Canvas Name="CanvasBottom" Grid.Row="0" Grid.Column="0" Background="LightGray" />
</Grid>
</Canvas>
</Border>
Thank you for your help.

I think it is your Width="{Binding ElementName=MainCanvas, Path=ActualWidth}" line which is causing that.
Instead of the width property can you try HorizontalAlignment="Stretch" ?? this will make sure that it uses the whole width

Problem solved, there was a function in the code-behind that resized the control the wrong way :
public void SetMainCanvasWidth(double size)
{
Width = Math.Max(2, size); // that line was evil. removed it and it runs
MainCanvas.Width = Math.Max(2, size);
}
Thank you for your help.

Related

How to keep canvas a fixed size while stretching its container

I am trying to make a really simple editor for images. Since the control panel is showed right next to the Canvas, I'd like to put a border between them (I am open to suggestions like a GridSplitter though). I have the Canvas nested in a ScrollViewer nested in a Border. When the image loads in the Canvas, if I resize the window I the image resizes with everything else. Since I am editing this image, I'd like to keep it to its original size and, if the Canvas is to big, use the ScrollViewer to handle that. I don't know if it is more recommendable to put the border around the Control Panel instead.
XAML Code:
<Border BorderBrush="Black" BorderThickness="2" Grid.Column="2" Grid.Row="0" Grid.RowSpan="10" Height="Auto" Width="Auto" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ScrollViewer x:Name="canvas_RosetteMap" Height="Auto" Width="Auto" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<Canvas Grid.Column="2" HorizontalAlignment="Center" Height="Auto" Grid.Row="0" Grid.RowSpan="10" VerticalAlignment="Center" Width="Auto"/>
</ScrollViewer>
</Border>
You should use a Grid instead. Canvas are not good at handling resizing, scrolling or anything like that. Here is a simple example that should work with an Image also:
<Border BorderBrush="Black" BorderThickness="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ScrollViewer x:Name="canvas_RosetteMap" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Visible">
<Grid Width="Auto">
<TextBox Background="Beige" VerticalAlignment="Top" HorizontalAlignment="Left"/>
</Grid>
</ScrollViewer>
</Border>

In WPF, TreeView is having a different outline shadowing that StackPanel with border. How to fix that?

I have a window with a TreeView with a BorderThickness of 1 and a StackPanel inside a Border element with a BorderThickness of 1.
As you can see in the following picture, the Border gets a shadowing effect but the Treeview doesn't. How to fix this (if possible remove the shadow effect)?
general view
zoom view
I tried setting BorderThickness of TreeView to 0 and put TreeView in a Border , but it didn't work.
XAML summary:
<Grid Name="MainGrid" Margin="5,5,5,5">
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions >
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<TreeView ItemsSource="{Binding FinalResult}"
SelectedItemChanged="TreeView_SelectedItemChanged"
BorderThickness="1"
>
<TreeView.Resources>
</TreeView.Resources>
</TreeView>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
<Border BorderBrush="#ff828790" BorderThickness="1" Grid.Column="2">
<StackPanel>
</StackPanel>
</Border>
</Grid>
I think that you might benefit from using the UIElement.SnapsToDevicePixels Property. From the linked page:
Gets or sets a value that determines whether rendering for this element should use device-specific pixel settings during rendering.
If you set this property to true on your blurry control, it should align it directly with the actual pixels to remove the blurriness:
<Border BorderBrush="#ff828790" BorderThickness="1" Grid.Column="2"
SnapsToDevicePixels="True">
...
</Border>

How to set XAML property via a function call?

I have a simple page with a rectangle, an ellipse, two sliders and a textblock.
The two slider controls (via binding) the height and width of the rectangle.
I would like to set the width and height of the ellipse based on the smallest value of the rectangles dimensions. The XAML code looks like this:
<UserControl
x:Class="App16.MyUserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App16"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="400"
d:DesignWidth="400"
x:Name="MyRoot">
<Grid Background="Black">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition />
</Grid.RowDefinitions>
<Rectangle Name="rect" Fill="Yellow"
Width="{Binding ElementName=rectX,Path=Value}"
Height="{Binding ElementName=rectY,Path=Value}" Grid.Column="0"/>
<Ellipse Fill="Yellow"
Width="{Binding ElementName=MyRoot,Path=SampleFunction}"
Height="{Binding ElementName=MyRoot,Path=SampleFunction}" Grid.Column="1" />
<StackPanel Grid.Row="1" Grid.ColumnSpan="2">
<Slider Name="rectX" HorizontalAlignment="Stretch" Minimum="100" Maximum="200" Value="150" />
<Slider Name="rectY" HorizontalAlignment="Stretch" Minimum="100" Maximum="200" Value="150" />
<TextBlock Foreground="White" Text="{Binding ElementName=MyRoot, Path=SampleFunction}" />
</StackPanel>
</Grid>
The code behind looks like this:
public Double SampleFunction {
get { return (rect.Width <= rect.Height ? rect.Width : rect.Height); }
}
In its current state, the rectangle resizes properly according to the value in the sliders, but "SampleFunction" is never called after the page is loaded.
Of course I could do this with the "RESIZED" event, but I wondering if this was possible without doing that.
Any suggestions? When the user adjust the slider control I would like to see the rectangle and ellipse change size.
Thanks!
Henk's suggestion with my comment would make it work, but actually for your scenario you can remove the bindings altogether and simply set
<Ellipse
Fill="Yellow"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
Stretch="Uniform" />
Your SampleFunctionneeds to be renamed (it's a property, not a function).
And to make it work for DataBinding it needs to implement INotifyPropertyChanged
In addition, the internal logic should probably be base on ActualWidth and ActualHeight.

Keep slider in usercontrol from scaling in WPF

I have a user control which contains a media element to play a video, a slider used as a trackbar for the video and a text block that display the title of the video. These 3 controls are placed in a grid which in turn is placed inside a border.
I want the user to be able to translate, rotate and scale this control. The problem is that when the control scales it's content scales also and i want the slider control not to scale. Is it possible to somehow keep the slider control from scaling?
I should also mention that the manipulation of the control is handled by setting the control ismanipulationenabled to true and using the manipulation delta event.
EDIT:
This is how the xaml for the control looks like:
<Grid Name="movieGrid" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border x:Name="moviePlayerBorder" Background="Black" BorderBrush="Blue" BorderThickness="2,2,2,2" CornerRadius="5,5,5,5" Grid.RowSpan="2">
<Grid Name="contentGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<WinControls:MediaElement x:Name="movieDisplay" ScrubbingEnabled="True" IsEnabled="True" Grid.RowSpan="2"
LoadedBehavior="Manual" UnloadedBehavior="Manual"
MediaOpened="movieDisplay_MediaOpened">
</WinControls:MediaElement>
<Image x:Name="btnPlay" Grid.Row="1" Height="60" Width="60" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="120,44,112,43" Grid.RowSpan="2">
</Image>
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch" Margin="6,2,6,0" Grid.Row="0">
<TextBlock Text="test" Margin="0,0,0,0" Name="txtBlockTitlu" HorizontalAlignment="Stretch"
FontSize="14" VerticalAlignment="Top" Foreground="White" TextWrapping="Wrap" Visibility="Collapsed"/>
</DockPanel>
</Grid>
</Border>
<Slider x:Name="seekBar" VerticalAlignment="Bottom" HorizontalAlignment="Center" Width="299"
Thumb.DragStarted="seekBar_DragStarted" Thumb.DragCompleted="seekBar_DragCompleted" Thumb.DragDelta="seekBar_DragDelta" MaxHeight="33"
Minimum="0" Maximum="286" Height="33" Margin="0,0,0,0" Grid.Row="1"/>
</Grid>
if you want to build a fully scaleable user control you should define the layout only with the size values of a row column / row row eg. auto, x* or fixed values (if realy needed).
do not use fixed size values on elements.

How do I include a custom row at the end of a DataGrid in Silverlight?

I have a DataGrid in my Silverlight application and it works nicely, adding a row or removing a row as I manipulate the ItemsSource collection. However, I want there to be an additional row, or control that always appears after the last data row.
I can get the additional control to appear after the last row using a ControlTemplate and setting the RowsPresenter row to Auto height, but this means the rows never scroll when the render area gets too small. However, if I change the RowsPresenter row height to Star, the rows scroll but the additional control appears pinned to the bottom of the data grid rather than to the bottom of the last row.
Is there a way I can have the Star height behavior on the RowsPresenter while still having my control appear the way I want?
My current thinking is that I need to somehow use the LoadingRow event to find the position of the last row and use a Canvas or similar to place my control in the appropriate location.
Thoughts?
Thanks in advance for the help.
Update
I also asked a question (and ultimately answered) about pinning one control below another, which could be used to fix this issue if you don't want the custom row to scroll with the rest of the rows (such as in my case, where I wanted another datagrid header row to show totals and float over the other rows).
How do I pin one control below another in Silverlight?
I solved my problem last night in a flurry of inspiration. I notice that no one else has voted for this question so this answer may not be helpful to anyone, but just in case.
First of all, I combined my custom row control and RowsPresenter in a grid of two rows, each row sized to Auto. I then placed the grid inside a ScrollViewer and then sized the scroll viewer row to Star sizing. I did not add the VerticalScrollbar template part into my template as this only scrolls the RowsPresenter.
This gave me the exact behaviour I was looking for where a row is added and the custom row remains pinned to the bottom of the last data row. When the rows and custom row overflow off the end of the visible area, the scrollbar appears to allow scrolling while keeping the headers fixed in place.
Job done. I hope someone finds this helpful. Below is my ControlTemplate XAML.
<ControlTemplate TargetType="swcd:DataGrid" x:Key="DataGridTemplate">
<Border
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid Name="Root" Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<swcdp:DataGridColumnHeader Name="TopLeftCornerHeader" Grid.Column="0"/>
<swcdp:DataGridColumnHeadersPresenter Name="ColumnHeadersPresenter" Grid.Column="1"/>
<swcdp:DataGridColumnHeader Name="TopRightCornerHeader" Grid.Column="2"/>
<ScrollViewer
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="1"
Padding="0,0,0,0"
BorderThickness="0,0,0,0"
VerticalScrollBarVisibility="Auto">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<swcdp:DataGridRowsPresenter Name="RowsPresenter" Grid.Row="0" />
<Border
Margin="1,1,1,1"
Padding="2,2,2,2"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Grid.Row="1">
<Grid Background="{TemplateBinding Background}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock
Grid.Row="0"
TextAlignment="Left"
TextWrapping="NoWrap"
Text="Add a new item using the lists below:" />
<mystuff:MySelectionControl
HorizontalContentAlignment="Stretch"
Grid.Row="1"
SelectionChanged="OnSelectionChanged"/>
</Grid>
</Border>
</Grid>
</ScrollViewer>
<Rectangle Name="BottomLeftCorner" Grid.Row="3" Grid.ColumnSpan="2" />
<Grid Grid.Column="1" Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Name="FrozenColumnScrollBarSpacer" />
<ScrollBar Name="HorizontalScrollbar" Grid.Column="1" Orientation="Horizontal" Height="18" />
</Grid>
<Rectangle Name="BottomRightCorner" Grid.Column="2" Grid.Row="3" />
</Grid>
</Border>
</ControlTemplate>
Not sure if this helps for Silverlight, but I added a totals row to a WPF DataGrid by adding and invisible column, called IsTotal. I was able to get this row to always appear at the buttom of the grid using custom grouping / sorting. The grouping / sort order was configured to use this column as the primary sort, with a fix direction. Seems to work well.
First, create a Grid for the DataGrid and the pinned control:
<Grid Grid.Row="0" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<sdk:DataGrid Grid.Row="0" ItemsSource="{Binding YOUR_COLLECTION}" />
<TextBlock Grid.Row="1" Text="Hello World" /> <!-- The pinned control. -->
</Grid>
The trick is VerticalAlignment="Top" - when the DataGrid is smaller than the available height, it will move to the top of the available space and the pinned control will appear under it.
Then, put this Grid into a container that stretches vertically, for example in a row of another Grid with Star height:
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<!-- RowDefition for the Grid with the DataGrid with the pinned control. -->
<!-- If you want to have some other controls, -->
<!-- add other RowDefinitions and put these controls there. -->
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<!-- The internal Grid for the DataGrid & the pinned control. -->
<Grid Grid.Row="0" VerticalAlignment="Top">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<sdk:DataGrid Grid.Row="0" ItemsSource="{Binding YOUR_COLLECTION}" />
<TextBlock Grid.Row="1" Text="Hello World" /> <!-- The pinned control. -->
</Grid>
</Grid>
Instead of the root Grid you may have any other container that stretches vertically, the important thing is that it tries to fill all the available space for it.

Categories