How to detect when the visual tree is destroyed? - c#

In a WPF application I have, I have a control that is central to the application. This control, called ArtView, is visible for the entire lifetime of the main window. It performs hardware accelerated rendering, and in order to avoid bogging down the UI thread, I set up an event loop in the OnLoaded handler for this control. Events such as mouse clicks, keyboard input, and scrolling are added to a queue that is then consumed by the event loop, but the problem I have is that I do not know how to end the event loop when the window is closed. When I close the window that contains the control, OnUnloaded does not fire, so what is the best way to disable the event loop when the control is no longer visible?
I am aware that I can do something like Window.GetWindow(this).Closing += OnWindowClosing; but that feels like a hack.

dymanoid's solution of subscribing to IsVisibleChanged works flawlessly, and provides a more satisfying solution than depending on the Window for the cleanup of my control.

Related

C# adding infinity loop in button click event and break it with another button click event

I tried to make a while (work){....}
inside button event called start
to do some stuff like label changing in the same form with random values
and I have another button called stop I want to make the work=false; so the while should be break
the problem is when I clicked start button and the form froze and did nothing
how I can do that like stay in the while loop and access all other events
As long as the loop runs, no events (like your other button's click) can be processed. This results in freezing the UI.
Better use a Timer instead of an infinite loop. The timer will not freeze the UI but call a Tick event at defined intervals and allow other events to be processed between two ticks. It is then easy for another button to stop this timer.
Since you have not mentioned any UI technology (is it WinForms, WPF, WebForms, MAUI, Xamarin, ...?) and not shown any code, it is difficult to give you example code.

Keydown event not firing in user control obj

I have a user control which is not declared in the designer. I have a button that I want to have create this user control when I click it - it should initialize the user control and insert it in the main UI.
However, it happens that the user control has a key press event on it, which is not firing.
Why does this happen?
I already tried to attach the event on the user control itself but it seems that it's not firing at all. Is there some kind of bug?
It is very hard to fix problems with code that you can't see, but in WPF, there are often reasons why Bubbling events like the KeyDown event don't fire. Occasionally certain controls may make use of these events and set them as handled internally, thereby stopping them from bubbling up any further.
The normal solution on these occasions is to use the related Tunneling events instead, which are raised before the Bubbling methods and not used internally by controls. So, while I can't guarantee that this will fix your problem, it is certainly worth trying to handle the UIElement.PreviewKeyUp event instead of the UIElement.KeyUp event.

Receiving touch events outside of custom control

I am developing a custom user control in WPF and trying to receive all touch events OUTSIDE of my control (so I can implement "cancel touches", where the user cancels an action by tapping somewhere else). Is there any good way to do this? Obviously, if I use TouchDown or other events I will only get notified of touches inside my control.
I tried receiving PreviewTouchDown events from Application.Current.MainWindow, but besides the fact it feels kind of dirty it also doesn't work that well - as soon as I capture those events, the SurfaceListBox inside my custom control stops working (it does not recognize touches anymore).
Is there a good way to solve this? Receiving simply ALL touch events would be sufficient as well, I can then check if they are inside my control.
In WPF, events travel the tree of elements. Events starting with "Preview" are the ones that travel up to bottom, meaning from the parent to the elements it contains. In your case, TouchDown event will travel from the control in which it originates and then it will bubble up towards the parents. PreviewTouchDown will travel in the opposite direction: from the parent towards the control.
Your idea of handling PreviewTouchDown event in the Application.Current.MainWindow is a good one and should handle all PreviewTouchDown events, if this is what you want. But in your case, if you want to check if the event originates in your custom control, you should catch all the TouchDown events in your MainWindow and check their Source property, like this:
private void CommonClickHandler(object sender, RoutedEventArgs e)
{
FrameworkElement feSource = e.Source as FrameworkElement;
if(feSource.Name == "MyCustomControlName")
{
//cancel whatever you want to cancel
e.Handled=true;
}
}
Do not catch the PreviewTouchDown event as this one will first pop in the MainWindow and just later will go all the way to your control.
This msdn link should give you more information: http://msdn.microsoft.com/en-us/library/ms742806.aspx

Remove original event behaviour of WinForm Control

I would like to remove the original event behavior of controls within a form (similar to design mode).
So, when the user clicks on the button, i only want to capture that event. I do not want the original button event to be fired. Is this somehow possible?
I am looking for a generic solution. So it should work with any form and any control within the form.
Reason: I wrote a form validation rules designer. It uses reflection to enumerate all form-types in the entry assembly. The user can then select a form type, the designer creates that form, enumerates the controls, and embedds the form in the designer panel.
clicking on a control, opens a formular designer panel, and the user can now create a formular for that control and saves the formular to a DB.
When the form is then opened in the normal "runtime" mode, it loads its validation formulars.
Events are not in fact disabled in the Winforms designer. The designer executes the constructor of the form through Reflection, everything in the InitializeComponent() method executes, including the event subscriptions. Wherever this might cause a problem, the controls check the DesignMode property (prevents a Timer from starting for example) or by custom designers. The form is displayed underneath a transparent layered window on top of which the selection rectangle and drag handles are painted. Which prevents issues with mouse clicks and keyboard focus.
You probably ought to look at this magazine article to get this working for you.
From what I understand from your question, I guess, you can still use the "DesignMode" property for this as well. In your event handling routine, you may want to bypass execution by checking on this property:
if (this.DesignMode) return;
as the first statement in your event handling block of code.

C# Manually triggered MouseDown fails to trigger MouseUp

Let's say I have a created a Form class and a CustomControl class.
On my Form I have two instances of the CustomControl, and a Panel.
Panel has 4 event handlers: MouseEnter (to give a different cursor), MouseLeave (to reset the cursor), MouseDown (to start the dragging thread), and MouseUp (to kill the dragging thread and do post-drag logic).
I can drag the Panel onto the CustomControl. When I do this, the code in Form detects what I have done and deletes Panel from Form.Controls, passes some meta-information to CustomControl, which then creates a Panel on itself.
Basically, it is a hand-over. The Panel object now belongs to the CustomControl.
(This is necessary. It's complicated to explain why, but imagine the custom control has something like scrollbars, and it's necessary for the Panel to belong to the CustomControl so that it will scroll with the CustomControl.)
Now, when I click down on the Panel in the CustomControl, the Panel's MouseDown is triggered, it gets deleted from CustomControl.Controls and sends some meta-information back to the Parent (the Form), which then re-creates the Panel as it was at the start - however already in a dragging state so that the user can re-position the Panel onto the second CustomControl, or perhaps put it back onto the Form. The function which creates the Panel when the Form is first initialised is exactly the same function which creates it now.
However, the Panel's MouseDown has not been triggered. The mouse is down, but the event is not firing because the mouse was already down when it was created. So, I manually call the MouseDown handler in the function in Form which accepts the meta-information from CustomControl.
Unfortunately, this only half-works. The MouseUp handler isn't firing. I can pick up the Panel off the CustomControl and drag it around on the Form as expected, but when I release the mouse, the Panel is stuck to the cursor.
I'm not really sure how to get around this?
An ideal solution would be for, when the meta-information is passed back to Form and the new Panel is created, the MouseDown event to somehow fire naturally as though the user had just clicked down on the Panel.
It sounds like you are creating a new instance of Panel when you move it from CustomControl to Form and back and loosing it's state.
You should either try to pass the actual instance owned by Form to CustomControl without creating a new one or you could capture the state of the Panel in another object which you can pass to the constructor when you create a new Panel so that it is in the same state as the one you were dragging?
It seems as though you are trying to manually fire mouse events to compensate for problems in your design.
Always better to give some example code if you can than lengthy textual explanations.
Look at this
Instant of custom control is disappear when click outside it
I have problem like you.
you shouldn't use a local variable for handling mouseEvent.
Try to use "Capture" function. It's work for me.

Categories

Resources