2017-09-29 10 views
1

데이터 처리 시간이 길기 때문에 프로그램에서 현재 수행하고있는 GUI 및 리치 텍스트 상자가있는 응용 프로그램이 있습니다. 내가 잘 다음 코드를 호출 할 수있는 BackgroundWorker 방법에backgroundworker에서 호출 한 메서드 내에서 프로세스 업데이트 C#

1 :

나는 그 두 가지 접근 방식을 시도

GlobalVar.backgroundWorkerAppendText = task.Build_CSV_List(); 
Processchange(); 

내가 인해 비 정적에 헬퍼 클래스에 Form1.Processchange();를 사용할 수없는 반면, 컨텍스트

2 따라서 첫 번째 이벤트 핸들러를 만들려고했습니다.
아이디어는 helper.UpdateConsole은() 이벤트

public event EventHandler OnConsoleUpdate; 
public void Consoleupdate() 
{ 
    OnConsoleUpdate(this, EventArgs.Empty); 
} 

을 올릴 것이라고했다 BackgroundWorker에 수신 대기하고 불행하게도이 성공하지이었다 컨텍스트

public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    StandardTasks task = new StandardTasks(); 
    Helper helper = new Helper(); 
    helper.OnConsoleUpdate += Processchange; 
    task.DoSomeStuffHere() 
} 
public void Processchange(object sender=null, EventArgs e=null) 
{ 
    //MessageBox.Show(GlobalVar.backgroundWorkerAppendText); 
    GlobalVar.next = false; 
    backgroundWorker1.ReportProgress(1); 
    while (GlobalVar.next == false) 
    { 
     helper.TimeBreaker(100,"ms"); 
    } 
} 

에서 Processchange를 호출하는 것이다. 이벤트가 일어나 자마자 나는 errormessage System.NullReferenceException을 얻었습니다. 그 후 - googling-은 내가 이벤트 워크 쇼에 첨부 된 listerner가 없기 때문에 Backgroundworker Do 작업에 첨부했습니다.

편집 : OnConsoleUpdate() == null의 도우미가

event = null

아래의 스크린 샷과 같이 해결책 중요 할 수있는 다른 클래스 파일 "헬퍼"입니다.

나는 너희들이 나를 도울 수 있기를 바랍니다.

+0

인가 (꼭지)? 그런 다음 ThreadPool에서 Task를 시작하고 Progress 객체를 전달할 수 있습니다. Backgroundworker를 계속 사용하려면 관련 코드를 더 많이 표시해야합니다. – Fildor

+0

이 백그라운드 작업을 어디에서 시작하셨습니까? 나는 그런 식으로 뭔가 : backgroundWorker1.RunWorkerAsync(); – Arkadiusz

+0

BTW : 일부 코드 냄새가있는 "GlobalVar"클래스가 있습니다 ... – Fildor

답변

2

안녕하세요!

몇 가지 사실이 즉시 뛰어납니다.

먼저 이벤트 문제를 해결해 봅시다. 올바른 접근법을 가졌습니다. 이벤트와 메서드를 호출해야하지만이 메서드는 이벤트가 null인지 확인해야합니다.

public event EventHandler OnConsoleUpdate; 
public void ConsoleUpdate() 
{ 
    OnConsoleUpdate?.Invoke(this, EventArgs.Empty); 
} 

(가) 상기 ?, 널 조건 연산자를 사용한다 : 기본적

이 수행. 자세한 내용은 on this MSDN page을 참조하십시오.

두 번째 것은 ... 배경 담당자가 실제로 무엇인지 분명하지 않습니다. 네가 만든 맞춤 수업 같은 것 같은데? 그 이유는 .NET이 실질적으로 운영을 위해 사용되는 BackgroundWorker 클래스를 가지고 있기 때문입니다. 또한 OnProgressChanged 이벤트가있어서 UI를 업데이트하는 데 사용할 수 있습니다 (WorkerReportsProgress 속성을 true으로 설정하는 것을 기억하십시오). 그리고 위에서 언급 한 BackgroundWorker을 사용하려면 자신의 이벤트를 만들 필요가 없습니다.

표준을 사용하는 방법은 다음과 같습니다.BackgroundWorker NET :

System.ComponentModel.BackgroundWorker worker = new System.ComponentModel.BackgroundWorker(); 

