Consider the following XAML:
<Window x:Class="ContextMenuEvent.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" ContextMenuOpening="Window_ContextMenuOpening">
<Grid>
<Button>Ok</Button>
</Grid>
</Window>
Right-clicking the button causes ContextMenuOpening to fire, even though no context menu actually appearing.
Why is it happening? What can I do to get an even only when a context menu is REALLY opening?
I am aware I can use ContextMenu.Opened event, but this will only cover a single context menu, and I want to cover all the (existing) context menus in the form.
Not so sure why you'd use this approach. You can however easily check if a context menu would appear. Like this:
private void Window_ContextMenuOpening(object sender, ContextMenuEventArgs e) {
var menu = (e.Source as FrameworkElement).ContextMenu;
if (menu != null) {
// etc..
}
}
You would the source element of the ContextMenuEventArgs parameter, and cast it as a System.Windows.Controls.Control (or something as generic as that which would cover all clicks). You can then check the ContextMenu property.
Related
I am trying to use RoutedCommands in my UserControls, following the example in this article:
https://joshsmithonwpf.wordpress.com/2008/03/18/understanding-routed-commands/
I defined the RoutedCommand and CommandBindings in the UserControl instead of in the article's example. I am trying to use it in my MainWindow, so that when the Button is clicked, the Command in the UserControl is executed. However, the Button is disabled and the Foo_CanExecute() method is never executed.
<UserControl x:Class="RoutedCommandTest.ViewControl"
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:RoutedCommandTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.CommandBindings>
<CommandBinding
Command="{x:Static local:ViewControl.Foo}"
PreviewCanExecute="Foo_CanExecute"
PreviewExecuted="Foo_Executed"
/>
</UserControl.CommandBindings>
<Grid>
</Grid>
</UserControl>
Here is the code for ViewControl.xaml.cs:
public static readonly RoutedCommand Foo = new RoutedCommand();
void Foo_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
void Foo_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("The Window is Fooing...");
}
public ViewControl()
{
InitializeComponent();
}
And here is the code for MainWindow.xaml:
<Window x:Class="RoutedCommandTest.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:RoutedCommandTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:ViewControl/>
<Button Content="Foo" Margin="0 5" Command="{x:Static local:ViewControl.Foo}"/>
</Grid>
</Window>
I would like to know how to fix the issue so that the Button is enabled and the Foo_CanExecute() method is executed when the Button is clicked.
Your command is in a usercontrol, whilst the button is in mainwindow.
Which presumably contains your usercontrol.
Like bubbling and routing events ( which are used to drive them ).
Executed looks for the command bubbling UP the visual tree to the binding.
PreviewExecuted looks for the command tunnelling DOWN the visual tree to the binding.
Since your button is in the parent of the usercontrol I'm not sure whether either bubbling or tunnelling will work.
But tunnelling would be PreviewExecuted And PreviewCanExecute.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.commandbinding.previewexecuted?view=netframework-4.8
https://learn.microsoft.com/en-us/dotnet/api/system.windows.input.commandbinding.previewcanexecute?view=netframework-4.8
Routedcommands can be pretty tricky to get right.
One thing you sometimes have to do is to bind commandtarget to tell it where to go look.
eg:
<Grid>
<local:UserControl1 x:Name="UC1" Height="60" Width="100"/>
<Button Content="Foo" TextElement.FontSize="30" Command="{x:Static local:UserControl1.Foo}"
CommandTarget="{Binding ElementName=UC1}"
/>
</Grid>
Works for me.
I have rarely found them useful - this is one of the aspects makes them way less useful than you might at first imagine.
EDIT:
It's perhaps worth mentioning the other thing makes these unattractive compared to a regular icommand. You need to either use a static which means it's only suitable for very generic commands OR you need event handlers which will be in code behind.
On the other hand.
If you're writing something has to work generically with whatever has focus. Like say a text editor with multiple textboxes and you're doing text manipulation. A routed command might be suitable. I have never encountered such a requirement in apps I've worked on though.
I have a window, it will do some checking before it is shown.
public class MyDlg : Window
{
public MyDlg()
{
Initialized += new EventHandler(Window_Initialized);
}
private void Window_Initialized(object sender, EventArgs eventArgs)
{
if (!/*do some checking*/)
{
Loaded += (s, e) => Close();
}
}
}
If "do some checking" fail, the above code will close my window immediately after the window is loaded. However this is too late because I can see the window just appear and disappear.
How can I close my window without showing it?
EDIT:
The one who will construct MyDlg is like:
MyDlg dlg = new MyDlg ();
dlg.ShowDialog();
But it is hard for me to prevent calling 'ShowDialog()', because they are written by other people (I'm trying to write MyDlg in some library)
How can I close my window without showing it?
Perform the check before calling the Show or ShowDialog method of the window. You could either do this in the calling code:
MyDlg dlg = new MyDlg();
//perform your check here...
dlg.ShowDialog();
...or in the constructor of the MyDlg window:
public MyDlg()
{
//perform your check here...
}
Obviously the window is already shown by the time the Window_Initialized event handler gets invoked so then it is too late to perform any check if you don't want the window to appear. You cannot close a window that hasn't been opened.
You can create splash dialog inside your new window.
And set IsEnabled=False on window/dialog.
Or if your operation is quick then there is no need for splash. Just hide your window:
<Window x:Class="Wpf.Test01.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:Wpf.Test01"
xmlns:charting="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
mc:Ignorable="d"
IsEnabled="False"
WindowStyle="None"
AllowsTransparency="True"
Title="MainWindow" Height="350" Width="525">
<Window.Background>
<SolidColorBrush Opacity="0.0" Color="White" />
</Window.Background>
You can see it done here WPF Window with transparent background containing opaque controls
Of course change the properties back to visible/default if everything is ok
I have a simple window:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:self="clr-namespace:WpfApplication1"
Title="MainWindow" Height="435" Width="613">
<StackPanel>
<Canvas Name="canvas">
<self:Red />
</Canvas>
<UserControl Name="uc">
<self:Blue />
</UserControl>
</StackPanel>
</Window>
Redand Blueare very simple UserControls:
<UserControl x:Class="WpfApplication1.Blue"
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">
<Grid>
<Rectangle Fill="Blue" Width="100" Height="100" />
</Grid>
</UserControl>
I have created some ContextMenus:
public MainWindow()
{
InitializeComponent();
canvas.ContextMenu = new ContextMenu();
canvas.ContextMenuOpening += (sender, e) =>
{
System.Diagnostics.Debug.WriteLine(e.Source.GetType());
};
uc.ContextMenu = new ContextMenu();
uc.ContextMenuOpening += (sender, e) =>
{
System.Diagnostics.Debug.WriteLine(e.Source.GetType());
};
}
If I open the context menu on the Canvas, the Source is Red, but if I open it on the UserControl, Source is UserControl.
Any idea why?
I found this on MSDN:
ContextMenu itself is a FrameworkElement derived class, but this event will not be raised from the context menu being opened as a source. The event is raised from the element that "owns" the context menu as a property...
If I understand it correctly Source should be Canvas in the first case, but it isn't.
This behavior is covered fairly well in the MSDN documentation for the RoutedEventArgs.OriginalSource property:
Source adjustment by various elements and content models varies from class to class. Each class that adjusts event sources attempts to anticipate which source is the most useful to report for most input scenarios and the scenarios for which the class is intended, and then sets that source as the Source. If this source is not the one that has relevance to your handling of the event, try checking OriginalSource instead to see if it reports a different source that is more suitable.
Which is exactly what the UserControl class does, it patches the Source property in its AdjustBranchSource() method.
So, as hinted by the quoted text, you are perhaps looking for the OriginalSource property to make the code behave similarly, you'll get a reference to the Rectangle in both cases.
Certain elements of my application have custom resizing events, which all work. However, they are messed up by one case:
When hovering over the border of the window, so that the cursor becomes the resize handle, and you click (but do not drag), the elements resize incorrectly, and my handlers are not fired.
I've looked for such an event but cannot find anything that matches. I'd like to simply make a handler for this event to avoid glitchy resizing of my elements.
I'm using C#/WPF, with .NET 4
xaml for the window:
<Window x:Class="XHealth.MainWindow"
Name="mainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridTemplateSample"
xmlns:XH="clr-namespace:XHealth"
xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit"
SizeChanged="update_size"
Title="XHealth" Loaded="Window_Loaded" WindowState="Normal" WindowStartupLocation="CenterScreen" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" SizeToContent="WidthAndHeight" WindowStyle="ThreeDBorderWindow" MinWidth="650" MinHeight="648" Width="Auto" VerticalAlignment="Top" DataContext="{Binding}" PreviewKeyDown="Window_KeyDown">
Event handler:
public void update_size(object sender, RoutedEventArgs e )
{
if (resultsTab.IsSelected){
Grid.SetRowSpan(dataGrid1, 2);
Grid.SetRowSpan(dataGrid2, 2);
}
}
This handler performs as intended, but does not trigger when the resize handle is not dragged, which leads me to believe clicking the resize handle is a different event.
Also, this only happens once - once my resize handler takes effect, clicked the resize handle has no effect.
Converting my comment into an answer:
That could be resolved by not putting any * in the Grid.
Also, if the Window is set to SizeToContent, you should only SizeToContent=Width to prevent the window from scaling endlessly.
Remove all the event handlers stuff, that's hack.
I'm looking for a click event or something similar for use with the ModernUI WPF's ModernTab.
I'm currently using ModernUI WPF (http://mui.codeplex.com/) and I'm trying to use a ModernTab control as a list of employees, which I'll then click and open their details in the Source page.
Problem is, I am going to be creating the list of employees at runtime from a database, which will mean that I'll need to add the links manually. Therefore, I need to be able to hook some click event from the tab so I can find out what user to display- but I don't see a property that'll work. The closest I can see is that the ModernTab parent control has click events, but they only register if I click an empty part of the control.
The only other thing I can think of is to generate a custom panel for each employee at runtime and set it to the Source attribute when I create the list, which I'd rather not do if possible.
Here's my panel:
<UserControl x:Class="Schedule.Pages.EditEmployees"
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:mui="http://firstfloorsoftware.com/ModernUI"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Style="{StaticResource ContentRoot}">
<mui:ModernTab Layout="List" Name="employeeTabList" >
<mui:ModernTab.Links >
<mui:Link DisplayName="Create New..." Source="/Pages/EditEmployeeDetail.xaml" />
</mui:ModernTab.Links>
</mui:ModernTab>
</Grid>
Any help appreciated!
This is just one example of "hijacking" the click on the ModernTab. Here, you can force the content to load in the top frame, for example:
Handle the SelectedSourceChanged event of the ModernTab:
employeeTabList.SelectedSourceChanged += employeeTabList_SelectedSourceChanged;
void employeeTabList_SelectedSourceChanged(object sender, SourceEventArgs e)
{
if (e.Source.OriginalString.EndsWith("EditEmployeeDetail.xaml"))
{
var url = "/Pages/EditEmployeeDetail.xaml";
var bb = new BBCodeBlock();
bb.LinkNavigator.Navigate(new Uri(url, UriKind.Relative), this, NavigationHelper.FrameTop);
// You may want to set some property in that page's ViewModel, for example, indicating the selected User ID.
}
}
Add a fragment to the Uri representing each employee when links are created. Then for the EmployeeDetail usercontrol implement the IContent Interface (specifically OnFragmentNavigation to initialize the data using the fragment). Sample code here -
http://mui.codeplex.com/discussions/455846