How to determine on which side ContextMenu opens? - wpf

Let's say i got this ContextMenu:
<Style x:Key="{x:Type ContextMenu}" TargetType="{x:Type ContextMenu}">
<Setter Property="VerticalOffset" Value="-10"/>
<Setter Property="HorizontalOffset" Value="-10"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border Background="Transparent">
<Border.Effect>
<DropShadowEffect BlurRadius="10" ShadowDepth="0" Opacity="0.5"/>
</Border.Effect>
<Border Margin="10" Style="{StaticResource MenuBorderStyle}">
<Grid x:Name="SubMenu" Grid.IsSharedSizeScope="True">
<!-- StackPanel holds children of the menu. This is set by IsItemsHost=True -->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Cycle"/>
</Grid>
</Border>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So as you can see, i offset the appearance of the menu by 10 pixels to the top and to the left, getting the top-left corner of the ContextMenu to be right under the cursor.
In fact, because of Border's margin of 10 pixels, the whole control shoule be more left-top than a cursor, because the control it self starts with a shadow.
And, as you can have guessed, when the context menu appears not on the bottom-right side of the cursor (say the cursor is near bottom or left side of the screen), the offset needs to be changed to an opposite (by either either X or Y or both coordinates).
The question is how to do that by xaml?
(sorry for my english)

Try setting Placement property to AbsolutePoint. Check this out as well, it might help you.

Related

Round the corners of a button in Window.Resources WPF

I am very new to WPF. I've familiarized myself with ControlTemplate, ContentPresenter, and some other pieces, but I am struggling to create a button with rounded corners as defined from Window.Resources (or potentially a separate style file).
Anyways, when I add this to a <Button/> tag, I get a button with rounded corners:
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="5"/>
</Style>
</Button.Resources>
However, when I try to include it up in the Window.Resources the button will not apply the border style:
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Grid>
<Rectangle Fill="{TemplateBinding Background}" Stroke="{TemplateBinding Foreground}"/>
<Border CornerRadius="5"/>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</ControlTemplate>
This doesn't look right to me, but I guess I don't know where to add the specification of CornerRadius such that it will apply to the button. I did see this post, How to create/make rounded corner buttons in WPF? but it's a little over my head. I just want to round all the buttons in my application!
The Border in your ControlTemplate is not visible, because you have neither set its Background, nor its BorderBrush.
You could have something like shown below. Note however that with a simple ControlTemplate like this a Button loses all the visualizations of its states, like focused, mouse-over, pressed etc.
<ControlTemplate x:Key="roundbutton" TargetType="Button">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
CornerRadius="5">
<ContentPresenter/>
</Border>
</ControlTemplate>
You may instead just declare a default Button Style (i.e. a Style resource without x:Key) that applies your original Border Style like this:
<Style TargetType="Button">
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="5"/>
</Style>
</Style.Resources>
</Style>

Remove shadow effect when window is maximised in wpf

I had an window with styles
Background="Transparent", AllowsTransparency="True", WindowStyle="None", ResizeMode="NoResize".
I had placed custom min, max, close buttons and implemented functionality.And as i want the window to resize the window on all the sides. i implemented it with HwndSource which works fine. Now my concern is i want shadow effect for the window.so i placed the border with shadow effect like this.
<Border CornerRadius="5" Margin="10">
<Border.BitmapEffect>
<DropShadowBitmapEffect ShadowDepth="10" Opacity=".5" Softness="9" />
</Border.BitmapEffect>
<Grid> **Content over here**</Grid>
</Border>
window gets the shadow effect. but when i maximise the window. it does not fit to the screen as i had added border. i need to remove the shadow effect when window is maximized so that it fit to the screen. and the shadow effect should appear when window is in not in maximized state. how to get this or is there any another method to get this.. please help me to find the solution.
I think it would be possible to add/remove the shadow effect dynamically in the code by creating style for your Border. You can create a style for your border something like this:
<Style x:Key="borderstyle" TargetType="Border">
<Setter Property="BitmapEffect">
<Setter.Value>
<DropShadowBitmapEffect ShadowDepth="10"> </DropShadowBitmapEffect>
</Setter.Value>
</Setter>
</Style>
And then set it dynamically in the code
borderelement.Style =(Style)Application.Current.MainWindow.Resources["borderstyle"];
and remove it by using the following code
borderelement.Style = null
You can use a trigger to determine if Window is maximized and then in the trigger setter, remove the effect. Just overload template for the Window and inside ControlTemplate triggers add a trigger
<Window.Template>
<ControlTemplate TargetType="Window">
<Border x:Name="brd">
<Border.Effect>
<DropShadowEffect BlurRadius="20" Color="Black"/>
</Border.Effect>
<Grid Width="200" Height="200" MouseDown="Grid_MouseDown_1" Background="Red"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="WindowState" Value="Maximized">
<Setter Property="Effect" TargetName="brd" Value="{x:Null}"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Template>

