2014-07-17 6 views
0

별도의 스레드에서 생성해야하는 작업을 사용하고 있음에도 불구하고 응용 프로그램에서 UI 프로세스가 멈추는 문제가 있습니다.UI 스레드가 잠기는 것을 어떻게 중지합니까?

<Image Name="LoadingCog" Source="/Resources/Cog.png" Margin="0,37" Width="60" Height="60" HorizontalAlignment="Center" RenderTransformOrigin="0.5,0.5"> 
    <Image.Resources> 
     <Storyboard x:Key="LoadingCogRotateStoryboard"> 
      <DoubleAnimation 
        Storyboard.TargetName="LoadingCogRotateTransform" 
        Storyboard.TargetProperty="Angle" 
        By="10" 
        To="360" 
        Duration="0:0:7" 
        FillBehavior="Stop" 
        RepeatBehavior="Forever" /> 
     </Storyboard> 
    </Image.Resources> 
    <Image.RenderTransform> 
     <RotateTransform x:Name="LoadingCogRotateTransform" Angle="0" /> 
    </Image.RenderTransform> 
</Image> 

가 나는 또한 내에서 이벤트 처리기가 코드 숨김에 대한 :

나는 여기에 XAML은, 내가/같이 필요에 따라 숨겨진되고있는 로딩 창에서 회전하고 이미지가 윈도우의 가시성이 변경 될 때 애니메이션을 다시 시작하는 창

void LoadingScreenWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) 
{ 
    var storyBoard = (System.Windows.Media.Animation.Storyboard)LoadingCog.Resources["LoadingCogRotateStoryboard"]; 

    if (IsVisible == true) 
    { 
     storyBoard.Seek(TimeSpan.Zero); 
     storyBoard.Begin(); 
    } 
    else 
    { 
     storyBoard.Stop(); 
    } 
} 

나는/숨어/다음과 같은 방법이있다 로딩 창에서 메시지를 변화 보여주는 담당하는 컨트롤러가 있습니다

Task.Factory.StartNew(() => 
{ 
    LoadingScreenController.ShowLoadingScreen("Loading application, please wait.."); 

    PerformNotSoIntensiveLoadingOperation(); 

    HideLoadingScreen(); 

    System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => 
    { 
     LoginWindow.Show(); 
    })); 

    LoadingScreenController.ShowLoadingScreen("Logging in, please wait.."); 

    PerformIntensiveLoadingOperations(); 

    LoadingScreenController.HideLoadingScreen(); 

    System.Windows.Application.Current.Dispatcher.Invoke((Action)(() => 
    { 
     MainWindow.Show(); 
    })); 
}, TaskCreationOptions.LongRunning); 

내가 실제로 새 스레드를 얻을 수 있도록하기 위해 TaskCreationOptions.LongRunning를 사용하여 내 App.xaml.cs 파일에서

internal void ShowLoadingScreen(string loadingMessage) 
{ 
    Application.Current.Dispatcher.Invoke((Action)(() => 
    { 
     _viewModel.LoadingMessage = loadingMessage; 

     _loadingWindow.Show(); 
    })); 
} 

internal void HideLoadingScreen() 
{ 
    Application.Current.Dispatcher.Invoke((Action)(() => 
    { 
     _loadingWindow.Hide(); 
    })); 
} 

내 응용 프로그램의로드 프로세스를 시작하려면 다음과 유사한 코드가 있습니다.

PerformNotSoIntensiveLoadingOperation()의 코드가 내 PC에서 실행되는 데 그리 오래 걸리지 않으므로 로딩 애니메이션이 제대로 작동합니다.

창을 숨기고보다 집중적 인 작업을 PerformIntensiveLoadingOperations()에서 실행하면 다시 창이 나타나 애니메이션이 멈 춥니 다.

집중적 인 작업이 완료된 후에 창이 열리면 예상대로 애니메이션이 계속됩니다. 대한 명확한

, 프로세스는 다음과 같다 :

