How to create stretching clipping rectangle in Silverlight - silverlight

Since Silverlight doesn't have the comfy feature of 'ClipToBounds' properties on controls, I have to define clipping shapes by myself. I was wondering if I could create a clipping rectangle that's following the size of my control. Any suggestions?

If there is an existing control in you layout that you want to dynamically clip then use its SizeChanged event. For example lets say you want to clip this Grid:-
<Grid SizeChanged="Grid_SizeChanged" Width="50" Height="20">
<Grid.Clip>
<RectangleGeometry />
</Grid.Clip>
<TextBlock Margin="0 -9 0 0" Text="This text should not be legible" />
</Grid>
With the code-behind:-
private void Grid_SizeChanged(object sender, SizeChangedEventArgs e)
{
((RectangleGeometry)((Grid)sender).Clip).Rect = new Rect(0.0, 0.0, e.NewSize.Width, e.NewSize.Height);
}
For a your own custom control you might consider handling the clip rectangle in the ArrangeOverride instead of relying on the SizeChanged event. In this case you probably want to assign RectangleGeometry to the Clip property in code rather than relying on it being assigned in the Xaml of the default template.

Silverlight supports that:
try using HorisontalAlignment and vertical alignment propertys. Set them to stretch.
If this doesn't work then you will have to post xaml example.

Related

Wpf Mouse event set on canvas, but targets child object

I have a Canvas that contains a Rectangle. On that canvas, I bind a mousedown event to a command on the ViewModel. In that command, I am being passed the MouseEventArgs, but there the Target element is either the Canvas or the Rectangle. Where can I find in the MouseEventArgs the Canvas this event was fired from?
My code is more or less:
<Canvas Background="White">
<i:EventTrigger EventName="MouseLeftButtonDown">
<local:InteractiveCommand Command="{Binding CmdMouseLeftButtonDown}"/>
</i:EventTrigger>
<Rectangle Width="50" Height="50" />
</Canvas>
And in the ViewModel:
ICommand CmdMouseLeftButtonDown => new DelegateCommand<MouseEventArgs>(e =>
{
e.??? // <= Where do I find the Canvas here, whether I click on the Rectangle or Canvas?
}
Please do not answer with some hackish solution like e.MouseDevice.Target.Parent. This needs to work however complicated the element in the canvas is. It could contain another canvas for instance.
A view model is not supposed to have a reference to a UI element such as a Canvas or a Rectangle at all in the first place. This effectively breaks the MVVM pattern and that's why it makes no sense to pass the sender argument to the command.
You might as well get rid of the EventTrigger and invoke the command programmatically from the code-behind of the view:
<Canvas Background="White" MouseLeftButtonDown="Canvas_MouseLeftButtonDown">
<Rectangle Width="50" Height="50" Fill="Red" />
</Canvas>
private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
var yourViewModel vm = DataContext as YourClass;
vm.CmdMouseLeftButtonDown.Execute(sender as Canvas); //<-- pass the Canvas as a command argument or create a new command argument type that holds a reference to the Canvas
}
This is certainly not any worse than your current approach as far as the MVVM pattern is concerned. You are still invoking the very same command from the very same view and MVVM is not about eliminating code. It is about separation of concerns.
Your MouseEventArgs.Source will reference to the Canvas in any case but the MouseEventArgs.OriginalSource will referece to the Rectange if you have clicked on its area. It will be the control determined by pure hit testing.
Set <Canvas Background="Transparent" ... />
as answered in the following question by #Rob Fonseca-Ensor:
WPF: Canvas mouse events not firing on empty space

How to implement popup in Windows Phone

I'm implementing a templated control, which should work as virtual keyboard button - when you hold it, it displays a popup with additional options to choose.
I've implemented the popup more less in the following way:
<Grid>
<Border>Content</Border>
<Grid x:Name="gPopup" Visibility="Collapsed">
<StackPanel x:Name="spSubItems" Orientation="Horizontal" />
</Grid>
</Grid>
I show the popup by changing visibility to visible and setting negative margins for top and bottom. However, when I do that, and when the popup is actually larger than the control, the control is being resized to match its size - despite fact, that it is not inside:
How can I implement the popup, such that it won't expand the container it's on? And such that the container will still match size of its contents?
Edit: In response to comments and answers
I'm not sure if I'm understood correctly. Here's an image with explanation:
I'd like to keep the original container's size the same after showing the popup. I'm unsure how WrapPanel or DockPanel could help me with that.
The solution is simply to use Popup instead of positioned Grid.
Sample- Create a grid
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<!-- Setting a Rectangle having transparent background which set the
Visibility of popup -->
<Rectangle Name="popupRect" Fill="#80000000" Visibility="Collapsed"/>
<!—Here in the above Code we are just filling the rectangle With the transparent BackGround -->
<!—Creating A Border -->
<Border Name="popupBorder" Background="{StaticResource PhoneChromeBrush}" BorderBrush="Red" BorderThickness="2"
HorizontalAlignment="Center" VerticalAlignment="Center" Visibility="Collapsed">
<!-- Creating A grid Inside the Border and Rectangle -->
</Grid>
Create event for which popup should appear(for both cancel and appear)-
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
popupRect.Visibility = Visibility.Collapsed;
popupBorder.Visibility = Visibility.Collapsed;
}
private void popupButton_Click(object sender, RoutedEventArgs e)
{
popupRect.Visibility = Visibility.Visible;
popupBorder.Visibility = Visibility.Visible;
}
It will work, I guess.
Like spook says, put your gPopup Grid in a Popup element and show it by opening the popup. This won't affect the main visual tree.
The reason the embedded grid embiggens the border is that the outer grid has to expand to hold pGrid and the border expands to fill the outer grid.

