Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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#_Multithreading_Winforms - Fatal编程技术网

C# 如何允许按钮停止操作并使该操作影响窗体控件

C# 如何允许按钮停止操作并使该操作影响窗体控件,c#,multithreading,winforms,C#,Multithreading,Winforms,因此,基本上,我正在创建音乐软件,希望能够在必要时暂停/停止歌曲。然而,当歌曲播放时,它不允许使用表单上的任何控件,“KeyDown”事件似乎也没有效果,因此我无法停止歌曲,直到它结束 我曾尝试使用“thread”类的一个实例来实现这一点,但问题是我需要在表单上使用某些“Label”控件,这在另一个线程中似乎很难实现 以下是我的“播放”代码的要点 Sound[]notes=song.Sounds; 双秒=0; foreach(音符中的声音) { 秒+=(双)音。NoteType.GetDurat

因此,基本上,我正在创建音乐软件,希望能够在必要时暂停/停止歌曲。然而,当歌曲播放时,它不允许使用表单上的任何控件,“KeyDown”事件似乎也没有效果,因此我无法停止歌曲,直到它结束

我曾尝试使用“thread”类的一个实例来实现这一点,但问题是我需要在表单上使用某些“Label”控件,这在另一个线程中似乎很难实现

以下是我的“播放”代码的要点

Sound[]notes=song.Sounds;
双秒=0;
foreach(音符中的声音)
{
秒+=(双)音。NoteType.GetDuration(节奏)/1000;
}
timeleft=秒;
lblSecondsLeft.Text=timeleft+“”;
双倍长度=注释长度;
双倍物=(100/长度);
双重其他事物=数学圆(事物);
声音=音符;
双进度=0;
for(int i=0;i
这是一种烦恼,但却是众所周知的烦恼。您必须在单独的(非UI)线程上运行非UI代码,以便UI对按钮、文本更新等保持响应。但是,这意味着您必须在更新期间切换到UI线程,从而从非UI线程更新UI。下面的代码就是这样做的

注1:这是从一些我必须手工编写的代码中删除的,因此没有正确检查

注2:这是WPF版本,WinForms略有不同,但原理相同

   public String LabelText{
        get {
            if (!this.Dispatcher.CheckAccess()) {
                return (String)this.Dispatcher.Invoke(new Func<String>(() => { return LabelText; }));
            }
            return Label.Text;
        }
        set {
            if (!this.Dispatcher.CheckAccess()) {
                this.Dispatcher.Invoke(new Action(() => { LabelText = value; }));
                return;
            }
            LabelText = value;
        }
    }
公共字符串标签文本{
得到{
如果(!this.Dispatcher.CheckAccess()){
返回(字符串)this.Dispatcher.Invoke(newfunc(()=>{return LabelText;}));
}
返回标签.文本;
}
设置{
如果(!this.Dispatcher.CheckAccess()){
Invoke(新操作(()=>{LabelText=value;}));
返回;
}
LabelText=值;
}
}

这是通过检查get/set是否在正确的线程上来实现的,如果不是,则切换线程并调用自身(现在在正确的线程上),完成get或set并返回。如果您不需要线程等待屏幕更新,您也可以使用BeginInvoke,这对于实时音乐来说很可能就是这样。

这是一个烦恼,但却是众所周知的烦恼。您必须在单独的(非UI)线程上运行非UI代码,以便UI对按钮、文本更新等保持响应。但是,这意味着您必须在更新期间切换到UI线程,从而从非UI线程更新UI。下面的代码就是这样做的

注1:这是从一些我必须手工编写的代码中删除的,因此没有正确检查

注2:这是WPF版本,WinForms略有不同,但原理相同

   public String LabelText{
        get {
            if (!this.Dispatcher.CheckAccess()) {
                return (String)this.Dispatcher.Invoke(new Func<String>(() => { return LabelText; }));
            }
            return Label.Text;
        }
        set {
            if (!this.Dispatcher.CheckAccess()) {
                this.Dispatcher.Invoke(new Action(() => { LabelText = value; }));
                return;
            }
            LabelText = value;
        }
    }
公共字符串标签文本{
得到{
如果(!this.Dispatcher.CheckAccess()){
返回(字符串)this.Dispatcher.Invoke(newfunc(()=>{return LabelText;}));
}
返回标签.文本;
}
设置{
如果(!this.Dispatcher.CheckAccess()){
Invoke(新操作(()=>{LabelText=value;}));
返回;
}
LabelText=值;
}
}

这是通过检查get/set是否在正确的线程上来实现的,如果不是,则切换线程并调用自身(现在在正确的线程上),完成get或set并返回。如果您不需要线程等待屏幕更新,也可以使用BeginInvoke,这对于实时音乐很可能是如此。

好的,您正在UI线程上同步运行所有内容-当然,UI不能使用。
Sound
类是否有异步API(不管是什么)?一个音符一个音符的播放可能不会很好,但是…我想说的是,我以前曾尝试在另一个线程中运行此代码,因此它已经是异步的。嗯,您无法避免使用不同的线程。但是,如果使用Invoke,从另一个线程访问控件是没有问题的。最简单的方法是将表示代码与实际播放分开。然后,您可以根据需要使用例如
IProgress
发布任何UI更新。尽管您可能希望改用基于拉的方法,因为您当前的方法要么发布太多更新(当注释较短时),要么发布太少更新(当注释较长时)。计时器读取当前状态并更新UI可能会更好。添加到@Luaan last comment中,您可以将事件
NextNote
添加到模型中以更新进度(例如,显示当前播放的音符以及还剩多少音符/秒)和事件
已开始
/
已完成
(出于明显的原因)(用于播放歌曲)。嗯,您正在UI线程上同步运行所有内容-当然UI不能使用。是否有用于
Sound
类的异步API(不管是什么)?一个音符一个音符的播放可能不会很好,但是…我想说的是,我以前曾尝试在另一个线程中运行此代码,因此它已经是异步的。嗯,您无法避免使用不同的线程。但是如果