표시 로딩 화면>> 다른 창을 표시하는 창을 닫기 전에 사용자 상호 작용을 기다립니다> 몇 가지 작업> 숨기기 로딩 화면을> 다시 로딩 창을 보여> 어떤을 더 많은 작업> 윈도우 다시로드 숨기기> 메인 응용 프로그램 윈도우 보이기

Task의 스레드 (UI 코드를 전혀 건드리지 않음)의 애니메이션이 멈 추면 그 부분은 do some more work입니다.

.Net 4.0.3을 사용하고 있습니다.

Application.Current.Dispatcher.Invoke으로 전화를 끊으면 호출 스레드가 액세스하려고하는 개체를 소유하고 있지 않다는 것을 알려주는 예상 크로스 스레드 위반 예외가 발생하므로 코드가 UI 스레드에서 실행되지 않습니다.

이 원인은 무엇이며 어떤 일이 발생하지 않도록 할 수 있습니까?

답변

2

귀하의 Task에 UI 작업을 시도하고 있습니다 ... 귀하가 그렇게 할 수 있다고 생각하지 않습니다. 백그라운드 스레드에서 UI 컨트롤에 액세스 할 수 없습니다. 렌더링 중이거나 알림을 보내고 통화 중 표시기를 고정시키지 않는 것이 UI 스레드임을 알 수 있습니다.

분명히 말하자면, 모든 UI 작업은 UI 스레드에서 수행됩니다. 따라서 백그라운드 스레드에서 UI에 무언가를 표시하려고하면 표준 오류가 발생하거나 코드가 UI 스레드에 자동으로 정렬됩니다.

대규모 WPF 응용 프로그램에서 비슷한 설정이 있는데 같은 문제가 있습니다. 데이터베이스에서 데이터를 페치하는 동안 사용 중 표시기는 잘 표시되지만 응용 프로그램이 UI에서 데이터를 렌더링하기 시작하면 사용 표시기가 고정됩니다.

나는 애니메이션 GIF를 사용하여이 문제를 해결하려고 시도했지만, 물론 WPF 응용 프로그램에서는 (자체적으로) 애니메이션을 적용하지 않습니다. Gif에서 프레임을 애니메이션화하는 코드를 작성한 후에도 동일한 문제로 고통 받았다는 사실에 매우 실망했습니다.

+0

내 상황에서 수행되는 유일한 UI 작업은 창 표시/숨기기입니다. 그 후 모든 코드는 웹 서비스 및 데이터베이스 작업에 대한 호출을 처리합니다. 또한 Dispatcher를 명시 적으로 사용하여 show/hide 메서드 (예 : 내 코드 예제와 같이)를 호출하지 않고 (예상대로) "호출 스레드가이 개체를 소유하지 못했습니다."오류가 발생했습니다. 로딩 윈도우는 매우 간단합니다. 전체 텍스트가 표시되는'TextBlock'과'Image'가 있습니다. 로딩 윈도우가 숨겨진 후에 다른 윈도우가 표시됩니다. 애니메이션이 적용되지 않는 경우에는 상관 없습니다. – Sean

+2

'이지만 응용 프로그램에서 UI의 데이터 렌더링을 시작하면 통화 중 표시기가 멈 춥니 다.' UI 스레드는 UI의 나머지 부분을 렌더링하는 동안 통화 중 표시기에 애니메이션을 적용 할 수 없습니다. – AwkwardCoder

+0

@AwkwardCoder 어느 시간까지 로딩 창이 숨겨져 있으며 그것이 애니메이션이기 때문에 움직이지 않아도 상관 없어요. 어쨌든 숨겨졌다. 무슨 일이 일어나고 있는지, 로딩 화면을 보이고,로드 스크린을 숨기고, 다른 윈도우를 보여 주며, 사용자 상호 작용을 기다리고, 윈도우를 닫고, 로딩 윈도우를 보여주고, 더 많은 일을하고, 다시 숨기며, 메인 애플리케이션 창. 그것은 내 애니메이션이 멈추고있는 Task의 스레드 (어떤 UI 코드도 건드리지 않음)에서 "어떤 일을하고있는 중"과 "더 많은 일을하고있는"동안입니다. – Sean

관련 문제