locked
How to override the onTouchUp in the user control which can be used to fire the event not only on this user control, but whole application RRS feed

  • Question

  •  I am a new to the C# and WPF. Right now, I want to override onTouchUp event in my user control. Then I can add user control in the references for reuse. The problem is each time I want to test this event on the application, the event only fire at area of user control, not whole screen. Anyone has solution for this?
    Monday, February 23, 2015 5:19 PM

Answers

  • Did you event bother to read my last reply? Then read it again.

    >>Maybe I am wrong  ... I want to my user control can react event not only the area of user control, but i also need fire event on the whole screen area.

    Yes, you are wrong. As I have already mentioned the OnTouchUp method of the UserControl will never get invoked when you touch an element outside of the UserControl because an event only travels between the source element and the handler(s).

    You should handle the TouchUp event of the top-level window if you want to detect when a TouchUp event occurs somewhere on the "whole screen area".

    If you for some reason want to UserControl to react to events that happens outside it you could get a reference to the window and handle its OnTouchUp event in the UserControl. Here is an example:

    public partial class UserControl1 : UserControl
      {
        public UserControl1() {
          InitializeComponent();
          this.Loaded += UserControl1_Loaded;
        }
    
        void UserControl1_Loaded(object sender, RoutedEventArgs e) {
          Window win = Window.GetWindow(this);
    
          win.TouchUp += (ss, ee) =>
          {
            MyTouchUpHandler(ss, ee);
          };
        }
    
        protected override void OnTouchUp(TouchEventArgs e) {
          base.OnTouchUp(e);
    
          MyTouchUpHandler(this, e);
          e.Handled = true;
        }
    
        private void MyTouchUpHandler(object sender, TouchEventArgs e) {
          //do your thing here....
          
        }
      }

    The MyTouchUpHandler will get called whenever a TouchUp occurs in the UserControl or in the parent window.

    Hope that helps.

    Please remember to mark helpful posts as answer to close your threads and please don't ask the same question twice. If you have a new question you should start a new thread.

    Edit: Andy: If I understand him correctly he wants to handle the TouchUp of the window in the UserControl. How are you supposed to handle an event that occurs in the window or any of child controls in the user control if you don't hook up an event handler to the window's event? A tunneling event tunnels down to the source but it will not tunnerling down to the UserControl if you touched an element that is located outside the same user UserControl.



    • Edited by Magnus (MM8)MVP Tuesday, February 24, 2015 11:05 AM
    • Proposed as answer by Magnus (MM8)MVP Tuesday, February 24, 2015 8:44 PM
    • Marked as answer by mozart0000 Tuesday, February 24, 2015 11:22 PM
    Tuesday, February 24, 2015 9:28 AM