UInable to enter values in a textbox after applyting Inner shade effects in wpf using mvvm

In my sample WPF-MVVM application , ihave one textbox and i have applied some Inner shade effects like this
<Style TargetType="{x:Type TextBox}" x:Key="TxtBoxStyle">
<Setter Property="Margin" Value="2,4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid x:Name="txtgrid">
<Border x:Name="txtBorder" CornerRadius="5" Background="LightGray" BorderBrush="DarkGray"
BorderThickness="1" ClipToBounds="True">
<Border Background="Transparent" BorderBrush="Black"
BorderThickness="1" Margin="-2">
<Border.Effect>
<DropShadowEffect ShadowDepth="5" BlurRadius="10"/>
</Border.Effect>
</Border>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But after applying these effects I am unable to enter values in textbox.
Please let me know whether my code is correct or not.
You have replaced the default template, but not provided anywhere to display the content. Your template only contains Borders.
If you take a look at the default TextBox template, you can see that it defines a named part called PART_ContentHost that takes the content. Try adding that to your template.
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>

Changing background color of a separator in WPF data bound combo box

I have a combobox that is bound to a dataset that then uses a datatrigger to insert a separator when it encounters a '-' in the data (example in this question).
The background of the menu has custom color, set by using a resource dictionary. The color in this case is #FFF8F4C5
If I add a separator to a non databound simple combo box, it appears correctly. But when adding it using the datatrigger, it does not look like the rest of the menu, as you can see below (it has a white background).
If I set the background of the separator, it actually changes the darker line to whatever color. I can't seem to find how to change the white area to match the same color as the menu.
In the ControlTemplate, enclose the Separator in a Border with Background bound to to the parent ComboBoxItem's Background. Something like this:
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border Background="{TemplateBinding Background}">
<Separator HorizontalAlignment="Stretch" IsEnabled="False"/>
</Border>
</ControlTemplate>
use a separator style:
<Style x:Key="SeparatorStyle1" TargetType="{x:Type Separator}">
<Setter Property="Background" Value="{DynamicResource
{x:Static SystemColors.ControlDarkBrushKey}}"/>
<Setter Property="Margin" Value="0,2,0,2"/>
<Setter Property="Focusable" Value="false"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Separator}">
<Border Height="1" SnapsToDevicePixels="true"
Background="#FFCCD480" BorderBrush="#FF633A3A" BorderThickness="0,0,0,1"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and use it like this
<ComboBox Background="#FFD2D2B5">
<ListBoxItem Content="item1"/>
<ListBoxItem Content="item2"/>
<Separator Style="{DynamicResource SeparatorStyle1}"/>
<ListBoxItem Content="item3"/>
That should do it

Styling a WPF layout grid background (of each cell, row, column)

