Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从多个后台线程更新标签_C#_Label_Invokerequired_Background Thread - Fatal编程技术网

C# 从多个后台线程更新标签

C# 从多个后台线程更新标签,c#,label,invokerequired,background-thread,C#,Label,Invokerequired,Background Thread,我正在做一个足球模拟器,我有9场比赛在不同的线程背景。在方法中,每个线程的核心都有一个事件。当这种情况发生时(当一个目标被“踢”了),我想用部分结果更新表单上的标签(名为goalLabel)。我写了一个代码…: for (int i = 0; i < 6; i++) { if (i % 2 == 0) homeGoals++; else awawyGoals++; if (goal != null) goal(this); //(goal is an event)

我正在做一个足球模拟器,我有9场比赛在不同的线程背景。在方法中,每个线程的核心都有一个事件。当这种情况发生时(当一个目标被“踢”了),我想用部分结果更新表单上的标签(名为goalLabel)。我写了一个代码…:

for (int i = 0; i < 6; i++)
{
    if (i % 2 == 0) homeGoals++;
    else awawyGoals++;
    if (goal != null) goal(this); //(goal is an event)
    Thread.Sleep(1000);
} //this is the full method
以及UpdateGallabel方法:

public void UpdateGoalLabel(string update)
{
    if (InvokeRequired)
    {
        MyDel del = new MyDel(UpdateGoalLabel); // yeah, I have a delegate for it: delegate void MyDel(string update);
        Invoke(del, update);
    }
    else
    {
        lock (this) // if this lock isn't here, it works the same way
        {
            this.goalLabel.Text = update;
        }
    }
}
所以我可以接触并更改标签的文本,但我不知道为什么它不会更改54次。这就是我们的目标,在每一个目标之后都能得到通知

有什么想法吗

先谢谢你

更新#1: 我正在使用VS2010

下面是我启动线程的代码:

List<Thread> allMatches = new List<Thread>();
foreach (Match match in matches)
{
    Thread newtmatch = new Thread(match.PlayMatch); //this is the first code block I wrote
    allMatches.Add(newtmatch);
    newtmatch.Start();
}
List allMatches=new List();
foreach(匹配中的匹配)
{
Thread newtmatch=new Thread(match.PlayMatch);//这是我写的第一个代码块
添加(newtmatch);
newtmatch.Start();
}
更新#2: 这里是我附加EventHandler的地方(这是在同一个方法中,在前面的代码块上方有几行):

matches=newlist();
foreach(Program.cm.nextMatches中的[]队对手)
{
比赛vmi=新比赛(对手);
匹配。添加(vmi);
vmi.goal+=新的Match.goalevent(GoalEventHandler);
}
//Program.cm.nextMatches是一个列表对象,其中包含下一场比赛的队对;

我将这些团队数组转换为Match对象,因为这个类有两个团队字段,并且有event和PlayMatch方法,它仍然是包含(仅)第一个代码块的方法。

我在UI刷新方面也遇到了问题,并且直接使用“BackgroundWorker”线程,而不仅仅是“Thread”类。BackgroundWorker线程允许您显式地报告更改的进度,并在线程外调用某些方法(即:调用辅助线程的调用UI线程)。因此,我创建了一个从后台工作程序派生的自定义类,还创建了您所描述的“Match”类的我自己的版本

public class Match
{
    public Match( string Home, string Away )
    {
        HomeTeam = Home;
        HomeGoals = 0;

        AwayTeam = Away;
        AwayGoals = 0;
    }

    // simple properties with PROTECTED setters, yet readable by anyone
    public string HomeTeam
    { get; protected set; }

    public int HomeGoals
    { get; protected set; }

    public string AwayTeam
    { get; protected set; }

    public int AwayGoals
    { get; protected set; }

    // just place-holder since I don't know rest of your declarations
    public EventHandler goal;

    public void PlayMatch()
    {
        for (int i = 0; i < 6; i++)
        {
            if (i % 2 == 0) 
                HomeGoals++;
            else 
                AwayGoals++;

            // Report to anyone listening that a score was made...
            if (goal != null) 
                goal(this, null);

            Thread.Sleep(1000);
        } 
    }
}

// Now, the background worker
public class MatchBGW : BackgroundWorker
{
    // each background worker preserves the "Match" instance it is responsible for.
    // this so "ReportProgress" can make IT available for getting values.
    public Match callingMatch
    { get; protected set; }

