처리코드와 컨트롤의 내용 변경시 비동기적으로 동작하는 것 같은데 원인이 무엇일까요?

안녕하세요.
저는 웹개발을 전문으로 하다보니 윈폼의 UI 개발에 개념이 좀 부족한 것 같습니다.

윈폼으로 윈도우 기능중 IIS를 설치하는 기능을 구현중에 있습니다.
윈도우에 보면 dismApi 가 제공되어 누겟에서 해당 api를 사용할 수 있게 해주는 라이브러리가 있어 적용하여 사용중입니다.

문제는 아래의 설치하려는 모듈 배열을 반복문을 통해 설치하는데요.
1개의 모듈이 설치될 때 진행바와 텍스트 박스 등에 현재 진행되고 있는 모듈 정보를 표시하려고 합니다.
어떤 모듈이 설치중인지 진행률은 어느정도인지.
문제는 반복문이 시작될 때 현재 설치되는 모듈 이름을 텍스트박스에 표시해 주고 진행률 텍스트 박스도 0%로 초기화 하고 하는 코드들이 있고 EnableFeature(featureItem) 메서드를 통해 실제 설치가 됩니다.
제가 원하는 의도는 내용이 하나의 모듈이 설치되면서 컨트롤의 내용도 바로바로 갱신이 되길 원하나 실제 동작은 반복문이 끝나고 나서 마지막 결과가 그때 반영이 됩니다. 뭔가 비동기적인 처리가 이루어 지고 있다는 느낌입니다. 이런 경우 어떤 부분을 확인해 봐야 할지 궁금합니다.

        string features = new string[]
        { "IIS-WebServerRole"
        ,"IIS-NetFxExtensibility45"
        ,"IIS-ISAPIExtensions"
        ,"IIS-ISAPIFilter"
        ,"IIS-ASPNET45"
        ,"IIS-LoggingLibraries"
        ,"IIS-BasicAuthentication"
        ,"IIS-WindowsAuthentication"
        ,"IIS-HttpCompressionDynamic"
        ,"IIS-ManagementScriptingTools"};

        //IIS 기능 사용
        var featureCount = 0;
        foreach (var featureItem in features)
        {
            featureCount++;
            lblFeaturePer.Text = "0%";
            prgFeature.Value = 0;
            prgFeature.Update();

            EnableFeature(featureItem);
            txtResult.Text += featureItem + System.Environment.NewLine;
            Thread.Sleep(1000);
        }

    //실제 기능 추가 하는 코드
    public void EnableFeature(string featureName, int featureCount = 0)
    {
        DismApi.Initialize(DismLogLevel.LogErrorsWarningsInfo);
        try
        {
            var session = DismApi.OpenOnlineSession();
            lblFeaturePer.Text = "0%";

            DismApi.EnableFeature(session, featureName, false, true, null, progress =>
            {
                prgFeature.Value = progress.Current / 10;
                prgFeature.Update();
                lblFeaturePer.Text = $"{progress.Current / 10}% / {progress.Total / 10}%";
            });
        }
        catch (DismRebootRequiredException Ex)
        {
            _isReboot = true;
        }
    }
1개의 좋아요

작성해주신 코드가 맞는 로직인지 모르겠는데 우선

foreach 에서 prgFeature를 0으로 초기화 하면 항상 0 아닌가요?

foreach (var featureItem in features)
{
    prgFeature.Value = 0;  // 항상 0
    EnableFeature(featureItem);
}

public void EnableFeature(string featureName, int featureCount = 0)
{
    prgFeature.Value = progress.Current / 10;
}

이 문제는 메인 스레드에서 모두 처리되서 이벤트 메세지 루프가 마지막에 한번에 처리되서 그런것 같습니다.

위 처리를 메인 스레드에서 처리 하시지 마시고 별도의 스레드로 처리하면 될 것 같습니다.

ProgressBar를 통해 현재 진행상태를 나타내고자 하니깐 EAP비동기, BackgroundWorker클래스 사용을 추천합니다.

BackgroundWorker 클래스 (System.ComponentModel) | Microsoft Learn

2개의 좋아요

우선 답변 감사드립니다.

EnableFeature(featureItem); 가 실행되기 전에 progressbar를 초기화 하고 EnableFeature가 진행되면서 prgFeature.Value를 갱신하는 코드가 있어서 진행률이 바뀌게 하고 있는데요.

말씀하신데로 BackgroundWorker를 통해 처리하고 이벤트에서 진행률과 현재 진행중인 작업을 넘겨받아서 갱신하니 바로바로 적용은 되더라고요.

2개의 좋아요

아 지금 닷넷 버전이 얼마를 쓰고 계신지는 모르겠지만…
.Net Framework 4.0을 쓸때까지만 하더라도 ProgressBarControl 버그(?)가 있었어요…
그게 무슨 Windows Aero테마 관련 이슈가 있었던 것으로 기억합니다.
아마 4.7.x도 마찬가지가 아닐까 싶은데요.
그때 제 해결책은 value 값을 설정하려는 값보다 1 크게 설정해주고, 곧장 -1을 해주는 방식으로
Value를 세팅해주니 그 문제가 사라지곤 했었습니다.

2개의 좋아요