void StartBackgroundTask() 
{ 
    worker.DoWork += worker_DoWork; 
    //if it's possible to display progress, use this 
    worker.WorkerReportsProgress = true; 
    worker.ProgressChanged += worker_ProgressChanged; 
    //what to do when the method finishes? 
    worker.RunWorkerCompleted += worker_RunWorkerCompleted; 
    //start! 
    worker.RunWorkerAsync(); 
} 

void worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e) 
{ 
    //perform any "finalization" operations, like re-enable disabled buttons 
    //display the result using the data in e.Result 
    //this code will be running in the UI thread 
} 

//example of a container class to pass more data in the ReportProgress event 
public class ProgressData 
{ 
    public string OperationDescription { get; set; } 
    public int CurrentResult { get; set; } 
    //feel free to add more stuff here 
} 

void worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e) 
{ 
    //display the progress using e.ProgressPercentage or e.UserState 
    //this code will be running in the UI thread 
    //UserState can be ANYTHING: 
    //var data = (ProgressData)e.UserState; 
} 

void worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) 
{ 
    //this code will NOT be running in the UI thread! 
    //you should NOT call the UI thread from this method 

    int result = 1; 
    //perform calculations 
    for (var i = 1; i <= 10; i++) 
    { 
     worker.ReportProgress(i, new ProgressData(){ OperationDescription = "CustomState passed as second, optional parameter", CurrentResult = result }); 
     System.Threading.Thread.Sleep(TimeSpan.FromSeconds(5)); 
     result *= i; 
    } 

    e.Result = result; 
} 

이제 BackgroundWorker 클래스에 대한 것은 당신이 쉽게 배경 운영 및 UI 업데이트를 처리 할 수 ​​async/await 키워드를 사용할 수 있습니다 오히려 예전과 현재의 .NET 버전입니다 그러나 이것은 아마도 때문이다 이 질문의 범위를 벗어납니다. 즉, async/await의 존재는 사용법이 매우 단순한 BackgroundWorker의 사용을 무효화하지 않습니다.

코드에 걱정스러운 점이 하나 더 있습니다.

public void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    StandardTasks task = new StandardTasks(); //<- you create a task 
    Helper helper = new Helper(); // <- you create a helper 
    helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper event 
    task.DoSomeStuffHere(); // <- you do stuff with the task... but the task doesn't know about your helper above! Does `StandardTasks` use `Helper`? If so, how? 
} 

static이 아닌 이벤트는 전역 적이 지 않습니다. 따라서 한 클래스의 한 인스턴스에서 이벤트에 연결해도 해당 클래스의 다른 인스턴스는 해당 이벤트를 "실행"하지 않습니다. 그것은 StandardTasks 클래스는 생성자 매개 변수 중 하나로서 Helper을하게하는 것입니다 귀하의 문제를 해결하는 한 가지 방법을 것 같다, 그래서 코드는 다음과 같을 것이다 : 그것은 작업 기반 비동기 패턴으로 전환 할 수있는 옵션

Helper helper = new Helper(); // <- you create a helper 
helper.OnConsoleUpdate += Processchange; // <- you hook up to the helper class event to actually do something 
StandardTasks task = new StandardTasks(helper); //<- you create a task which will use the helper with the hooked up event above 
+0

null과 같은 이벤트 처리기를 확인하는 것은 안전하지 않으며 예외가 발생할 수 있습니다. 추가 된 핸들러는 null에 대한 점검과 핸들러 호출 사이에 제거 될 수 있습니다. null 조건부 연산자 (?.)를 사용하거나 OnConsoleUpdate를 로컬 변수에 저장하고이를 null 검사 및 호출에 사용하는 것이 좋습니다. –

+1

@ SzabolcsDézsi 당신은 틀린입니다. 나는 대답을 편집 할 것이다. 그럼에도 불구하고, 그것은 공정하기 위해 사건을 처리하기위한 표준 방법 이었습니까? 연산자는 내가 믿는 추가되었습니다 ... – Shaamaan

+0

안녕하세요 Shaamaan, 도와 줘서 고마워. 귀하의 코드는 실제로 내 코드에서 가지고 있지만 작동하지 않습니다. backgroubndworker 나는 양식 디자이너에서 도구 창에서 "뽑아". 나는 또한 Processchanged를 할 수 있지만 backgroundworker 내에서만 직접 할 수 있습니다. 호출 한 메소드가 아닙니다. –