views:

233

answers:

2

Hello All,

I may be waaaay off, or else really close. Either way, I'm currently SOL. :)

I want to be able to use an extension method to set properties on a class, but that class may (or may not) be updated on a non-UI thread, and derives from a class the enforces updates to be on the UI thread (which implements INotifyPropertyChanged, etc).

I have a class defined something like this:

public class ClassToUpdate : UIObservableItem
{
    private readonly Dispatcher mDispatcher = Dispatcher.CurrentDispatcher;
    private Boolean mPropertyToUpdate = false;

    public ClassToUpdate() : base()
    {
    }

    public Dispatcher Dispatcher
    {
        get { return mDispatcher; }
    }

    public Boolean PropertyToUpdate
    {
        get { return mPropertyToUpdate; }
        set { SetValue("PropertyToUpdate", ref mPropertyToUpdate, value; }
    }
}

I have an extension method class defined something like this:

static class ExtensionMethods
{
    public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList,
                                                  Boolean newValue)
    {
       ClassToUpdate firstClass = sourceList.FirstOrDefault() as ClassToUpdate;

       if (firstClass.Dispatcher.Thread.ManagedThreadId != 
           System.Threading.Thread.CurrentThread.ManagedThreadId)
        {
            // WHAT GOES HERE?
        }
        else
        {
            foreach (var classToUpdate in sourceList)
            {
               (classToUpdate as ClassToUpdate ).PropertyToUpdate = newValue;
               yield return classToUpdate;
            }
        }
    }
}

Obviously, I'm looking for the "WHAT GOES HERE" in the extension method.

Thanks, wTs

+1  A: 

// WHAT GOES HERE?

mDispatcher.Invoke(new Action(() => sourceList.SetMyProperty(newValue)));

As a side note, if you need to check whether the current thread has access to the UI, you don't need to compare thread ids. You just need to call the CheckAccess method :

if (firstClass.Dispatcher.CheckAccess())
{
    ...
}

For some reason, this methods is hidden in Intellisense... no idea why


UPDATE

OK, my answer wasn't totally accurate... you still need to yield return each item of the collection, and Invoke doesn't do it. Here's another version of your method :

public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList, bool newValue)
    where T : ClassToUpdate
{
    Action<T> setProperty = t => t.PropertyToUpdate = newValue;

    foreach(var t in sourceList)
    {
        if (t.Dispatcher.CheckAccess())
        {
            action(t);
        }
        else
        {
            t.Dispatcher.Invoke(action, new object[] { t });
        }
    }
}

Note that I added a constaint on the generic type parameter, and I removed the casts (the way you were doing it, generics didn't bring any benefit)

Thomas Levesque
I'm not sure if this is working. For some reason, breakpoints and tracepoints aren't hit in the function after calling Invoke. I would expect to hit a breakpoint at the first line of the function after Invoke is called.
Wonko the Sane
Also, does the Invoke have the same effect as the other loop, which creates an IEnumerable via a yield return? The object returned from the Invoke is null.
Wonko the Sane
See my updated answer
Thomas Levesque
Thank you! I was able to solve it using your example. Oh, and I also had a constraint of my real class - I just didn't put it in the quick example above.
Wonko the Sane
A: 

Just to clean up a couple of small typos (and hopefully not add my own) in the above example, here is a final solution to the example.

public static IEnumerable<T> SetMyProperty<T>(this IEnumerable<T> sourceList, 
    bool newValue) where T : ClassToUpdate
{
    Action<T> setProperty = t => t.PropertyToUpdate = newValue;

    foreach(var t in sourceList)
    {
        if (t.Dispatcher.CheckAccess())
        {
            setProperty(t);
        }
        else
        {
            t.Dispatcher.Invoke(setProperty, new object[] { t });
        }

        yield return t;
    }
}
Wonko the Sane