0

I tried setting the SynchronizingObject like this:

timer.SynchronizingObject = this;//The Window

but VS told me I need an explicit cast. So I did that and the error went away.

timer.SynchronizingObject = (ISynchronizeInvoke)this;

Until I ran it and got a

System.InvalidCastException Unable to cast object of type 'Test.Window1' to type 'System.ComponentModel.ISynchronizeInvoke'.

So how do I pass the Window's context to the Timer?

The requirement is for the timer to be a System.Timers.Timer.

13
  • Why would you not use a DispatcherTimer? Commented Nov 23 at 19:26
  • 1
    stackoverflow.com/q/50161741/1136211 Commented Nov 23 at 19:27
  • @Clemens Thanks. As you posted your comment I added the last line to the question. That's a requirement. It will be used for other things as well. And in any case I would like to know how to use it. Commented Nov 23 at 19:27
  • Next question would be, why would you not call Dispatcher.Invoke from the Timer callback. Commented Nov 23 at 19:28
  • 1
    Dispatcher.Invoke can return a result to the calling thread: learn.microsoft.com/de-de/dotnet/api/… Commented Nov 23 at 19:38

1 Answer 1

2

You need to create an ISynchronizeInvoke for the dispatcher. Example.

    public class SynchronizeInvoke : ISynchronizeInvoke
    {
        private readonly System.Windows.Threading.Dispatcher dispatcher;

        public SynchronizeInvoke(System.Windows.Threading.DispatcherObject dObj)
            : this(dObj.Dispatcher)
        { }

        public SynchronizeInvoke()
            : this(Application.Current.Dispatcher)
        { }

        public SynchronizeInvoke(System.Windows.Threading.Dispatcher dispatcher)
        {
            this.dispatcher = dispatcher;
        }

        public bool InvokeRequired => !dispatcher.CheckAccess();

        private class AsyncResult : IAsyncResult
        {
            public readonly System.Windows.Threading.DispatcherOperation operation;
            public readonly IAsyncResult asyncResult;

            public AsyncResult(System.Windows.Threading.DispatcherOperation operation)
            {
                this.operation = operation;
                asyncResult = operation.Task;
            }

            public object? AsyncState => asyncResult.AsyncState;

            public WaitHandle AsyncWaitHandle => asyncResult.AsyncWaitHandle;

            public bool CompletedSynchronously => asyncResult.CompletedSynchronously;

            public bool IsCompleted => asyncResult.IsCompleted;
        }

        public IAsyncResult BeginInvoke(Delegate method, object?[]? args) => new AsyncResult(dispatcher.BeginInvoke(method, args));

        public object? EndInvoke(IAsyncResult result)
        {
            AsyncResult asyncResult = (AsyncResult)result;
            asyncResult.operation.Task.Wait();
            return asyncResult.operation.Result;
        }

        public object? Invoke(Delegate method, object?[]? args)
            => dispatcher.Invoke(method, args);
    }

Usage:

timer.SynchronizingObject = new SynchronizeInvoke();
// or
timer.SynchronizingObject = new SynchronizeInvoke(this.Dispatcher);
// or
timer.SynchronizingObject = new SynchronizeInvoke(this);

P.S. You can simplify the implementation of SynchronizeInvoke by using undocumented behavior. In practice, this implementation works flawlessly.

    public class SynchronizeInvoke : ISynchronizeInvoke
    {
        private readonly System.Windows.Threading.Dispatcher dispatcher;

        public SynchronizeInvoke(System.Windows.Threading.DispatcherObject dObj)
            : this(dObj.Dispatcher)
        { }

        public SynchronizeInvoke()
            : this(Application.Current.Dispatcher)
        { }

        public SynchronizeInvoke(System.Windows.Threading.Dispatcher dispatcher)
        {
            this.dispatcher = dispatcher;
        }

        public bool InvokeRequired => !dispatcher.CheckAccess();

        public IAsyncResult BeginInvoke(Delegate method, object?[]? args) => dispatcher.BeginInvoke(method, args).Task; 

        public object? EndInvoke(IAsyncResult result)
        {
            Task<object> task = (Task<object>)result;
            task.Wait();
            return task.Result;
        }

        public object? Invoke(Delegate method, object?[]? args)
            => dispatcher.Invoke(method, args);
    }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.