    // require parameter of the match responsible for handling activity
    public MatchBGW(Match m)
    {
        // preserve the match started by the background worker activity
        callingMatch = m;

        // tell background worker what method to call
        // using lambda expression to cover required delegate parameters 
        // and just call your function ignoring them.
        DoWork += (sender, e) => m.PlayMatch();

        // identify we can report progress  
        WorkerReportsProgress = true;

        // Attach to the match.  When a goal is scored, notify ME (background worker)
        m.goal += GoalScored;
    }

    // this is called from the Match.
    public void GoalScored(object sender, EventArgs e)
    {
        // Now, tell this background worker to notify whoever called IT
        // that something changed.  Can be any percent, just something to
        // trigger whoever called this background worker, so reported percent is 1
        ReportProgress(1);
    }
}
公共类匹配
{
公开赛(主场、客场)
{
主队=主场;
家庭目标=0;
AwayTeam=远离;
AwayGoals=0;
}
//具有受保护的setter的简单属性,但任何人都可以读取
公共字符串主队
{get;受保护集;}
公共目标
{get;受保护集;}
公共字符串自动转换
{get;受保护集;}
公共交通警署
{get;受保护集;}
//因为我不知道你们其余的声明,所以我只是占位符
公共目标;
公开竞技场(
{
对于(int i=0;i<6;i++)
{
如果(i%2==0)
家庭目标++;
其他的
AwayGoals++;
//向任何听到的人报告评分结果。。。
如果(目标!=null)
目标(this,null);
睡眠(1000);
} 
}
}
//现在,背景工作者
公共类MatchBGW:BackgroundWorker
{
//每个后台工作人员保留其负责的“匹配”实例。
//这使得“ReportProgress”可以用于获取值。
公开比赛
{get;受保护集;}
//需要负责处理活动的匹配参数
公共匹配BGW(匹配m)
{
//保留由后台工作程序活动启动的匹配
callingMatch=m;
//告诉后台工作人员要调用什么方法
//使用lambda表达式覆盖所需的委托参数
//然后调用函数忽略它们。
DoWork+=(发送方,e)=>m.PlayMatch();
//确定我们可以报告进展情况
WorkerReportsProgress=true;
//连接到比赛。当进球时,通知我(后台工作人员)
m、 目标+=得分得分;
}
//这是比赛的结果。
public void GoalScored(对象发送方、事件参数)
{
//现在,告诉这个后台工作人员通知打电话的人
//有些东西改变了。可以是任何百分比,只是一些改变
//触发调用此后台工作程序的人,因此报告的百分比为1
报告进展(1);
}
}
现在,从带有标签的呼叫窗口,例如从按钮开始单击

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        // create your "Matches" between teams
        matches = new List<Match>();
        matches.Add(new Match("A", "B"));
        matches.Add(new Match("C", "D"));
        matches.Add(new Match("E", "F"));

        foreach (Match m in matches)
        {
            // create an instance of background worker and pass in your "match"
            MatchBGW bgw = new MatchBGW(m);
            // tell the background worker that if it is notified to "
            // report progress" to, to pass itself (background worker object)
            // to this class's SomeoneScored method (same UI thread as textbox)
            bgw.ProgressChanged += SomeoneScored;
            // Now, start the background worker and start the next match
            bgw.RunWorkerAsync();
        }
    }

    // This is called from the background worker via "ReportProgress"
    public void SomeoneScored(object sender, ProgressChangedEventArgs e)
    {
        // Just ensuring that the background worker IS that of what was customized
        if (sender is MatchBGW)
        {
            // get whatever "match" associated with the background worker
            Match m = ((MatchBGW)sender).callingMatch;
            // add it's latest score with appropriate home/away team names
            this.txtAllGoals.Text +=
                string.Format("{0} {1} - {2} {3}\r\n", 
                m.HomeTeam, m.HomeGoals, m.AwayGoals, m.AwayTeam );
        }
    }