All replies

  • You cannot just add a UserControl to a window and expect its OnTouchUp method to get invoked when a TouchUp event occurs outside of the user control. That is not how routed events work.

    The OnTouchUp method of the UserControl will only be invoked when a TouchUp event occurs from within the UserControl.

    The event will indeed bubble up to the parent elements of the UserControl and you could for example handle the event in the parent window:

    <Window x:Class="WpfApplicationSlider.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" TouchUp="Window_TouchUp">


    The OnTouchUp method of the UserControl will however never get invoked when you touch an element outside of the UserControl because an event only travels between the source element and the handler(s). This is how routed events work.

    If you want a "global" TouchUp event handler you should override the OnTouchUp of the top-level window:

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            protected override void OnTouchUp(TouchEventArgs e)
            {
                base.OnTouchUp(e);
      //do your thing...
            }
    
        }
    


    If you want to be able to reuse the functionality across all of your windows in case you have several you could for example create an abstract window class and make all your windows inherit from this one:

    namespace WpfApplication1
    {
        public abstract class BaseWindow : System.Windows.Window
        {
            protected override void OnTouchUp(System.Windows.Input.TouchEventArgs e)
            {
                base.OnTouchUp(e);
                //do your thing...
            }
        }
    }



    MainWindow:

    public partial class MainWindow : BaseWindow
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
        }
    


    
    <local:BaseWindow x:Class="WpfApplicationSlider.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
    ...
    </local:BaseWindow>
    

    Hope that helps.

    Please remember to mark helpful posts as answer to close your threads and please start a new thread if you have a new question.


    Monday, February 23, 2015 6:26 PM
  • I'm rather confused by the question.

    There are bubbling and tunnelling routed events though.

    If you mean you want to handle the usercontrol's event at window level then the bubbling event Magnus has mentioned is the one to go with.

    https://msdn.microsoft.com/en-us/library/system.windows.uielement.touchup(v=vs.110).aspx

    If you instead wanted to handle touchup in the usercontrol that happens outside of it then the tunnelling version is the one to go for and that is PreviewTouchUp.

    https://msdn.microsoft.com/en-us/library/system.windows.uielement.previewtouchup(v=vs.110).aspx

    You could handle that in the usercontrol and it'll get fired for touchup from outside it or override OnPreviewTouchUp.

    I'm particularly confused by what you mean from "adding a usercontrol in references for reuse".


    Hope that helps.
    Recent Technet articles: Property List Editing;   Dynamic XAML

    Monday, February 23, 2015 8:56 PM
  • Maybe I am wrong, basically, I need a user control(maybe not) can be reused in any of application layer. which I don't need override event again. So I override the onTouchUp event, only add message.show("test"). Then I add this user control into reference of my application. after I add this user control in my application, only I touch up the area of user control, the message "test" will pop up, if touch out of that area, there is no reaction. I want to my user control can react event not only the area of user control, but i also need fire event on the whole screen area.
    Tuesday, February 24, 2015 4:40 AM
  • I thought I already covered that.

    If you instead wanted to handle touchup in the usercontrol that happens outside of it then the tunnelling version is the one to go for and that is PreviewTouchUp.

    https://msdn.microsoft.com/en-us/library/system.windows.uielement.previewtouchup(v=vs.110).aspx

    You could handle that in the usercontrol and it'll get fired for touchup from outside it or override OnPreviewTouchUp.

    There's a tree structure to controls in a xaml view.

    It's called the visual tree.

    You stick some usercontrol inside a window then it's down the visual tree.

    That means you want to look for a tunneling routed event.

    You could read more about that here:

    https://msdn.microsoft.com/en-us/library/ms742806%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396



    Hope that helps.
    Recent Technet articles: Property List Editing;   Dynamic XAML

    Tuesday, February 24, 2015 7:59 AM
  • Did you event bother to read my last reply? Then read it again.

    >>Maybe I am wrong  ... I want to my user control can react event not only the area of user control, but i also need fire event on the whole screen area.

    Yes, you are wrong. As I have already mentioned the OnTouchUp method of the UserControl will never get invoked when you touch an element outside of the UserControl because an event only travels between the source element and the handler(s).

    You should handle the TouchUp event of the top-level window if you want to detect when a TouchUp event occurs somewhere on the "whole screen area".

    If you for some reason want to UserControl to react to events that happens outside it you could get a reference to the window and handle its OnTouchUp event in the UserControl. Here is an example:

    public partial class UserControl1 : UserControl
      {
        public UserControl1() {
          InitializeComponent();
          this.Loaded += UserControl1_Loaded;
        }
    
        void UserControl1_Loaded(object sender, RoutedEventArgs e) {
          Window win = Window.GetWindow(this);
    
          win.TouchUp += (ss, ee) =>
          {
            MyTouchUpHandler(ss, ee);
          };
        }
    
        protected override void OnTouchUp(TouchEventArgs e) {
          base.OnTouchUp(e);
    
          MyTouchUpHandler(this, e);
          e.Handled = true;
        }
    
        private void MyTouchUpHandler(object sender, TouchEventArgs e) {
          //do your thing here....
          
        }
      }

    The MyTouchUpHandler will get called whenever a TouchUp occurs in the UserControl or in the parent window.

    Hope that helps.

    Please remember to mark helpful posts as answer to close your threads and please don't ask the same question twice. If you have a new question you should start a new thread.

    Edit: Andy: If I understand him correctly he wants to handle the TouchUp of the window in the UserControl. How are you supposed to handle an event that occurs in the window or any of child controls in the user control if you don't hook up an event handler to the window's event? A tunneling event tunnels down to the source but it will not tunnerling down to the UserControl if you touched an element that is located outside the same user UserControl.



    • Edited by Magnus (MM8)MVP Tuesday, February 24, 2015 11:05 AM
    • Proposed as answer by Magnus (MM8)MVP Tuesday, February 24, 2015 8:44 PM
    • Marked as answer by mozart0000 Tuesday, February 24, 2015 11:22 PM
    Tuesday, February 24, 2015 9:28 AM
  • It seems an odd sort of a requirement.

    But the reason tunneling events exist is so you don't need to go get a reference to any parent container.

    Why would you recommend obtaining a reference and subscribing to an event from that rather than using the tunneling event?


    Hope that helps.
    Recent Technet articles: Property List Editing;   Dynamic XAML

    Tuesday, February 24, 2015 9:41 AM
  • Could you give some code example about my scenario? For example, you have a user control which you override the onPreviewTouchUp, how to use tunneling event affect whole screen, not only for that user control ?  
    Tuesday, February 24, 2015 4:21 PM
  • Could you explain how it work? I use your solution in my project well, hope I can understand fully. Thanks
    Tuesday, February 24, 2015 4:46 PM
  • Could you explain how it work? I use your solution in my project well, hope I can understand fully. Thanks

    I believe I have already explained it pretty well. You get a reference to the parent window's (using the Window.GetWindow method) OnTouchUp event and handle this one in the UserControl.  You have to do this because when you touch an element that is located outside of the UserControl the UserControl's OnTouchUp event will not be raised but the window's will. By hooking up an event handler to the window's event you are able to execute some code that resides in the UserControl when this happens.

    Since my solution helped you, please remember to close the thread by marking helpful posts as answer.

    Tuesday, February 24, 2015 8:44 PM
  • Based on your solution, in the application layer, once i add  user Control tag into XAML, error jump up, can not load the designer.


    System.NullReferenceException
    Object reference not set to an instance of an object.
       at serverControl.UserControl1.UserControl1_Loaded(Object sender, RoutedEventArgs e) in C:\Users\zhehuang\OneDrive for Business 2\2015Thiese File\serverControl_v7\serverControl\UserControl1.xaml.cs:line 86
       at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
       at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
       at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
       at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
       at System.Windows.BroadcastEventHelper.BroadcastEvent(DependencyObject root, RoutedEvent routedEvent)
       at System.Windows.BroadcastEventHelper.BroadcastLoadedEvent(Object root)
       at MS.Internal.LoadedOrUnloadedOperation.DoWork()
       at System.Windows.Media.MediaContext.FireLoadedPendingCallbacks()
       at System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks()
       at System.Windows.Media.MediaContext.RenderMessageHandlerCore(Object resizedCompositionTarget)
       at System.Windows.Media.MediaContext.RenderMessageHandler(Object resizedCompositionTarget)
       at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
       at MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(Object source, Delegate method, Object args, Int32 numArgs, Delegate catchHandler)
    



    • Edited by mozart0000 Wednesday, February 25, 2015 3:07 AM
    Wednesday, February 25, 2015 3:07 AM