How to make a messagebox show up on left click - c#

I have a pretty simple problem but I can't get it to work. I want a MessageBox to appear each time I left click inside my form. I didn't know how to capture it on the whole form so I started of trying to capture my left click inside my WebBrowser1. However, nothing really happens when trying to trigger the event.
I declared the action as WebBrowser1_Mousedown.
private void WebBrowser1_Mousedown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
MessageBox.Show("test");
}
}
What am I doing wrong?
My relevant XAML as follows:
<Window x:Class="IndianBrowser.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="488.806" Width="807.089" MouseDown="Window_MouseDown">
and now trying with the webbrowser:
<WebBrowser x:Name="WebBrowser1" HorizontalAlignment="Stretch" Height="auto" Margin="0,85,0,0" VerticalAlignment="Stretch" Width="auto" MouseDown="WebBrowser1_Mousedown"/>

If you look into MSDN documentation for WebBrowser class, you'll see that mouse events are not supported. What you can do instead is subscribe for HtmlDocument.MouseDown event.
Update
Here is small snippet that demonstrates how to do this in WPF, NOTE you will have to add reference to Microsoft.mshtml assembly:
public MainWindow()
{
InitializeComponent();
this.webBrowser1.Navigated += webBrowser1_Navigated;
this.webBrowser1.Source = new Uri("your url");
}
void webBrowser1_Navigated(object sender, NavigationEventArgs e)
{
HTMLDocumentClass document = this.webBrowser1.Document as HTMLDocumentClass;
document.HTMLDocumentEvents2_Event_onclick += document_HTMLDocumentEvents2_Event_onclick;
}
bool document_HTMLDocumentEvents2_Event_onclick(IHTMLEventObj pEvtObj)
{
// here you can check if the clicked element is your form
// if (pEvtObj.fromElement.id == "some id")
MessageBox.Show("test");
return true;
}

Related

WPF Windows Not Responding After Windows Sleep/Resume