How to position TextBlock in Canvas after window resize?

I have a TextBlock which I move within a Canvas via DoubleAnimation(). On the enclosing Window SizeChanged event, I am able to properly resize the TextBlock.FontSize and inner Canvas, but I am having problems getting the position of the TextBlock correctly within the Canvas. (I was trying to do some form of Canvas.SetTop(NameQueueTextBlock, <newVal>) but that didn't work.)
<Canvas Grid.Column="1" ClipToBounds="True">
<Canvas Name="NameQueueCanvas" ClipToBounds="True" Height="79" Width="309">
<TextBlock Canvas.Top="0" Name="NameQueueTextBlock" FontSize="19" Text="
"/>
</Canvas>
</Canvas>
I'm gonna guess your DoubleAnimation is the culprit.
If it hold's the end value(which is the default) of Canvas.Top while moving the TextBlock any future updates of Canvas.Top according to the WPF priority system will "appear" to be ignored.
Solution:
switch
Canvas.SetTop(NameQueueTextBlock, /*newVal*/);
with
NameQueueTextBlock.BeginAnimation(Canvas.TopProperty, null);
Canvas.SetTop(NameQueueTextBlock, /*newVal*/);
and you should be sorted.
Alternate approach:
Assuming your Storyboard is called sb, Just before calling sb.Begin();
add something like:
sb.Completed += (o, args) => {
var finalVal = Canvas.GetTop(NameQueueTextBlock);
NameQueueTextBlock.BeginAnimation(Canvas.TopProperty, null);
Canvas.SetTop(NameQueueTextBlock, finalVal);
};
I'd prefer this as it then allows you to not keep track of which code-fragment might potentially change the Canvas.Top on the TextBlock first and reset the property with a null animation before-hand.

"Modal Dialog" in WPF - make overlay block key events

I'm creating a WPF application containing a "Main-Content" - Layer containing a TabControl and a "Dialog" - Layer containing an ItemsControl.
The XAML looks like this:
<Grid>
<TabControl>
..Some Tabs
</TabControl>
<ItemsControl>
<ContentControl Content={Binding Dialog1Property} />
<ContentControl Content={Binding Dialog2Property} />
</ItemsControl>
</Grid>
Usually "Dialog1Property" and "Dialog2Property" are null which means the ItemsControl is invisible. Whenever I assign a Control to one of them, it is shown in front of the TabControl which is exactly what I want. If I assign a gray Rectangle with an opacity of 0.7 to one of the Dialog - Properties it creates a Gray overlay.
If I click on the Tab, which is slightly visible through the overlay, nothing happens - the Rectangle blocks Mouse Events. It is, however, still possible to focus the TabControl behind the overlay using the Tab-Key and therefore it is also possible to switch tabs even though a Dialog is shown.
Is there an easy way to tell the rectangle to somehow block key events as it allready does with Mouseclicks?
Regards
BBRain
Yes, on your Rectangle, subscribe to the event PreviewKeyDown.
<Rectangle Opacity="0.7" Fill="Green" PreviewKeyDown="Rectangle_PreviewKeyDown" />
In its handler, simply set e.Handled = true;
private void Rectangle_PreviewKeyDown(object sender, KeyEventArgs e)
{
e.Handled = true;
}
Since routed events prefixed with "Preview..." are tunneling, the elements under your rectangle won't recieve the input.

Move Image control in VB2010 WPF

In windows forms, you can easily change the ".left" value of a picturebox to move it. However, I have noticed that in VB2010 WPF, this is not the case.. Can anyone show me how to change an image control's .left (or equivalent) value in wpf?
Thanks
Nick
Normally placement in WPF depends on the container a control is a child of. If you want to adjust placements you can either use the Margin property which should work for almost all containers or place the Image in a Canvas, then you can use the Canvas.Left attached property for placement.
Additionally you could use LayoutTransform or RenderTransform properties to move your control around; you would use a TranslateTransform for that.
e.g.
<Grid>
<Button Margin="20,0,0,0" Content="Using Margin"/>
</Grid>
<Canvas Height="30">
<Button Canvas.Left="20" Content="Using a Canvas"/>
</Canvas>
<Grid>
<Button Content="Using TranslateTransform">
<Button.RenderTransform>
<TranslateTransform X="20"/>
</Button.RenderTransform>
</Button>
</Grid>
(Changing margin programmatically:)
Thickness margin = Control.Margin;
margin.Left += 1;
Control.Margin = margin;

Resources