I would like to know if there is any way to style a WPF layout grid's cells, rows and columns. I've been trying to find any information and the few mentions I've found have not been that informative.
I would like to style the grid to look like the one in the linked screenshot.
If the actual control does not support it, can I inherit it somehow and do it then? I am quite new to WPF so any help would be very appreciated.
One other thing, I know I can style each and every control within the grid, but it seems like overkill. I would like to have a grid that does it itself.
screenshot http://img21.imageshack.us/img21/2842/capturehz8.png
#Dan recommends WPF Unleashed, which I'm currently reading. Just this morning, I come across a section addressing your question.
Chapter 6, Page 161:
FAQ: How can I give Grid cells background colors, padding, and borders like I can with cells of a HTML Table?
There is no intrinsic mechanism to give Grid cells such properties, but you can simulate them pretty easily thanks to the fact that multiple elements can appear in any Grid cell. To give a cell a background color, you can simply plop in a Rectangle with the appropriate Fill, which stretches to fill the cell by default. To give a cell padding, you can use auto sizing and set the Margin on the appropriate child element. For borders, you can again use a Rectangle but give it an explicit Stroke of the appropriate color, or you can simply use a Border element instead.
Just be sure to add such Rectangles or Borders to the Grid before any of the other children (or explicitly mark them with the ZIndex attached property), so their Z order puts them behind the main content.
Btw, WPF Unleashed rocks. Its very well written, and the print in full color makes it even more easier to read.
Here's a quick (very rough sample) that you could hack around to get the format you want (if you're serious about working with WPF, you'll find Blend an enormous help in getting your layouts looking good):
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<Style x:Key="CustomerDefinition" TargetType="TextBlock">
<Setter Property="Control.FontFamily" Value="Tahoma"/>
<Setter Property="Control.FontSize" Value="12"/>
<Setter Property="Control.Foreground" Value="Red"/>
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Width" Value="100"/>
</Style>
<Style x:Key="{x:Type TextBox}" TargetType="{x:Type TextBox}">
<Setter Property="SnapsToDevicePixels" Value="True"/>
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border
Name="Border"
Background="#FFEBE9E9"
BorderBrush="#FF8B8787"
BorderThickness="1"
CornerRadius="2"
Padding="3">
<ScrollViewer x:Name="PART_ContentHost" Margin="0"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background"
Value="#EEEEEE"/>
<Setter TargetName="Border" Property="BorderBrush"
Value="#EEEEEE"/>
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<LinearGradientBrush x:Key="NormalBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.0" Color="#FFF0EDED"/>
<GradientStop Offset="1.0" Color="#FFE1E0E0"/>
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
</Page.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="26"/>
<RowDefinition Height="23"/>
<RowDefinition Height="24"/>
<RowDefinition Height="24"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<TextBlock
Grid.ColumnSpan="2"
Grid.Row="0"
Style="{StaticResource CustomerDefinition}"
Text="Customer Definition"/>
<Border
Grid.Column="0"
Grid.Row="1"
Background="#FFEBE9E9"
BorderBrush="#FF8B8787"
BorderThickness="1">
<StackPanel Background="{StaticResource NormalBrush}" Orientation="Horizontal">
<Label Content="Customer Code"/>
<TextBox Text="SMITHA 098 (normally I'd bind here)"/>
</StackPanel>
</Border>
<Border
Grid.Column="1"
Grid.Row="1"
Background="#FFEBE9E9"
BorderBrush="#FF8B8787"
BorderThickness="1">
<StackPanel Background="{StaticResource NormalBrush}" Orientation="Horizontal">
<Label Content="Customer Type"/>
<TextBox Text="PRIVATE INDIVIDUAL"/>
</StackPanel>
</Border>
</Grid> </Page>
The WPF Grid doesn't have visible cells as such. Think of them as invisible grid lines against which you can have child elements be aligned.
So, to style the grid's cells, you have to style the items that are aligned inside the grid.
It is confusing to think of the Grid as being anything like a WinForms DataGrid. I guess its closest WinForms equivalent is the TableLayout control.
Check out some 3rd party grid controls. I used the DevExpress one while it was in beta and found it pretty straightforward.
I would recommend using borders for your styling.
You could recreate that layout pretty easily by creating borders for each row and each column and set the rowspans and colspans accordingly.
You will have 5 borders with colspan 2, these borders will take care of your gradient backgrounds for each row and the borders along the top and bottom of each row. Then you will have 2 borders with rowspan 5 these will handle the column borders. Imagine that you are overlaying the borders to form the visual grid effect you are after.
For the header and outer border, just wrap the entire grid with a border and style as needed.
I would recommend storing your styles as resources so you can keep all your styling info in one place.
Take care to learn how the styling works because it is pretty powerful, but there is a learning curve as it is quite different to the way CSS works. I would recommend reading WPF Unleashed if you can.
I found this post when looking for method for setting margin (or padding) for DataGrid cells. My problem was solved thanks to example xaml code posted at (near the end) -- pretty minimalistic.
http://forums.silverlight.net/forums/p/16842/55997.aspx

Resources