0

I'm just playing around with WPF and MVVM, and I have made a simple app that displays a Rectangle that changes color whenever Network availability changes.

But when that happens, I get this error: Cannot use a DependencyObject that belongs to a different thread than its parent Freezable.

Code

XAML

<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="400" Width="600">
<DockPanel LastChildFill="True">
    <Rectangle x:Name="networkStatusRectangle" Width="200" Height="200" Fill="{Binding NetworkStatusColor}" />
</DockPanel>
</Window>

Code-behind

using System.Windows; using WpfApplication1.ViewModels;

namespace WpfApplication1
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            DataContext = new NetworkViewModel();
        }
    }
}

ViewModel

using System.ComponentModel;
using System.Net.NetworkInformation;
using System.Windows.Media;

namespace WpfApplication1.ViewModels
{
    public class NetworkViewModel : INotifyPropertyChanged
    {
        private Brush _NetworkStatusColor;

        public Brush NetworkStatusColor
        {
            get { return _NetworkStatusColor; }
            set
            {
                _NetworkStatusColor = value;
                NotifyOfPropertyChange("NetworkStatusColor");
            }
        }

        public NetworkViewModel()
        {
            NetworkChange.NetworkAvailabilityChanged += new NetworkAvailabilityChangedEventHandler(NetworkChange_NetworkAvailabilityChanged);
        }

        protected void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e)
        {
            if (e.IsAvailable)
            {
                this.NetworkStatusColor = new SolidColorBrush(Colors.Green);
            }
            else
            {
                this.NetworkStatusColor = new SolidColorBrush(Colors.Red);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        public void NotifyOfPropertyChange(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

I assume that I should change the NetworkStatusColor property by invoking something?

2 Answers 2

3

You assume correctly. It's the Dispatcher class and the .Invoke method you want to take a look at.

Something a bit like this:

if (this.Dispatcher.Thread != Thread.CurrentThread)
{
    this.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(...your method...), any, params, here);
    return
}

There's an MSDN article here with some more info.

Sign up to request clarification or add additional context in comments.

4 Comments

Cool. So should you always have your ViewModels derive from the DispatcherObject class?
@MartinHN: No, sorry. I wouldn't have my viewmodel inherit from DispatcherObject. That code is a if you are running from within a view/window class. If you want to do this from within a viewmodel you can just pass the Dispatcher from the view when the viewmodel is bound (or created). Or you can use Dispatcher.CurrentDispatcher if your viewmodels are created on the main thread. Take a look at this question for some other suggestions for getting access to the window's dispatcher from the viewmodel: stackoverflow.com/questions/2354438/…
Although, if you are going to use DependencyProperties on your view model, you will end up inheriting from DispatcherObject indirectly in the hierarchy anyway (it's a parent class of DependencyObject), so I suppose it depends on what how you're doing things.
Ok, I think I will go for a generic helper, inspired by the MVVM Light Toolkit: mvvmlight.codeplex.com/sourcecontrol/network/…
0

With MVVM you have a couple of options when dealing with dispatching. Either you can send some kind of message to your view to have it invoke the operation for you, or you can create some kind of abstract dispatcher service that you are able to easily mock.

Take a look at the MVVM Light toolkit, as it includes a simple dispatcher-service you can use/copy.

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.