I have a fairly simple C# WPF application using .NET 5. Basically it sits in the background and times specific events for the end user. The events are built from a xml file that is generated externally.
The application consists of 2 windows, one hidden that does all the thinking. If it detects that an event is due it raises a toast message which when clicked on opens the other window to show the event details to the user. All works fine and runs as expected except after a windows sleep/suspend and resume. We obviously don't want the events to add up upon sleep/suspend and so we close the hidden window and upon resume open it again. No problems there but once the system is resumed and an event is raised the visible window refuses to show. If the visible window is open when sleep/suspend happens then upon resume the whole window is frozen and refuses to respond (only way to close the window is kill the application and restart)
The APP code is as follows :-
public static Forms.NotifyIcon notifyIcon;
public static MainWindow mw;
public static ConfigWindow cw;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
// Listen to notification activation
ToastNotificationManagerCompat.OnActivated += toastArgs =>
{
// Obtain the arguments from the notification
ToastArguments args = ToastArguments.Parse(toastArgs.Argument);
// Obtain any user input (text boxes, menu selections) from the notification
ValueSet userInput = toastArgs.UserInput;
// Need to dispatch to UI thread if performing UI operations
Application.Current.Dispatcher.Invoke(delegate
{
ToastControl.HandleToast(args);
});
};
ConfNotifyIcon();
OpenApp();
}
private void ConfNotifyIcon()
{
notifyIcon = new Forms.NotifyIcon();
notifyIcon.Icon = new System.Drawing.Icon("Images/Wellformation.ico");
notifyIcon.DoubleClick += OnClick;
notifyIcon.ContextMenuStrip = new Forms.ContextMenuStrip();
notifyIcon.ContextMenuStrip.Items.Add("Open", System.Drawing.Image.FromFile("Images/Wellformation.ico"), OnClick);
notifyIcon.ContextMenuStrip.Items.Add("Close", System.Drawing.Image.FromFile("Images/Wellformation.ico"), OnClose);
notifyIcon.ContextMenuStrip.Items.Add(new Forms.ToolStripSeparator());
notifyIcon.ContextMenuStrip.Items.Add("Exit", System.Drawing.Image.FromFile("Images/Wellformation.ico"), OnExit);
}
private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
switch (e.Mode)
{
case PowerModes.Suspend:
this.Dispatcher.BeginInvoke((Action)(() =>
{
PrepareLock();
}), null);
break;
case PowerModes.Resume:
this.Dispatcher.BeginInvoke((Action)(() =>
{
PrepareAwake();
}), null);
break;
default:
break;
}
}
private void PrepareAwake()
{
OpenApp();
ConfNotifyIcon();
notifyIcon.Visible = true;
}
private void PrepareLock()
{
notifyIcon.Dispose();
cw.Close();
}
private void OnExit(object sender, EventArgs e)
{
Application.Current.Shutdown();
}
private void OnClose(object sender, EventArgs e)
{
mw.Close();
}
private void OnClick(object sender, EventArgs e)
{
OpenMain();
}
private void OpenMain()
{
mw = new();
mw.Show();
mw.Activate();
}
public static void OpenApp()
{
cw = new ConfigWindow();
}
The hidden Window XAML is as follows :-
<Window x:Class="WellformationDesktopApplication.ConfigWindow"
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:WellformationDesktopApplication"
mc:Ignorable="d"
Title="ConfigWindow" Height="1" Width="1" Visibility="Hidden" WindowState="Minimized">
<Grid>
</Grid>
</Window>
with code as follows :-
Timer at = new();
public ConfigWindow()
{
BuildConfig();
InitializeComponent();
}
public void refreshconfig()
{
myObjects.Clear();
myObjects = NudgeManager.GetNudges();
NudgeHandler(myObjects);
}
public void BuildConfig()
{
myObjects.Clear();
myObjects = GetEvents(); // pulls a list of event names with intervals from the config file
EventHandler(myObjects); //Goes through the list of events and figures out when the next event is due based upon the interval in the configuration
ActionTimer();
}
private void ActionTimer()
{
at.Interval = 60000;
at.Elapsed += ChecktActions;
at.AutoReset = true;
at.Enabled = true;
}
private void ChecktActions(object sender, ElapsedEventArgs e)
{
//Go through the trigger times for all events and see if those time have passed, if they have raise a toast showing the event name.
//If an event is raised reset the trigger time for the event based upon the interval and reset that time.
}
and the visible window XAML is as follows :-
<Window x:Class="WellformationDesktopApplication.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:WellformationDesktopApplication"
mc:Ignorable="d"
ResizeMode="NoResize"
WindowStyle="None"
Title="MainWindow" Height="500" Width="800" Background="{x:Null}" Foreground="{x:Null}" AllowsTransparency="True">
<Grid x:Name="BG">
<TextBlock x:Name="Display" HorizontalAlignment="Left" Margin="546,13,0,0" Text="Show event name and appropriate information about the event here..." VerticalAlignment="Top" FontSize="22"/>
</Grid>
</Window>
With Code as follows :-
public MainWindow()
{
InitializeComponent();
setstyles();
this.MouseLeftButtonDown += delegate { DragMove(); };
}
We know that everything to do with the ConfigWindow works fine, we know it is closed upon suspend and a new one is opened on resume with new timings set and all the appropriate alerts working.
The issue is with MainWindow as after a suspend and resume it cannot be interacted with at all. The open button on the icon does nothing, if the window is opened is is completely frozen and cannot be interacted with in any way, and if a toast is clicked on the window does not open but the rest of the toast handling code works fine around it. This happens on Win8, Win10 and Win11.
Any help out there as I am completely at a loss for how this is happening?
Thanks
After much work and going through the code section by section commenting it out to see if it made a difference I have found the issue.
Buried deep inside the the code for the hidden window (4 calls to functions down the line) I found that the EventHandler() was also raising a listener for
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(OnSessionSwitch);
With all the associated functions buried in a separate class that was not directly referenced from the window itself.
When this line was commented out everything worked fine, with it in and attached to the hidden window after Suspend/Resume of windows no UI changes would take place throughout the whole code (hence hidden window continued to working completely fine as it did not interact with the UI).
By lifting this code out into the APP space and handling it there rather than in a window the problem has gone away (though has revealed other issues that were not being handled upon Resume of Windows that I now have to fix).
So the answer is that for a WPF application listeners for SystemEvents of any type need to be housed int the APP code space and not within windows.

Keyboard accelerator firing when writing to Textbox

