I have a Window page, after click a button from window page --> then a UserControl page showing. After Inside UserControl there is a <Popup Name="MyPopup"> popup. The Popup always stays on top problem. How can I solve this issue ?
I have tried,
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Background="Green">
<Grid >
<Button Height="50" Width="100" Content="window_ClickMe" Click="btnUserManage_Click"></Button>
<ContentControl Name="cont2" Visibility="Hidden">
</ContentControl>
</Grid>
</Window>
and code behind page of window,
private void btnUserManage_Click(object sender, RoutedEventArgs e)
{
UC_UserMgmt mw = new UC_UserMgmt();
cont2.Content = mw;
cont2.Visibility = Visibility.Visible;
}
then, this is usercontrol page with popup,
<UserControl x:Class="WpfApplication1.UC_UserMgmt"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400" Background="Blue">
<Grid>
<Grid Name="g1">
<Button Content="usercontrol_ClickMe" Height="50" Width="150" Margin="150,0,0,250" Click="btnShow_Click"></Button>
</Grid>
<Popup Name="MyPopup" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
HorizontalOffset="-150" Placement="Mouse" StaysOpen="{Binding ElementName=g1,Path=IsMouseOver}"
VerticalOffset="20"
AllowsTransparency="True">
<StackPanel>
<Border BorderBrush="Black" Background="Brown" BorderThickness="1" Width="300" Height="100" >
<Grid>
<TextBox x:Name="txtUName" HorizontalAlignment="Center" Height="28" Width="223" TextWrapping="Wrap" VerticalAlignment="Top" Margin="10,26,64.6,0" />
<Button Content="Open" Height="30" Width="50" Margin="238,24,9.6,43.6" Click="btnOpen_Click"/>
</Grid>
</Border>
</StackPanel>
</Popup>
</Grid>
</UserControl>
and this is code behind page of usercontrol,
private void btnOpen_Click(object sender, EventArgs e)
{
MyPopup.IsOpen = true;
System.Windows.Forms.OpenFileDialog fDialog = new System.Windows.Forms.OpenFileDialog();
fDialog.Title = "Select file to be zip";
if (fDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
txtUName.Text = fDialog.FileName.ToString();
}
}
private void btnShow_Click(object sender, EventArgs e)
{
MyPopup.IsOpen = true;
}
The problem is, when user click on OPEN button, an openFileDialog is opening and when it is opened, the popup seems disappear. How can I solve this problem?
I believe using Popup is not the right choice in your situation. Take a look at Popup.StaysOpen Property, in particular the part that says
When the StaysOpen property is set to true, Popup stays open until it is explicitly closed by setting the IsOpen property to false. When StaysOpen is false, the Popup control intercepts all mouse and keyboard events to determine when one of these events occurs outside the Popup control.
I can't think of a clean way of keeping that popup open when showing the dialog box, because the dialog box is going to create a mouse/keyboard event when you interact with it
But to answer your question, I can think of two choices
1) You can simply move MyPopup.IsOpen = true; in btnOpen_Click to the end of the code block. I assume this will cause the popup to reopen after the dialog box is closed
2) You can create a boolean property or dependency property in your code behind set it to true when showing the popup and bind your Popup's StaysOpen to it, and maybe set it to false in LostFocus for g1 or something like that. Or even set StaysOpen to true and use IsOpen to close your Popup in g1's LostFocus
Edit - Second Solution How-To Don't use it, dirty code, bad practices, and the popup remains on top of dialogbox
In the Popup set StaysOpen="True"
In every control in the UserControl except the UserControl itself and the textbox set Focusable="False"
Add private bool dont; to the UserControl's code-behind and set it to True in the beginning of btnOpen_Click and set it to False in its end
In the UserControl and the TextBox add LostFocus="UserControl_LostFocus"
And then add this function in UserControl code-behind
private void UserControl_LostFocus(object sender, RoutedEventArgs e)
{
if(!dont && !txtUName.IsFocused && !IsFocused)
MyPopup.IsOpen = false;
}
Related
I have a dialog which returns a IList value for the key CreatedGroups.
I can already return said string when the user presses a certain button on the dialog to close it.
private void CloseDialogOK()
{
CanCloseDialog = true;
DialogParameters parm = new DialogParameters();
parm.Add("CreatedGroups", _createdGroups);
RequestClose?.Invoke(new DialogResult(ButtonResult.OK, parm));
}
However, as I cannot remove the [X] Close button located on the dialog's top right, how can I attach the same method above to the [X] Close button?
Prism has an attached property to set a style for the dialog window in the dialog UserControl markup. There, you can set the WindowStyle to None to remove the buttons and title.
<UserControl ...>
<mvvm:Dialog.WindowStyle>
<Style TargetType="Window">
<Setter Property="WindowStyle" Value="None"/>
</Style>
</mvvm:Dialog.WindowStyle>
<!-- ...other markup. -->
</UserControl>
If this does not fulfill your requirements, you will have to create a custom dialog window.
Register a Custom Dialog Window
There you could customize everything, even create your own buttons and title bar, e.g.:
<Window x:Class="MCOSMOS.Infrastructure.Interactivity.Confirmations.ConfirmationWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
SizeToContent="WidthAndHeight"
WindowStartupLocation="CenterOwner">
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="1"
CaptionHeight="0"
ResizeBorderThickness="1"
UseAeroCaptionButtons="False"
NonClientFrameEdges="Bottom"/>
</WindowChrome.WindowChrome>
<Window.Template>
<ControlTemplate TargetType="{x:Type Window}">
<DockPanel Background="White">
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0"
Text="{Binding Title, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"/>
<Button Grid.Column="1"
Focusable="False"
Content="X">
</Button>
</Grid>
<ContentPresenter DockPanel.Dock="Bottom"/>
</DockPanel>
</ControlTemplate>
</Window.Template>
</Window>
In this case, your could either add a Click event handler to the close Button or bind a command to it in order to add your custom behavior.
Another option of using the default window style, but changing how the close button works is to create a custom dialog window that adds a handler to the Closed event. Then you can put your custom behavior there. It will be called before the DialogService from Prism handles the event.
public partial class YourCustomDialogWindow : Window, IDialogWindow
{
public YourCustomDialogWindow()
{
InitializeComponent();
Closed += OnClosed;
}
public IDialogResult Result { get; set; }
private void OnClosed(object sender, EventArgs e)
{
// Check for null to make sure no other button caused closing.
if (DialogResult is null)
{
var dataContext = (YourDataContext)DataContext;
// ...do something, call a method and set a result.
}
}
}
In general, instead of casting to a concrete data context type, you could provide your own interface to make the dialog with this mechanism reusable instead of hard-wired to a single data context.
Yet another option to solve the issue in a general way is to create your own DialogService by deriving from the default implementation and changing how closing is handled. Overwrite the ConfigureDialogWindowEvents method, copy the default implementation here and customize the closedHandler, e.g.:
EventHandler closedHandler = null;
closedHandler = (o, e) =>
{
// ...
if (dialogWindow.Result == null)
dialogWindow.Result = // ...get and set your result.
// ...
};
dialogWindow.Closed += closedHandler;
Please be aware that these approaches assume that all other methods of closing the dialog will set an IDialogResult, so that you can be sure that a value of null means the dialog was closed through an external mechanism like the close button.
I was testing a Popup control in WPF with the following code
<Window x:Class="Popup1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Popup1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="250">
<Grid>
<TextBlock TextWrapping="Wrap">You can use a popup to provide a link for a specific
<Run TextDecorations="Underline" MouseEnter="ContentElement_OnMouseEnter">
term
</Run>
</TextBlock>
<Popup Name="popLink" StaysOpen="False" Placement="Mouse" MaxWidth="200"
PopupAnimation="Slide" AllowsTransparency="True">
<Border>
<TextBlock Margin="10" TextWrapping="Wrap">
For more information, see
<Hyperlink NavigateUri="http://en.wikipedia.org/wiki/Term" Click="Hyperlink_OnClick">Wikipedia</Hyperlink>
</TextBlock>
</Border>
</Popup>
</Grid>
</Window>
and the handlers
private void ContentElement_OnMouseEnter(object sender, MouseEventArgs e) {
popLink.IsOpen = true;
}
private void Hyperlink_OnClick(object sender, RoutedEventArgs e) {
Process.Start(((Hyperlink) sender).NavigateUri.ToString());
}
The result is a trivial window that contains a textblock with a link to a popup control that visually appears when the mouse hovers over the link to the popup.
The normal behavioris the popup to stay visible until a mouse click. This works fine as long as the mouse click is not on the link to the popup
The strange behaviorthat i can't explain happens when i click the mouse over the link to the popup.Then, the popup closes ( as expected ) but it never appears again when the mouse hovers over the link (as it should).
Can you explain this behavior?
As commented, the reason is probably a race condition between closing popup and re-opening because the mouse is over the textblock. You can prevent this situation by delaying the popup open action until current work is completed:
private void ContentElement_OnMouseEnter(object sender, MouseEventArgs e)
{
Dispatcher.BeginInvoke(new Action(() => popLink.IsOpen = true));
}
Regarding your title text: the MouseEnter event is actually fired (debug it!), just the action within is not working as expected because the popup is in an inconsistent state.
After some tweaking the best behaviour is achieved if we add an extra event (comparing to the initial code) handler for the Popup Close event that sets the IsOpen property to false when the popup closes
private void PopLink_OnClosed(object sender, EventArgs e) {
if (popLink.IsOpen) {
popLink.IsOpen = false;
}
}
and the ammenment in XAML
<Popup Name="popLink" StaysOpen="False" Placement="Mouse" MaxWidth="200"
PopupAnimation="Slide" AllowsTransparency="True"
Closed="PopLink_OnClosed">
<Border Background="Bisque">
<TextBlock Margin="10" TextWrapping="Wrap">
For more information, see
<Hyperlink NavigateUri="http://en.wikipedia.org/wiki/Term" Click="Hyperlink_OnClick">Wikipedia</Hyperlink>
</TextBlock>
</Border>
</Popup>
I am trying to achieve the following:
User brings up a context menu in a datagrid.
User selects a context menu item which then opens a popup and displays some information.
when the user clicks anywhere else in the application, not in the popup, the popup closes.
Everything works fine until I come to closing the popup.
From searching elsewhere I am aware that I need Staysopen to be set to false ( which it is)
I also read the best way is to bind the IsOpen value to a property in the view model and set its binding to 2 way ( also done )
As a side note I have found that if I add a textbox and click inside the box, when I then click outside the popup it closes as desired.
Another thing I unsuccessfully tried as a workaround was to programmatically set the keyboard focus on the text box to get the "autoclose" functionality I desired.
Here is code:
xaml -
<Popup Name="PredictionsPopup" Height="200" Width="200" AllowsTransparency="false" StaysOpen="False" IsOpen="{Binding DisplaySummaryPopup, Mode=TwoWay}">
<StackPanel Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}">
<TextBlock Text="here is some stuff" />
<TextBox Name="hiddenBox" Text="moo"/>
</StackPanel>
</Popup>
Codebehind that sets the property on the viewmodel when the menu item is selected.
private void CurrentPredicitions_OnClick(object sender, RadRoutedEventArgs e)
{
PredictionsPopup.Placement = PlacementMode.MousePoint;
ViewModel.DisplaySummaryPopup = true;
}
Viewmodel property
public bool? DisplaySummaryPopup
{
get
{
return this.displaySummaryPopup;
}
set
{
this.displaySummaryPopup = value;
RaisePropertyChanged(() => this.DisplaySummaryPopup);
}
}
Please let me know if you need anymore details.
Here you have a working example:
MainWindow XAML:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Popup Name="PredictionsPopup" Height="200" Width="200" AllowsTransparency="false" StaysOpen="False" IsOpen="{Binding DisplaySummaryPopup, Mode=TwoWay}">
<StackPanel Background="Red">
<TextBlock Text="here is some stuff" />
<TextBox Name="hiddenBox" Text="moo"/>
</StackPanel>
</Popup>
<DataGrid AutoGenerateColumns="False" Name="dataGrid1" IsReadOnly="True" >
<DataGrid.Columns>
<DataGridTextColumn Header="Site" Width="150" />
<DataGridTextColumn Header="Subject" Width="310" />
</DataGrid.Columns>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Click Me" Click="ButtonBase_OnClick">
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
</Grid>
</Window>
MainWindow cs :
public MainWindow()
{
InitializeComponent();
DataContext = new TestViewModel();
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
PredictionsPopup.Placement = PlacementMode.MousePoint;
PredictionsPopup.IsOpen = true;
}
ViewModel:
public class TestViewModel : INotifyPropertyChanged
{
private bool _displaySumarry;
public bool DisplaySummaryPopup
{
get { return _displaySumarry; }
set
{
_displaySumarry = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
I think that your implementation for INotifyPropertyChanged is the one which causes the problem. I tried myself the code and is working now.
After trying to track this problem down I worked out that the issue is something to do with the context menu. I know this because as per the answer above instead of launching my popup via a context menu I launched it from a test button and all worked as expected.
I still don't know the exact reason for this issue but I think its something to do with the fact that the context menu is itself a subclass of popup and the focus isn't being set correctly on the new popup, so it never detects popup loss and closes.
To get round my problem I have added a close button to the popup, and then whenever the active tab in the control that hosts the popup changes it fires an event that the popup picks up and closes.
Had the same problem. The reason was, that the toggle button's ClickMode property was set to "Press". Setting it back to "Release" solved it :).
For me, the solution was to add this line in the constructor of the popup's code-behind:
LostFocus += delegate { this.IsOpen = false; };
Many hours were spent, when such a quickie line was all it took :)
I faced same problem a few times. Every time it was occuring, when a popup was changing its "isOpen" property to true from an event, which was raised from listview or datagrid element, like selectedItemChanged event, or items mouseUp event. I don't know reason, however resolved it by opening the popup from another task with code as below:
Task.Run(()=> Dispatcher.Invoke( () => myPopup.IsOpen = true));
Dispatcher is used to avoid an exception from changing any GUI object property from another than the main thread.
I have a UserControl which is shown in a popup. I have a button in usercontrol that on clicking, makes a textfield visible. But as again i visit that usercontrol, the textfiled remains visible, i want it to be again collapsed until user clicks the button.
I have no clue how to do that? which method to override. please help me
use the UserControl.Loaded event to set your textfield to collapsed.
This blogpost about the Loaded and Initialized Event was very helpful for me.
Example:
UserControl XAML
<UserControl x:Class="YourNamespaceName.YourClassName"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Loaded="YourClassName_OnLoaded">
<Grid>
<TextBlock x:Name="testTextBlock" Text="Invisible on startup" />
<Button x:Name="testButton" Content="Click" Click="TestButton_OnClick" />
</Grid>
</UserControl>
UserControl CodeBehind
private void YourClassName_OnLoaded(object sender, System.Windows.RoutedEventArgs e)
{
this.testTextBlock.Visibility = Visibility.Collapsed;
}
private void TestButton_OnClick(object sender, RoutedEventArgs e)
{
this.testTextBlock.Visibility = Visibility.Visible;
}
I am very new to XAML and WPF.I have a problem.
I have two files. first.xaml and second.Xaml. There is a button in first.xaml, on click of which it should navigate to second.xaml.How do i achieve this.
This is one way of organising the code:
Your second.xaml should contain your window definiton e.g.:
<Window x:Class="MediaCheckerWPF.AboutBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="About Media Checker" Height="300" Width="400" ResizeMode="NoResize"
Icon="/MediaCheckerWPF;component/Resources/checker.ico"
ShowInTaskbar="False">
<Grid>
...
</Grid>
</Window>
Your first.xaml has the button e.g.:
<Button Height="23" HorizontalAlignment="Right" Name="aboutButton"
VerticalAlignment="Top" Width="23" Click="AboutButton_Click"
Content="{DynamicResource TInformationButton}"
ToolTip="{DynamicResource TInformationButtonTooltip}" Margin="0,0,8,0"/>
Then in the code behind:
private void AboutButton_Click(object sender, RoutedEventArgs e)
{
var about = new AboutBox { Owner = this };
about.Initialise();
about.Show();
}
ChrisF's answer is a good way of popping up a new window in a Windows-style application, except you should not call Initialize that way (it should be called from the constructor).
If you want web-style navigation instead, you should use the Page class instead of Window, along with NavigationService. This also allows your WPF application to run inside an actual web browser.