private void TaskStateChangingHandler(object sender, PropertyUpdateEventArgs <TaskState> e) { var er = new EventRecord(nameof(TestTask.StateChanging), sender, e); lock (EventRecords) { EventRecords.Add(er); } }
/// <summary> /// Sets a property on the object passed in to the value passed in. This method /// invokes itself on the GUI thread if the property is being invoked on a GUI /// object. /// </summary> private void SetProperty(object sender, PropertyUpdateEventArgs args) { try { // If the target is a control that has been disposed then we don't // try to update its properties. This can happen if the control is // on a form that has been closed while the transition is running... if (IsDisposed(args.Target)) { return; } if (args.Target is ISynchronizeInvoke invokeTarget && invokeTarget.InvokeRequired) { // There is some history behind the next two lines, which is worth // going through to understand why they are the way they are. // Initially we used BeginInvoke without the subsequent WaitOne for // the result. A transition could involve a large number of updates // to a property, and as this call was asynchronous it would send a // large number of updates to the UI thread. These would queue up at // the GUI thread and mean that the UI could be some way behind where // the transition was. // The line was then changed to the blocking Invoke call instead. This // meant that the transition only proceded at the pace that the GUI // could process it, and the UI was not overloaded with "old" updates. // However, in some circumstances Invoke could block and lock up the // Transitions background thread. In particular, this can happen if the // control that we are trying to update is in the process of being // disposed - for example, it is on a form that is being closed. See // here for details: // http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/7d2c941a-0016-431a-abba-67c5d5dac6a5 // To solve this, we use a combination of the two earlier approaches. // We use BeginInvoke as this does not block and lock up, even if the // underlying object is being disposed. But we do want to wait to give // the UI a chance to process the update. So what we do is to do the // asynchronous BeginInvoke, but then wait (with a short timeout) for // it to complete. var asyncResult = invokeTarget.BeginInvoke(new EventHandler <PropertyUpdateEventArgs>(SetProperty), new object[] { sender, args }); asyncResult.AsyncWaitHandle.WaitOne(50); } else { // We are on the correct thread, so we update the property... args.PropertyInfo.SetValue(args.Target, args.Value, null); } }
/// <summary> /// Called when the transition timer ticks. /// </summary> internal void OnTimer() { // When the timer ticks we: // a. Find the elapsed time since the transition started. // b. Work out the percentage movement for the properties we're managing. // c. Find the actual values of each property, and set them. // a. var elapsedTime = (int)_stopwatch.ElapsedMilliseconds; // b. _method.OnTimer(elapsedTime, out double percentage, out bool completed); // We take a copy of the list of properties we are transitioning, as // they can be changed by another thread while this method is running... var listTransitionedProperties = new List <TransitionedPropertyInfo>(); lock (_lock) { foreach (TransitionedPropertyInfo info in TransitionedProperties) { listTransitionedProperties.Add(info.Copy()); } } // c. foreach (TransitionedPropertyInfo info in listTransitionedProperties) { // We get the current value for this property... object value = info.ManagedType.GetIntermediateValue(info.StartValue, info.EndValue, percentage); // We set it... var args = new PropertyUpdateEventArgs(info.Target, info.PropertyInfo, value); SetProperty(this, args); } // Has the transition completed? if (completed) { // We stop the stopwatch and the timer... _stopwatch.Stop(); // We raise an event to notify any observers that the transition has completed... Utility.RaiseEvent(TransitionCompleted, this, EventArgs.Empty); } }
private void HandleArrayRecived(object sender, PropertyUpdateEventArgs <object[]> e) { Capture.Add(e.Record()); }
private void HandleFloatRecived(object sender, PropertyUpdateEventArgs <float> e) { Capture.Add(e.Record()); }
private void HandleStringRecived(object sender, PropertyUpdateEventArgs <string> e) { Capture.Add(e.Record()); }
private void HandleVectorRecived(object sender, PropertyUpdateEventArgs <Vector> e) { Capture.Add(e.Record()); }
public static RecordedPropertyUpdate <T> Record <T>(this PropertyUpdateEventArgs <T> args) { return(new RecordedPropertyUpdate <T>(args.Property.Index, args.Value)); }
private void HandleArrayRecived (object sender, PropertyUpdateEventArgs<object[]> e) { Capture.Add(e.Record()); }
private void HandleFloatRecived (object sender, PropertyUpdateEventArgs<float> e) { Capture.Add(e.Record()); }
private void HandleStringRecived (object sender, PropertyUpdateEventArgs<string> e) { Capture.Add(e.Record()); }
private void HandleVectorRecived (object sender, PropertyUpdateEventArgs<Vector> e) { Capture.Add(e.Record()); }
private void HandleInt64Received(object sender, PropertyUpdateEventArgs <long> e) { Capture.Add(e.Record()); }