Click event of Button is fired when pressing D while writing to Textbox.
Is there an elegant way how to suppress Keyboard Accelerator while Textbox is focused?
XAML:
<StackPanel Orientation="Vertical">
<TextBox></TextBox>
<Button Click="Button_Click" Content="Button with "D" as keyboard accelerator" Margin="0,10">
<Button.KeyboardAccelerators>
<KeyboardAccelerator Key="D"></KeyboardAccelerator>
</Button.KeyboardAccelerators>
</Button>
<TextBlock x:Name="ButtonClickCounter"></TextBlock>
</StackPanel>
C#:
int buttonClickCounter;
private void Button_Click(object sender, RoutedEventArgs e)
{
ButtonClickCounter.Text = $"Button clicked {++buttonClickCounter} times";
}
EDIT:
Why Accelerator with Modifier (Alt+D or Ctrl+D) is not solution?
I am creating video player and I found that one-key shortcuts are neat solution for fast operations with video player (same as in VLC).
Best Solution so far:
Creating custom KeyboardAccelerator, that checks if focus is set to text box. Only edit in code that need to be done is changing KeyboardAccelerator to AcceleratorWithHandledActionIfTextboxIsFocused.
public class AcceleratorWithHandleDActionIfTextboxIsFocused:KeyboardAccelerator
{
public AcceleratorWithHandleActionIfTextboxIsFocused()
{
Invoked += AcceleratorWithHandleActionIfTextboxIsFocused_Invoked;
}
private void AcceleratorWithHandleActionIfTextboxIsFocused_Invoked(KeyboardAccelerator sender, KeyboardAcceleratorInvokedEventArgs args)
{
var focusedElement = FocusManager.GetFocusedElement();
if (focusedElement.GetType() == typeof(TextBox))
args.Handled = true;
}
}
part of XAML:
<Button.KeyboardAccelerators>
<custom:AcceleratorWithHandleDActionIfTextboxIsFocused Key="D"></KeyboardAccelerator>
</Button.KeyboardAccelerators>
I agree with #Thomas Weller in his comments as for not using a single letter as a keyboard accelerator...
But everybody has their own requirements, anyway, you could try to e.handle = true your event when textbox is focused.
Something like this:
public void Button_Click(object sender, ExecutedRoutedEventArgs e)
{
if (textBox.isFocused)
{
e.handled = true;
}
}

WPF disabling the window close button via MVVM

I am trying to disable the close button on a window via MVVM
I realise that you can do this in the view (window) CS code by stating
public Window()
{
InitializeComponent();
this.Closing += new System.ComponentModel.CancelEventHandler(Window_Closing);
}
void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
However I would like to keep it consistent and try to do this is the MVVM.
Thanks
It's a strange demand. If you have a closing button,why you disable it's func. But you can realize it with mvvm like this:
add two ref:
- Microsoft.Expression.Interactions.dll
- System.Windows.Interactivity.dll
add two xmlns:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
create trigger to window:
<Window x:Class="WpfApplication3.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:control="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Input.Toolkit"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Title="MainWindow" Height="350" Width="525">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Closing">
<ei:CallMethodAction TargetObject="{Binding}" MethodName="WindowsClosing"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Grid >
</Grid>
</Window>
edit viewmodel,and creat closing func:
public void WindowsClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
}
Change your Closing method with a variable from ViewModel.
void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = (this.DataContext as MyViewModel).ProcessWorking;
}
In your ViewModel (MyViewModel) add a property ProcessWorking :
public Boolean ProcessWorking
{
get { return this.processWorking; }
}
and in your method of background thread, just modify processWorking
private Boolean processWorking;
private void MyBackgroundThread()
{
this.processWorking = true;
// do your process
this.processWorking = false;
}
You can add a RaisePropertyChange() when you modify this.processWorking if you want to show somewhere of your UI the state of the background process.
you can use the ResizeMode of Window or you can use it by using Window API use of Window API mentioend Here

How to catch mouse movement when left mouseButton is pressed on a button control and released on different button control?

