WPF Popup placement relative to main window - wpf

I have a WPF application that uses one window as main window. Now I want to display various popups centered in the window. This works fine when the popup is placed inside the window. However, I have implemented the popups as user control; meaning that the main window contains a user controls which itself contains the actual popup. So the UI element tree looks like this:
Window --> UserControlPopup --> Popup
The popup inside the user control is declared like this:
<UserControl x:Class="X.Custom_Controls.ErrorPopup"
...
xmlns:local="clr-namespace:X.Custom_Controls"
mc:Ignorable="d" d:DesignHeight="360" d:DesignWidth="500">
<Popup Name="errorPopup" Height="360" Width="500" Placement="Center" StaysOpen="True" PlacementTarget="{Binding ElementName=mainWindow}">
...
</Popup> </UserControl>
The mainWindow element name is the one of my main window, which is declared as follows:
<Window x:Class="X.MainWindow" x:Name="mainWindow" ...>
The problem is that the popup is not placed in the center, but on the left side. So my guess is that the popup cannot resolve the elementName properly (since it's a child of a child of the mainWindow). Does anyone know how I can solve this issue in XAML?
Update: the solution was to use
PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType=Window}}"

Try to acces your main window through x:Reference. This one should work:
<MainWindow x:Name="mainWindow">
<UserControl Tag="{x:Reference mainWindow}">
</MainWindow>
<UserControl x:Name="userControl">
<PopUp PlacementTarget="{Binding Path=Tag, ElementName=userControl}"/>
</UserControl>
Such a way you can use your UserControl in another Controls/UserControls and you will not need to modify it, just set the Tag property from outside, if you use {RelativeSource AncestorType=Window} you will need to modify it.

The solution was to use the following as PlacementTarget:
PlacementTarget="{Binding RelativeSource={RelativeSource AncestorType=Window}}"

Related

WPF Usercontrol based on Textbox/Popup definition

I created a "UserControl" based on a TextBox. That means I created a new UserControl and replaced UserControl by TextBox in xaml and xaml.cs files.
Now I want that my new TextBox control shall have a popup to display some suggestions.
Now my question is: Where can I define the look/structure of the Popup as XAML? The Popup definition shall be part of the newTextBox.
That's what I have:
<TextBox x:Class="WpfApplication11.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApplication11"
mc:Ignorable="d"
MaxWidth="{Binding Path=ActualWidth}">
</TextBox>
I think you're totally missing what a UserControl actually is. To put it simply, a UserControl is a group or collection of controls that make up one larger... uh... control.
I want that my new TextBox control shall have a popup to display some suggestions.
What you are describing here is a UserControl. You cannot place a Popup inside a TextBox.
So. What you're after here is probably something like this:
<UserControl ... >
<Grid>
<TextBox Name="txt"
Width="150" ... />
<Popup PlacementTarget="{Binding ElementName=txt}"
Placement="Bottom"
IsOpen="True"
StaysOpen="True"
Width="{Binding ActualWidth, ElementName=txt}">
<!-- Some popup content here -->
</Popup>
</Grid>
</UserControl>
This is obviously an extremely simplified example, but you get the idea.

Why do my commandbindings only work if button is in toolbar?

I have a window with a toolbar which contains some buttons with commands.
The Buttons stopped working since i replaced the toolbar with a stackpanel containing the buttons.
In my understanding this shound not make any difference. The buttons still have the Command property set, i did not change anything in my custom commands class and the CommandBinding are also still the same. They are implemented some grids and usercontrols deeper than the button, but they do work, as long as the buttons are in a ToolBar control!
If i implement CommandBindings directly in the Window they work (but that is not what i want)
Here's the code (abridged):
<Window>
<Grid>
<StackPanel>
<Button Command="gui:GuiCommands.Hello">Hello</Button>
</StackPanel>
<Grid>
<TabControl>
<TabItem Header="MyTab">
<Grid>
<Grid.CommandBindings>
<CommandBinding Command="gui:GuiCommands.Hello" Executed="hello_Clicked"/> <!-- THIS WOULD NOT WORK -->
</Grid.CommandBindings>
<Grid>
</TabItem>
</TabControl>
</Grid>
</Grid>
<Window.CommandBindings>
<CommandBinding Command="gui:GuiCommands.Hello" Executed="hello_Clicked"/> <!-- THIS WOULD WORK -->
</Window.CommandBindings>
</Window>
I know it would not compile but i had to simplify it. This works as soon as i replace "StackPanel" with "ToolBar" with my app. How can that be?
Okay, i guess is figured it out by my self again (why does this always happen right after i posted the question?)
Short: I needed to set FocusManager.IsFocusScope="true" on the StackPanel
Long: see the answer to this question: Do I have to use CommandTarget? I thought any focused element would receive the Command
A StackPanel only arranges child elements into a single line that can be oriented horizontally or vertically.
While a Toolbar provides a container for a group of commands or controls.
So what happens if you put a StackPanel element inside of the ToolBar
<ToolBar>
<StackPanel>
<Button Command="gui:GuiCommands.Hello">Hello</Button>
</StackPanel>
</ToolBar>