private void按钮1\u单击(对象发送者,路由目标)
{
//创建团队之间的“比赛”
匹配项=新列表();
匹配项。添加(新匹配项(“A”、“B”));
匹配。添加(新匹配(“C”、“D”);
匹配项。添加(新匹配项(“E”、“F”));
foreach(匹配中的匹配m)
{
//创建后台工作程序实例并传入“匹配”
MatchBGW-bgw=新的MatchBGW(m);
//告诉后台工作人员,如果它被通知“
//将进度报告给,以传递自身(后台工作对象)
//该类的SomeoneScored方法(与textbox相同的UI线程)
bgw.ProgressChanged+=某人得分;
//现在,启动后台工作程序并开始下一个匹配
bgw.RunWorkerAsync();
}
}
//这是通过“ReportProgress”从后台工作程序调用的
public void SomeoneScored(对象发送者,progresschangedventargs e)
{
//只是确保后台工作人员是定制的工作人员
如果(发送方为匹配BGW)
{
//获取与后台工作程序关联的任何“匹配”
匹配m=((MatchBGW)发送方)。调用匹配;
//用适当的主客场球队名称添加其最新得分
此文件为.txtallgools.Text+=
string.Format(“{0}{1}-{2}{3}\r\n”,
m、 主队,m.HomeGoals,m.AwayGoals,m.AwayTeam);
}
}
是的,它可能是更多的代码,但我明确地处理谁被召回,并报告什么在他们适当的thre
public class Match
{
    public Match( string Home, string Away )
    {
        HomeTeam = Home;
        HomeGoals = 0;

        AwayTeam = Away;
        AwayGoals = 0;
    }

    // simple properties with PROTECTED setters, yet readable by anyone
    public string HomeTeam
    { get; protected set; }

    public int HomeGoals
    { get; protected set; }

    public string AwayTeam
    { get; protected set; }

    public int AwayGoals
    { get; protected set; }

    // just place-holder since I don't know rest of your declarations
    public EventHandler goal;

    public void PlayMatch()
    {
        for (int i = 0; i < 6; i++)
        {
            if (i % 2 == 0) 
                HomeGoals++;
            else 
                AwayGoals++;

            // Report to anyone listening that a score was made...
            if (goal != null) 
                goal(this, null);

            Thread.Sleep(1000);
        } 
    }
}

// Now, the background worker
public class MatchBGW : BackgroundWorker
{
    // each background worker preserves the "Match" instance it is responsible for.
    // this so "ReportProgress" can make IT available for getting values.
    public Match callingMatch
    { get; protected set; }

    // require parameter of the match responsible for handling activity
    public MatchBGW(Match m)
    {
        // preserve the match started by the background worker activity
        callingMatch = m;

        // tell background worker what method to call
        // using lambda expression to cover required delegate parameters 
        // and just call your function ignoring them.
        DoWork += (sender, e) => m.PlayMatch();

        // identify we can report progress  
        WorkerReportsProgress = true;

        // Attach to the match.  When a goal is scored, notify ME (background worker)
        m.goal += GoalScored;
    }

    // this is called from the Match.
    public void GoalScored(object sender, EventArgs e)
    {
        // Now, tell this background worker to notify whoever called IT
        // that something changed.  Can be any percent, just something to
        // trigger whoever called this background worker, so reported percent is 1
        ReportProgress(1);
    }
}
    private void button1_Click(object sender, RoutedEventArgs e)
    {
        // create your "Matches" between teams
        matches = new List<Match>();
        matches.Add(new Match("A", "B"));
        matches.Add(new Match("C", "D"));
        matches.Add(new Match("E", "F"));

        foreach (Match m in matches)
        {
            // create an instance of background worker and pass in your "match"
            MatchBGW bgw = new MatchBGW(m);
            // tell the background worker that if it is notified to "
            // report progress" to, to pass itself (background worker object)
            // to this class's SomeoneScored method (same UI thread as textbox)
            bgw.ProgressChanged += SomeoneScored;
            // Now, start the background worker and start the next match
            bgw.RunWorkerAsync();
        }
    }

    // This is called from the background worker via "ReportProgress"
    public void SomeoneScored(object sender, ProgressChangedEventArgs e)
    {
        // Just ensuring that the background worker IS that of what was customized
        if (sender is MatchBGW)
        {
            // get whatever "match" associated with the background worker
            Match m = ((MatchBGW)sender).callingMatch;
            // add it's latest score with appropriate home/away team names
            this.txtAllGoals.Text +=
                string.Format("{0} {1} - {2} {3}\r\n", 
                m.HomeTeam, m.HomeGoals, m.AwayGoals, m.AwayTeam );
        }
    }
public class MainWindowViewModel : DispatcherObject, INotifyPropertyChanged
{
    public MainWindowViewModel()
    {
        Matches = new ObservableCollection<MatchViewModel>();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private ObservableCollection<MatchViewModel> _matches;
    public ObservableCollection<MatchViewModel> Matches
    {
        get { return _matches; }
        set
        {
            _matches = value;
            OnPropertyChanged("Matches");
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class MatchViewModel : DispatcherObject, INotifyPropertyChanged
{
    public MatchViewModel()
    {
        HomeTeam = new TeamViewModel();
        AwayTeam = new TeamViewModel();
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private TeamViewModel _homeTeam;
    public TeamViewModel HomeTeam
    {
        get { return _homeTeam; }
        set
        {
            _homeTeam = value;
            OnPropertyChanged("HomeTeam");
        }
    }

    private TeamViewModel _awayTeam;
    public TeamViewModel AwayTeam
    {
        get { return _awayTeam; }
        set
        {
            _awayTeam = value;
            OnPropertyChanged("AwayTeam");
        }
    }

    public void PlayMatch()
    {
        for (int i = 0; i < 6; i++)
        {
            if (i % 2 == 0)
                OnGoalScored(HomeTeam);
            else
                OnGoalScored(AwayTeam);
            Thread.Sleep(1000);
        }
    }

    private void OnGoalScored(TeamViewModel team)
    {
        if (!team.Dispatcher.CheckAccess())
        {
            team.Dispatcher.Invoke((Action<TeamViewModel>)OnGoalScored, team);
        }
        else
        {
            team.Score++; // do other stuff here
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

public class TeamViewModel : DispatcherObject, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            _name = value;
            OnPropertyChanged("Name");
        }
    }

    private int _score;
    public int Score
    {
        get { return _score; }
        set
        {
            _score = value;
            OnPropertyChanged("Score");
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        MainWindowViewModel mainWindow = new MainWindowViewModel();
        List<Thread> matchThreads = new List<Thread>();
        foreach (Team[] opponents in Program.cm.nextMatches)
        {
            MatchViewModel match = new MatchViewModel();
            match.HomeTeam.Name = opponents[0].Name;
            match.AwayTeam.Name = opponents[1].Name;
            mainWindow.Matches.Add(match);

            Thread matchThread = new Thread(match.PlayMatch);
            matchThreads.Add(matchThread);
            matchThread.Start();
        }

        MainWindow = new MainWindow();
        MainWindow.DataContext = mainWindow;
        MainWindow.Show();
    }
<Window x:Class="TestMatch.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <ItemsControl ItemsSource="{Binding Matches}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock>
                    <TextBlock.Text>
                        <MultiBinding StringFormat="{}{0} {1} - {2} {3}">
                            <Binding Path="HomeTeam.Name"/>
                            <Binding Path="HomeTeam.Score"/>
                            <Binding Path="AwayTeam.Name"/>
                            <Binding Path="AwayTeam.Score"/>
                        </MultiBinding>
                    </TextBlock.Text>
                </TextBlock>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Window>
public partial class Program
{
    protected override void OnStartup(StartupEventArgs e)
    {
        ...
    }

    private class Team
    {
        public string Name { get; set; }
    }

     private static class cm
     {
         static cm()
         {
             nextMatches =
                 new Team[][]
                     {
                         new[] { new Team { Name = "TeamA" }, new Team { Name = "TeamB" }},
                         new[] { new Team { Name = "TeamC" }, new Team { Name = "TeamD" }},
                         new[] { new Team { Name = "TeamE" }, new Team { Name = "TeamF" }},
                         new[] { new Team { Name = "TeamG" }, new Team { Name = "TeamH" }},
                         new[] { new Team { Name = "TeamI" }, new Team { Name = "TeamJ" }},
                         new[] { new Team { Name = "TeamK" }, new Team { Name = "TeamL" }},
                         new[] { new Team { Name = "TeamM" }, new Team { Name = "TeamN" }},
                         new[] { new Team { Name = "TeamO" }, new Team { Name = "TeamP" }},
                         new[] { new Team { Name = "TeamQ" }, new Team { Name = "TeamR" }},
                     };
         }

         public static Team[][] nextMatches { get; set; }
     }
}