I have created a custom user control in WPF, which is shown in attached image, I want to mouse left click on button "8" and by holding down mouse button move on another button eg: button "1" and release mouse left button. Now i want to get the both buttons "8" when clicking on it and "1" when releasing the button. I have registered the PreviewMouseLeftButtonDown to get mouse down event and PreviewMouseLeftButtonUp to get mouse up event. but when i click on "8" and move on "1" release button in both event i get the same "8" button.
Can anyone please let me know how can i achieve this.
private ToggleButton _startButton;
private ToggleButton _endButton;
private void tb_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_startButton = sender as ToggleButton;
}
private void tb_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
_endButton = sender as ToggleButton;
if (_endButton != null && _startButton != null)
{
string start = _startButton.Content.ToString();
string end = _endButton.Content.ToString();
if (!start.Equals(end))
ToggleButton(_endButton);
}
}
This behaviour caused by the fact that the mouse is getting captured. Try using hit testing to get an element located at the point where mouse was released: http://msdn.microsoft.com/en-us/library/ms608752.aspx
UPDATE
In example you have the following layout:
<Window x:Class="WpfApplication24.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">
<StackPanel>
<Button Content="b1" PreviewMouseLeftButtonUp="Button_PreviewMouseLeftButtonUp_1"/>
<Button Content="b2"/>
</StackPanel>
</Window>
On your PreviewMouseLeftButtonUp handler you should execute the following code:
private void Button_PreviewMouseLeftButtonUp_1(object sender, MouseButtonEventArgs e) {
var result = VisualTreeHelper.HitTest(this, e.GetPosition(this));
}
Note that you should use HitTest for element that is the common parent for both your buttons (in example - it is the MainWindow)
In the result.VisualHit property you can see the element located under cursor.
After that you can use VisualTreeHelper to check if it is the child of your Button, or try the following approach:
1)Create some flag attached property:
public static bool GetIsHitTestTarget(DependencyObject obj) {
return (bool)obj.GetValue(IsHitTestTargetProperty);
}
public static void SetIsHitTestTarget(DependencyObject obj, bool value) {
obj.SetValue(IsHitTestTargetProperty, value);
}
public static readonly DependencyProperty IsHitTestTargetProperty = DependencyProperty.RegisterAttached("IsHitTestTarget", typeof(bool), typeof(MainWindow), new PropertyMetadata(false));
2) Set it's value for the elements that you should find:
<Button Content="b1" local:MainWindow.IsHitTestTarget="true" PreviewMouseLeftButtonUp="Button_PreviewMouseLeftButtonUp_1"/>
<Button Content="b2" local:MainWindow.IsHitTestTarget="true"/>
3) Modify the PreviewLeftButtonUp callback:
private void Button_PreviewMouseLeftButtonUp_1(object sender, MouseButtonEventArgs e) {
DependencyObject result = null;
VisualTreeHelper.HitTest(this,
(o)=> {if(GetIsHitTestTarget(o)) {
result = o;
return HitTestFilterBehavior.Stop;
}
return HitTestFilterBehavior.Continue;
},
(res) => HitTestResultBehavior.Stop,
new PointHitTestParameters(e.GetPosition(this)));
}

UserControl tab focus not working

I got a class that extends UserControl
I have a few tabs in it, and I want to recognise when a tab is selected, so I have this:
this.GotFocus += new RoutedEventHandler(OnGotFocus);
private void OnGotFocus(object sender, System.EventArgs e)
{
if (DataContext != null)
{
((SomeViewModelClass)DataContext).SetActiveTab();
}
}
So my problem is: when I select a tab for the first time, the OnGotFocus mehod is called, however when I select some other tabs, and come back and select it a second time, it doesn't get called for some reason, any one know why?
Thanks in advance!
You are using WPF's Tab Control Right?
Why are you doing this.GotFocus....? what is this exactly in this case?
You should do something like this if you want GetFocus to be called when a Tab is selected.
XAML (sample Tabs)
<TabControl>
<TabItem x:Name="table1"></TabItem>
<TabItem x:Name="table2"></TabItem>
<TabItem></TabItem>
</TabControl>
Code Behind
//register event for each individual tab
table1.GotFocus += new RoutedEventHandler(table1_GotFocus);
table2.GotFocus += new RoutedEventHandler(table2_GotFocus);
private void table1_GotFocus(object sender, RoutedEventArgs e)
{
}
private void table2_GotFocus(object sender, RoutedEventArgs e)
{
}
let me know if I misunderstood you requirement

Categories