简体   繁体   中英

System.InvalidOperationException in C# WPF

I want to move a rectangle in WPF application using the following code. However, I am getting the following error:

System.InvalidOperationException: Cannot use a DependencyObject that belongs to a different thread I looked at other problems in stackoverflow but nothing worked.

public partial class MainWindow : Window
{
    private Rectangle rect;
    int count = 1;
    Timer timer;

    public MainWindow()
    {
        InitializeComponent();
        Rectangle movedRectangle = new Rectangle();
        movedRectangle.Width = 200;
        movedRectangle.Height = 50;
        movedRectangle.Fill = Brushes.Blue;
        movedRectangle.Opacity = 0.5;
        TranslateTransform translateTransform1 = new TranslateTransform(50, 20);
        movedRectangle.RenderTransform = translateTransform1;

        this.can.Children.Add(movedRectangle);
        this.rect = movedRectangle;

        timer = new Timer(500);
        timer.Elapsed += OnTimedEvent;
        timer.Enabled = true;
    }

    private void OnTimedEvent(Object source, ElapsedEventArgs e)
    {
        count++;
        TranslateTransform translateTransform1 = new TranslateTransform(50 + count * 2, 20);
        this.rect.Dispatcher.Invoke(new Action(()=>
            rect.RenderTransform = translateTransform1));

        //this.can.UpdateLayout();
        this.can.Dispatcher.Invoke(new Action(()=>
            this.can.UpdateLayout()
            ));

    }

You are constructing a TranslateTransform (which is a DependencyObject ) outside the UI thread. Easy fix:

        this.rect.Dispatcher.Invoke(new Action(
            () =>
            {
                TranslateTransform translateTransform1 = new TranslateTransform(50 + count * 2, 20);
                rect.RenderTransform = translateTransform1;
            }));

Arguably a better fix: use a DispatcherTimer instead and get rid of all your Dispatcher.Invoke calls.

I would suggest you to use DispatcherTimer than a normal timer.

Please see the below solution. enjoy.

Note: for DispatcherTimer you will need to add the assembly reference for System.Windows.Threading

public partial class MainWindow : Window
{
    private Rectangle rect;
    int count = 1;
    private DispatcherTimer timer = null;

    public MainWindow()
    {
        InitializeComponent();
        Rectangle movedRectangle = new Rectangle();
        movedRectangle.Width = 200;
        movedRectangle.Height = 50;
        movedRectangle.Fill = Brushes.Blue;
        movedRectangle.Opacity = 0.5;
        TranslateTransform translateTransform1 = new TranslateTransform(50, 20);
        movedRectangle.RenderTransform = translateTransform1;

        this.can.Children.Add(movedRectangle);
        this.rect = movedRectangle;

        timer = new DispatcherTimer();
        timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
        timer.Tick += timer_Tick;
        timer.Start();
        timer.IsEnabled = true;

    }

    void timer_Tick(object sender, EventArgs e)
    {
        count++;
        TranslateTransform translateTransform1 = new TranslateTransform(50 + count * 2, 20);
        Dispatcher.BeginInvoke(new Action<TranslateTransform>(delegate(TranslateTransform t1)
            {
                rect.RenderTransform = t1;
                this.can.UpdateLayout();
            }), System.Windows.Threading.DispatcherPriority.Render, translateTransform1);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM