Search code examples
wpfvisifire

The calling thread must be STA, because many UI components require this


I found on website all about the answer to that question, the code changes into the following format is no longer an error, but the delegate does not execute the statement inside a, What's wrong? Can anybody help me?My program use multimedia timer every 2 seconds to draw a curve point, draw the curve with Visifire

Thread Messagethread = new Thread(new ThreadStart(delegate() {
                DispatcherOperation DispacherOP = Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, 
                    new Action(delegate() {
                    ChartData.Add(new Tuple<string, double>("A" + seed.NextDouble(), 1.5 + seed.Next(10)));
                })); 
            }));
            Messagethread.SetApartmentState(ApartmentState.STA);
            Messagethread.Start();

My ViewModel page:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
using System.Collections.ObjectModel;
using Dongzr.MidiLite;
using System.Windows.Threading;
using System.Threading;

namespace WpfVisifire
{
    public class ChartViewModel
    {
        static MmTimer timer1;
        static DispatcherTimer timer2;

        private static readonly Random seed = new Random();
        public ObservableCollection<Tuple<string, double>> ChartData
        {
            get;
            private set;
        }

        public ChartViewModel()
        {
            StopDataCommand = new RelayCommand((p) => stop());
            ChangeVisiChartDataCommand = new RelayCommand((p) => changeData());
            ChartData = new ObservableCollection<Tuple<string, double>>();
            timer1 = new MmTimer();
        }
        public ICommand StopDataCommand
        {
            get;
            private set;
        }
        public ICommand ChangeVisiChartDataCommand
        {
            get;
            private set;
        }
        private void changeData()
        {
            timer1.Mode = MmTimerMode.Periodic;
            timer1.Interval = 2000;
            timer1.Tick += new EventHandler(timer1_Tick);
            timer1.Start();           
        }

        void timer1_Tick(object sender, EventArgs e)
        {
           /*Dispatcher.CurrentDispatcher.BeginInvoke(
                 DispatcherPriority.Normal,
                 new Action(
                     delegate()
                     {
                         ChartData.Add(new Tuple<string, double>("A" + seed.NextDouble(), 1.5 + seed.Next(10)));
                     }));*/
            Thread Messagethread = new Thread(new ThreadStart(delegate() {
                DispatcherOperation DispacherOP = Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, 
                    new Action(delegate() {
                    ChartData.Add(new Tuple<string, double>("A" + seed.NextDouble(), 1.5 + seed.Next(10)));
                })); 
            }));
            Messagethread.SetApartmentState(ApartmentState.STA);
            Messagethread.Start(); 
        }

        private void stop()
        {
            timer1.Stop();
            timer1.Dispose();
            //.Show("jeighier");
        }

    }
}`

MainWindow.xaml

<Window x:Class="WpfVisifire.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vCharts="clr-namespace:Visifire.Charts;assembly=WPFVisifire.Charts"
        xmlns:vm="clr-namespace:WpfVisifire"
        Title="MainWindow" Height="600" Width="525">
    <Window.Resources>
        <ResourceDictionary>
            <vm:ChartViewModel x:Key="chartViewModel" />
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <StackPanel DataContext="{Binding Source={StaticResource chartViewModel}}">
            <WrapPanel Orientation="Horizontal">
                <Button Content="Start" Height="28" Name="Add" Margin="5" Width="125" Command="{Binding Path=ChangeVisiChartDataCommand}"/>
                <Button Margin="5" Height="28" Width="125" Content="Stop" Command="{Binding Path=StopDataCommand}" />
            </WrapPanel>

            <vCharts:Chart Watermark="False" Theme="Theme1" Width="480" Height="479" x:Name="MyChart"
                            AnimationEnabled="True" AnimatedUpdate="True">
                <vCharts:Chart.Titles>
                    <vCharts:Title Text="This is a chart" FontSize="12" />
                    <vCharts:Title Text="This is another chart" FontSize="10" HorizontalAlignment="Right" />
                </vCharts:Chart.Titles>
                <vCharts:Chart.AxesX>
                    <vCharts:Axis Title="horizontal title" />
                </vCharts:Chart.AxesX>
                <vCharts:Chart.AxesY>
                    <vCharts:Axis Title="vertical title" />
                </vCharts:Chart.AxesY>
                <vCharts:Chart.Series>
                    <vCharts:DataSeries x:Name="dataSeries" RenderAs="Line"  DataSource="{Binding Path=ChartData}">
                        <vCharts:DataSeries.DataMappings>
                            <vCharts:DataMapping MemberName="AxisXLabel" Path="Left" />
                            <vCharts:DataMapping MemberName="YValue" Path="Right" />
                        </vCharts:DataSeries.DataMappings>
                    </vCharts:DataSeries>
                </vCharts:Chart.Series>
            </vCharts:Chart>
        </StackPanel>
    </Grid>
</Window>

Solution

  • Try to execute the drawing procedure in your Tick handler. If the tick handler is not executed on the main thread save a Dispatcher instance in a local variable and initialize it in

    public ChartViewModel()
    

    like this :

    myDispatcher=Dispatcher.CurrentDispatcher
    

    then use the myDispatcher.Invoke in the timer tick handler