PopUp in Silverlight is not being clipped by container control

Simple, yet frustrating issue here...
I have a PopUp control.
It is contained in side a Grid, which has a Grid.Clip defined.
The PopUp is still visible outside the Grid's clipped area.
i.e.
<Grid Background="Red" Width="150" Height="150">
<Grid.Clip>
<RectangleGeometry Rect="0,0,150,150" />
</Grid.Clip>
<Popup IsOpen="True" Margin="100,100,0,0">
<Grid Background="Green" Width="150" Height="150" />
</Popup>
</Grid>
Ideally, the green box should not appear or "bleed" outside of the red box. The problem is that it is contained within a PopUp, and so it bleeds. How can I modify this (without removing the PopUp control) so that the PopUp does not bleed outside of it's containing control?
Popup works differently. It "ignores" its parent and it is added directly into visual root of your app. This is how it can be on-top of everything.
So now it depends on what are you trying to do. I think popup is not suitable for this scenario.
You can try to clip the popup in its template, but I feel that's not what you want.

Silverlight - specify stackpanel contents of a user control in the parent

I created a user control called 'RibbonTabX' which contains a stackpanel named 'spMain'. What I'd like to do, is when I declare an instance of my 'RibbonTabX' in xaml, within that same xaml I'd like to specify controls which will be inside the child stackPanel 'spMain'. Here is the code which will make what I'm trying to do much clearer:
<ribbon:RibbonTabX strHeaderText="Testing 123...">
<ribbon:RibbonTabX.spMain>
<sdk:Label Content="Hello" />
<sdk:Label Content="World" />
</ribbon:RibbonTabX.spMain>
</ribbon:RibbonTabX>
In the parent of RibbonTabX, I want to specify child contents of the stackpanel within my user control 'RibbonTabX'. Just like you can do with a 'TabItem' control. Any ideas how I can do this?
Thanks!
You need to create a custom content control, not a user control.
Start with this article
It is more complex than a user control as you have to hand-craft a generic template for it, but they are more versatile.
You want to use a ContentControl. Rather than specify that those controls go in the stack panel you probably should just place the Content in the stack panel. Have your RibbonTabX derive from ContentControl rather than UserControl, then where it is appropriate put the <ContentPresenter /> then the user of the ribbon can put whatever into it.
<ribbon:RibbonTabX strHeaderText="Testing 123...">
<StackPanel>
<sdk:Label Content="Hello" />
<sdk:Label Content="World" />
</StackPanel>
</ribbon:RibbonTabX>
Here is the most basic ContentControl possible:
<ContentControl x:Class="SilverlightControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid x:Name="LayoutRoot" Background="Orange">
<ContentPresenter />
</Grid>
</ContentControl>

How to wire up a click event for a custom usercontrol button? Should I use CustomControl?

I wanted to create a button that had an image and a textblock as content. So I went about looking for an answer and found a post (Reusable Custom Content for Buttons) which told me to create a usercontrol.
I did this and it works great. I can set the image source and text through dependency properties. However, I am stuck as there is no click event for my control.
I did a little more digging and concluded that I probably need a CustomControl derived from Button. Is this correct? Or would it be better to wire up a click event to my UserControl?
Here's my UserControl:
<UserControl x:Class="Client.Usercontrols.MyButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" MinHeight="30" MinWidth="40"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<Button Width="Auto" HorizontalAlignment="Center">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="Transparent" >
<Grid>
<Image Name="tehImage" Source="{Binding ImageSource}" />
<TextBlock Name="tehText" Text="{Binding Text}"
Style="{DynamicResource ButtonText}" />
</Grid>
</Border>
</Button>
</UserControl>
Implementation
<my:MyButton ImageSource="../Images/MainSyncButton.png" ImageWidth="141" Text="Synchronise" Click="btnSynchronise_Click" />
The easiest option would be to just make your UserControl expose a click event, and pass through your Button's click event.
In MyButton's xaml:
<Button Width="Auto" HorizontalAlignment="Center" Click="onButtonClick">
In MyButton's code:
public event RoutedEventHandler Click;
void onButtonClick(object sender, RoutedEventArgs e)
{
if (this.Click != null)
{
this.Click(this, e);
}
}
You can then leave your "implementation" code as-is.
The answer really depends on what your goals are for the control. You may be able to get away with not creating a user or custom control if you can manipulate the data that you are binding to. If all you want to do is display a dynamic image and text, then you could create an ImageText object that contains two properties. You could then bind the default Button control's Content property to this object and use a DataTemplate to define the layout of the content.
If you cannot control the data type that you are binding to, or if you're really set on the idea of creating a control then I would recommend creating a custom control. Custom controls allow you to utilize the built-in capabilities of a standard button. Generally you would only want to create a User Control if you wanted to hide or encapsulate the default functionality of the visual controls contained within the control.
Good luck.

Resources