I am experiencing a strange WPF popup placement issue.
I have defined this XAML:
<Window x:Class="PositionBug.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="300" Width="525">
<Grid>
<TextBlock Name="Textblock1" Height="60" Width="300" Background="LightGray" HorizontalAlignment="Center"
VerticalAlignment="Bottom">The PlacementTarget</TextBlock>
<Popup Name="Popup1" PlacementTarget="{Binding ElementName=Textblock1}" Placement="Top" Width="120" Margin="198,0,199,0" IsOpen="True">
<TextBlock Background="LightBlue" FontSize="18">This is a Popup</TextBlock>
</Popup>
</Grid>
On most computers this is the result, as expected:
However, on multiple units of one specific computer model, the result is presented like this:
Is there any way to force Placement to both Top AND Left?
The left and right alignment of menus and popups appears to be controlled by this special registry key:
HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Windows
REG_SZ: MenuDropAlignment
Value: 0 means to the right
Value: 1 means to the left
Somehow my system switched the menu and popup alignment from right to left. I checked this registry key and sure enough the value was 1 so I changed it back to 0 and now my WPF Popup alignments are working as expected.
UPDATE: Here is a better solution if you want to make it apply to the entire Window: WPF Handedness with Popups
ORIGINAL:
I realize this is an old thread but I just ran across this. With this:
<Popup
Name="Popup"
Placement="Bottom"
PlacementTarget="{Binding ElementName=ToggleButton}"
...
I get this:
I didnt want to rely on the user settings and I wanted to avoid code behind and math. So I just did this DIRTY hack but using a hollow rectangle in the corner. Good thing is all of the built-in logic for shifting the popup when at different edges of the screen all still work:
<!--POPUP PLACEMENT HACK-->
<Rectangle
x:Name="PART_PopPlacer"
Fill="Red"
Width="0"
Height="0"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Focusable="False"
Visibility="Hidden"
IsHitTestVisible="False"
/>
<Popup
Name="Popup"
Placement="Left"
PlacementTarget="{Binding ElementName=PART_PopPlacer}"
...
Which gave this:
The full code (should probably put the rectangle at the top of the xaml so it can be covered by the cascading elements):
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<!-- COMBO BOX STYLE AND TEMPLATE -->
<Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton
Background="White"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press"
/>
<ContentPresenter
Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
Margin="2"
/>
<!--POPUP PLACEMENT HACK-->
<Rectangle
x:Name="PART_PopPlacer"
Fill="Red"
Width="0"
Height="0"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Focusable="False"
Visibility="Hidden"
IsHitTestVisible="False"
/>
<Popup
Name="Popup"
Placement="Left"
PlacementTarget="{Binding ElementName=PART_PopPlacer}"
VerticalOffset="6"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid
Name="DropDown"
SnapsToDevicePixels="True">
<Border
Name="DropDownBorder"
Background="LightYellow"
BorderThickness="1"
BorderBrush="Black"/>
<ScrollViewer Margin="2" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel>
<ComboBox Height="20" Width="50" SelectedIndex="0" Margin="20">
<ComboBoxItem Content="Very Very Very Very Long Text" />
<ComboBoxItem Content="Text" />
<ComboBoxItem Content="Text" />
<ComboBoxItem Content="Text" />
<ComboBoxItem Content="Text" />
</ComboBox>
</StackPanel>
</Page>
I was able to fix this on my HP laptop. Turns out since it has a touch screen, it uses a left/right "handedness" to choose whether drop-down menus and popups are left- or right-aligned with the target control (when using Top or Bottom alignment).
To fix, go to Control Panel, search (upper right corner) and type Tablet PC Settings. On that dialog (under General tab on some versions of Windows, and the Other tab on other PCs) you'll see options for right- and left-handed operation.
The right-justified popups are "better" if the menus and popups show to the left of the point being touched, so the right hand doesn't obscure the component. Of course if you primarily use a mouse, then it just looks weird and confuses us developers!
I had the same issue with popups in an application I'm working on. I can't expect customers to change the settings on their Tablet PCs, so I used this code to fix the popup positioning for everyone:
var simplePlacement = new CustomPopupPlacement(new Point(0, 0), PopupPrimaryAxis.None);
popup.Placement = PlacementMode.Custom;
popup.CustomPopupPlacementCallback = new CustomPopupPlacementCallback((popupSize, targetSize, offset) => new [] { simplePlacement });
Go to "system settings"
- "hardware & sound"
- "tablet pc-settings"
- "to be used writing hand"
- select "right-handed" (PopUps, DropDowns align left)
or "left-handed" (PopUps, DropDowns align right)
Related
I want to instantiate two Controls (an Expander and a Button) from two ControlTemplates. They are docked in a Dockpanel (right and left). The Expander is visible and it works fine, but the Button isn't visible.
The ControlTemplate of the Button in App.xaml:
...
<ControlTemplate x:Key="OpenFileButton" TargetType="{x:Type Button}">
<Image Name="OpenFileButton" Source="F:\AudioNodeGUI_XAML\images\filebutton.jpg">
</Image>
</ControlTemplate>
...
And the instantiation in a usercontrol:
<Grid>
<Image Source="F:\AudioNodeGUI_XAML\images\FileInputNode.jpg"/>
<DockPanel Name="dock" Width="151" Height="20" Margin="27,53,122,139">
<Expander Name="expander" Template="{StaticResource FileExpander}" Height="20" Width="41" PreviewMouseLeftButtonUp="expand" DockPanel.Dock="Left">
<ListView Name="usedFiles" Background="Black" BorderBrush="Transparent" BorderThickness="0" Width="140" Height="120" Opacity="0.5">
</ListView>
</Expander>
<Button Name="OpenFileButton" Template="{StaticResource OpenFileButton}" DockPanel.Dock="Right" />
</DockPanel>
</Grid>
But the Button isn't visible, neither in the Designer (just the outline) nor in execution. What am I doing wrong?
I suspect that your issue is just incorrect path to the image file. Unfortunately you won't have any tip about this kind of error neither in designer nor in output window. However if you have ReSharper it should highlight the path to the file if it doesn't exist
I've got the following control template which I use as a Validation.ErrorTemplate for TextBoxes:-
<ControlTemplate x:Key="ControlValidationErrorTemplate">
<DockPanel LastChildFill="True">
<Border Background="Red"
DockPanel.Dock="right"
Padding="2,0,2,0"
ToolTip="{Binding ElementName=valAdorner, Path=AdornedElement.(Validation.Errors), Converter={x:Static val:ValidationErrorsConverter.Instance}}">
<TextBlock Text="!"
VerticalAlignment="center"
HorizontalAlignment="center"
FontWeight="Bold"
Foreground="white" />
</Border>
<AdornedElementPlaceholder x:Name="valAdorner"
VerticalAlignment="Center">
<Border BorderBrush="red"
BorderThickness="1" />
</AdornedElementPlaceholder>
</DockPanel>
</ControlTemplate>
When a TextBox contains invalid content, the above template applies a red border and adds a red box containing an exclamation mark immediately to the right of the TB.
The problem is, the exclamation mark overlaps anything immediately to the right of the TB, rather than the layout changing to accomomodate the exclamation mark. I have a similar problem in DataGrids - the exclamation mark overlaps the right-hand edge of the containing cell, rather than the column width increasing to accommodate it.
Using Snoop, it appears that the template is being displayed in an "adorner layer" which I assume is a separate visual tree? This would explain why the window's layout isn't recalculated to take into account the exclamation mark. Can anyone suggest a way to achieve what I want?
As I suspected, it's due to the error template being rendered on the adorner layer, so it doesn't affect the layout of the window. See: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9de3c9e5-5759-4f88-9184-175d3eaabdad/
I'm now using this control template instead:-
<ControlTemplate x:Key="ControlValidationErrorTemplate">
<Grid>
<Polygon Points="9,9 9,0 0,0"
Stroke="Red"
StrokeThickness="1"
Fill="Red"
HorizontalAlignment="Right"
VerticalAlignment="Top"
ToolTip="{Binding ElementName=valAdorner, Path=AdornedElement.(Validation.Errors), Converter={x:Static val:ValidationErrorsConverter.Instance}}" />
<AdornedElementPlaceholder x:Name="valAdorner"
VerticalAlignment="Center">
<Border BorderBrush="red"
BorderThickness="1" />
</AdornedElementPlaceholder>
</Grid>
</ControlTemplate>
This draws a red border around the control, with a small red triangle overlapping the top-right corner of the control - hovering over this displays a tooltip containing the error message.
I am creating a container whose style will be used across the application. It essentially is a 'pop up' but won't spawn in a new window. The general structure of my app is one NavigationWindow and many pages. So I get started with the following Template, defined in my Resource Dictionary:
<ControlTemplate x:Key="RainbowModalTemplate" TargetType="{x:Type Control}">
<Canvas Height="540" Canvas.Left="492" Canvas.Top="296" Width="945">
<Border x:Name="Modal" Height="540" Width="945" Background="#ec2016" BorderBrush="White" BorderThickness="2" CornerRadius="15" Style="{DynamicResource RainbowModalBox}">
<Border.Clip>
<RectangleGeometry RadiusX="15" RadiusY="15" Rect="0,0,945,540"/>
</Border.Clip>
<Image Source="Resources/RainbowModal/rainbow.png" Height="247" Width="947" Margin="0,0,0,0" VerticalAlignment="Bottom" d:LayoutOverrides="Height" Stretch="UniformToFill" Canvas.Left="-2" Canvas.Top="293" ClipToBounds="True" />
</Border>
</Canvas>
</ControlTemplate>
So when I want to 'consume' this, I want to be able to implement this control but provide my own content inside, (buttons, text, etc). However because I am new to WPF I am unsure what control or controls to use, and what structure to lay this out as. Below is sample 'consumer' of the object. Someone will click a button in the application and that will set this objects' visibility to be Visible :
<Control x:Name="RequestMoreInfoModal" Template="{DynamicResource RainbowModalTemplate}" Canvas.Left="494" Canvas.Top="250" Visibility="Collapsed"></Control>
I know this probably isn't the most kosher way to do this, so I am open to suggestion. My specific concerns:
I know "Control" isn't the right type. But I don't know what is appropriate and it appears Canvas and other controls do not allow Templating. What control should I use?
how do I implement this Template and also allow the consumer to define their own content within the Template?
What I eneded up doing is using a ControlTemplate and ContentPresenter.
Here is the definition of the reusable content in my ResourceDictionary:
<ControlTemplate x:Key="RainbowModal" TargetType="ContentControl">
<Canvas>
<Border x:Name="Modal" Height="540" Width="945" Background="#ec2016" BorderBrush="White" CornerRadius="15" BorderThickness="2" Style="{DynamicResource RainbowModalBox}">
<Border.Clip>
<RectangleGeometry
RadiusX="{Binding CornerRadius.TopLeft, RelativeSource={RelativeSource AncestorType={x:Type Border}}}"
RadiusY="{Binding RadiusX, RelativeSource={RelativeSource Self}}"
Rect="0,0,945,540"/>
</Border.Clip>
<Canvas>
<Image Source="Resources/RainbowModal/rainbow.png" Height="247" Width="947" Margin="0,0,0,0" VerticalAlignment="Bottom" Stretch="UniformToFill" Canvas.Left="-2" Canvas.Top="293" ClipToBounds="True" />
<ContentPresenter/>
</Canvas>
</Border>
</Canvas>
</ControlTemplate>
And here is the 'consumption' of that content.
<ContentControl x:Name="RequestMoreInfoModal" Canvas.Left="489" Canvas.Top="122" Template="{StaticResource RainbowModal}" Visibility="Collapsed">
<Canvas>
<TextBlock FontSize="78" Foreground="White" Width="903" Canvas.Top="28" Canvas.Left="20" Height="298" Text="Scan your card to receive an email with more information." TextWrapping="Wrap" FontFamily="Serif72 Beta" TextAlignment="Center" />
<Button Width="250" Height="76" Content="CLOSE" Margin="350,350" Style="{DynamicResource PurpleInfoButton}" FontSize="28" Click="Button_Click_1" ></Button>
</Canvas>
</ContentControl>
I would like to build a WPF window application using the following layout structure. Consider title and button on left hand frame/window like "Master Pages" in ASP.Net. On the right hand frame it should be a WPF navigation window.
When I include Navigation Window as an UI element at the last stack panel, it throws me and error. How should I design the entire layout according to the image screenshot below? Thanks
<Window x:Class="MainWindow"
xmlns:local="clr-namespace:ClientSocket"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title=" Desktop" Height="841" Width="1271" WindowStartupLocation="CenterScreen" WindowState="Maximized">
<DockPanel>
<StackPanel DockPanel.Dock ="Top" Orientation="Horizontal" Background="Red">
<TextBlock Background="red" FontSize ="36" Width="482" >
Main Title
</TextBlock>
</StackPanel>
<StackPanel Background="LightGray" DockPanel.Dock ="Left" Width="145">
<Button Content="Button1" Name="btnAndroid" Width="119" Margin="3" BorderBrush="{StaticResource {x:Static SystemColors.InfoBrushKey}}" />
<Button Content="Button2" Name="btnDownloads" Width="119" Margin="3" BorderBrush="{StaticResource {x:Static SystemColors.InfoBrushKey}}" />
<Button Content="AddNewDownloads" Height="37" Name="Button1" Width="133" />
</StackPanel>
<StackPanel>
<NavigationWindow Height="auto" Width="auto" Name="nwMain" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" BorderBrush="Blue" BorderThickness="1" />
</StackPanel>
</DockPanel>
</Window>
You cannot add a window as the child of anything, there is a nestable navigation control which you can use here instead, it is called Frame.
Layout-wise i would recommend a Grid with two rows, contains another Grid (in Grid.Row="1") with two columns.
DockPanels are sad controls that probably should not be used, unless someone points a gun at you and tells you to.
Below is a very crude start to a thumb template that eventually might look like a respectable popup window. Obviously the user can drag it around from any location therein. Is there any way to make it so it can only be dragged from the top AliceBlue border? Put another way, it is possible to disable dragging from the second border?
<Popup x:Name="MyPopup">
<Popup.Child>
<Thumb DragDelta="Thumb_DragDelta">
<Thumb.Template>
<ControlTemplate>
<StackPanel Margin="20">
<Border Height="20" Width="200" BorderBrush="Black" BorderThickness="2,2,2,0" CornerRadius="3,3,0,0" Background="AliceBlue"></Border>
<Border Height="200" Width="200" BorderBrush="Black" BorderThickness="2,0,2,2" Background="Bisque"></Border>
</StackPanel>
</ControlTemplate>
</Thumb.Template>
</Thumb>
</Popup.Child>
</Popup>
I haven't tested this so it's a bit of a guess. Add an event handler to the MouseLeftButtonDown event on AliceBlue Border. In the event handler:-
e.Handled = true;