locked
WPF block the timer event in WinForm application RRS feed

  • Question

  • I have encountered a very curious problem - the timer event will not be triggered if I launched a WPF window which contains a rotating image even then I close it, below is the test application which could duplicate my problem

    The project named 'Duplicate' is the WinForm application, click the 'Show form' button on the form will launch the WPF window (implemented in the project 'WpfApplicationForm', then you could close this WPF window by clicking the 'Close' button, you could notified that the idleTimer_Tick will not be entered

    This is the source code

    Thursday, August 25, 2011 2:17 AM

Answers

  • Hi Carlos_zxl,

    Closing the window won't remove the timeline you started.

    Setting wnd to null only make the window available to GC and won't make any difference before GC occurs.

    If you removed the storyboard, then the issue won't occur.

        <Style x:Key="SpinBusy" TargetType="{x:Type Image}">
          <Setter Property="RenderTransform">
            <Setter.Value>
              <RotateTransform Angle="0" CenterX="16" CenterY="16" />
            </Setter.Value>
          </Setter>
          <Style.Triggers>
            <Trigger Property="IsEnabled" Value="true">
              <Trigger.EnterActions>
                <BeginStoryboard Name="MyBeginStoryBoard">
                  <Storyboard>
                    <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" 
                      From="0" 
                      To="360" 
                      Duration="0:0:5"
                             RepeatBehavior="Forever"
                      />
                  </Storyboard>
                </BeginStoryboard>
              </Trigger.EnterActions>
            </Trigger>
            <EventTrigger RoutedEvent="Unloaded">
                <RemoveStoryboard BeginStoryboardName="MyBeginStoryBoard"/>
            </EventTrigger>
          </Style.Triggers>
        </Style>
    

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Carlos Liu Wednesday, August 31, 2011 5:02 AM
    Monday, August 29, 2011 7:25 AM

All replies

  • Try to set reference to wpf window to null to allow it for garbage collection
    Thursday, August 25, 2011 8:25 AM
  • Dan,

     

    Thanks for your reply and it really solves the issue in my test application. But I found that my problem is a little bit different with the test application and I have created another test application, the difference is that the Show/close dialog in called be delegate, would you please help me to get it out, thanks in advance!

     

    Source code here

    Friday, August 26, 2011 9:00 AM
  • Hi Carlos_zxl,

    Call GC.Collect to gc the wpf window.

        public void Close()
        {
          if (wnd != null)
          {
            App.Current.Dispatcher.Invoke(new Method_0Params(wnd.Close), null);
            wnd = null;
            
            //--Add This Line--
            App.Current.Dispatcher.Invoke(new Action(() =>
            {
              GC.Collect();
            }), DispatcherPriority.Background);
            //-----------------
    
          }
        }
    

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, August 29, 2011 3:02 AM
  • Hi Min Zhu

    Thanks for your reply! Yes it solves my problem, but I still do not quite understand why the timer event is not triggered if the WPF window is not cleaned by GC?

     

    Monday, August 29, 2011 5:09 AM
  • Hi Carlos_zxl,

    This is become the Application.Idle fires too frequently.

    In its event handler, it stop the Timer and re-start it. Assume the Timer's Interval is 1 second. If another Application.Idle happens in that 1 second, then it will stop the Timer and Timer.Tick will never get the change to fire.

    If that's not your designed behavior, try removing Timer.Stop from the event handler of Application.Idle.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, August 29, 2011 5:20 AM
  • But why using GC after the WPF window is closed will solve the issue?
    Monday, August 29, 2011 5:57 AM
  • Hi Carlos_zxl,

    Because the Storyboard in WPF window makes the application goes "busy" and "idle" frequently which makes the Application.Idle fires frequently (less than the Timer's interval) and causes the problem. After the WPF window is gc-ed, the Application.Idle doesn't fire that frequent so you don't see the problem. But you can still reproduce the same problem if you continuesly move the mouse over the ListBox.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, August 29, 2011 6:09 AM
  • It seems that the WPF window still has influences on the WinForm application even it was closed and set to be null (without GC), does this make sense?

    App.Current.Dispatcher.Invoke(new Method_0Params(wnd.Close), null);
        wnd = null
    Monday, August 29, 2011 6:34 AM
  • Hi Carlos_zxl,

    Closing the window won't remove the timeline you started.

    Setting wnd to null only make the window available to GC and won't make any difference before GC occurs.

    If you removed the storyboard, then the issue won't occur.

        <Style x:Key="SpinBusy" TargetType="{x:Type Image}">
          <Setter Property="RenderTransform">
            <Setter.Value>
              <RotateTransform Angle="0" CenterX="16" CenterY="16" />
            </Setter.Value>
          </Setter>
          <Style.Triggers>
            <Trigger Property="IsEnabled" Value="true">
              <Trigger.EnterActions>
                <BeginStoryboard Name="MyBeginStoryBoard">
                  <Storyboard>
                    <DoubleAnimation Storyboard.TargetProperty="RenderTransform.Angle" 
                      From="0" 
                      To="360" 
                      Duration="0:0:5"
                             RepeatBehavior="Forever"
                      />
                  </Storyboard>
                </BeginStoryboard>
              </Trigger.EnterActions>
            </Trigger>
            <EventTrigger RoutedEvent="Unloaded">
                <RemoveStoryboard BeginStoryboardName="MyBeginStoryBoard"/>
            </EventTrigger>
          </Style.Triggers>
        </Style>
    

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Carlos Liu Wednesday, August 31, 2011 5:02 AM
    Monday, August 29, 2011 7:25 AM
  • Hi Carlos_zxl,

    Just checking in to see if the information was helpful. Please let us know if you would like further assistance.

    Have a great day!


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, August 31, 2011 2:06 AM
  • To be honest, I have never touched with WPF before, so it is a little bit hard for me to understand what StoryBoard and other concepts means. Let me repeat my understanding, if I am wrong please correct me

    When the WPF window is first shown, the image ProgressCircle.png will be rotated because the animation is triggered, and this cause the Application.Idle fires too frequently, and the animation won't stop even if the window is closed because the the RepeatBehavior of the animation is set as "Forever"

    I am still a little bit confused about your following comments, would you please explain it more detailed, is the timeline here means the duration of the rotate animation? Why it is not stopped when the window is closed? is this a defect of WPF or is this my code mistake?

    Closing the window won't remove the timeline you started.

    Thanks for your kind help!

    Wednesday, August 31, 2011 3:16 AM
  • Hi Carlos_zxl,

    Timeline here refers to the animation. The animation is a subclass of System.Windows.Media.Animation.Timeline. Sorry for the confusion.

    Opening/Closing a window doesn't have much to do with the animations.

    Based on my understanding, animation is a mechanism that changes the value of a DependencyObject's DependencyProeprty when the animationtimer ticks.

    Closing a window closes the window on your screen, releases the unmanaged resources. But the System.Windows.Window object is still there, alive. And as long as it is not garbage collected, the animation still ticks.

    Let's see a simple example.

          Window win = new Window();
          win.Width = 200;
          DoubleAnimation doubleAnimation = new DoubleAnimation(500, new Duration(TimeSpan.FromSeconds(5)));
          doubleAnimation.CurrentTimeInvalidated += (o, e) => Debug.WriteLine(win.Width);
          win.BeginAnimation(Window.WidthProperty,doubleAnimation);
    

    It demonstrates we don't need to "Show" the window and the animation still runs. They are not related.

    Best regards,


    Min Zhu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, August 31, 2011 4:06 AM
  • Great thanks for your help!
    Wednesday, August 31, 2011 5:02 AM