2011-02-09 10 views
9

Mam kontrolę użytkownika WPF, dla której muszę wymusić renderowanie w RenderMode.SoftwareOnly. Ponieważ używam .NET 3.5, musiałem zrobić coś takiego,Tryb renderowania oprogramowania - WPF

var hwndSource = PresentationSource.FromVisual(this) as HwndSource; 
if (hwndSource != null) 
{ 
    hwndSource.CompositionTarget.RenderMode = RenderMode.SoftwareOnly;   
} 

Ale to nie działa na mojej aplikacji, program WPF jest upaść na kilku maszynach i wyłączenie akceleracji sprzętowej na poziomie rejestru wydaje naprawić problem.

Powyższy kod jest zapisany w zdarzeniu Loaded okna. Jeśli mam rację, zdarzenie Loaded dzieje się po wyrenderowaniu formantów (MSDN). Czy ma sens posiadanie powyższego kodu w tym wydarzeniu? Jeśli nie, jakie wydarzenie byłoby dla niego odpowiednie?

Czy ustawienie na obrazie RenderMode wpływa na jego dzieci? Czy muszę ustawić to specjalnie dla każdego elementu potomnego?

Każda pomoc będzie świetna!

+0

Cześć, jestem ciekawy. Czy rozwiązanie dyspozytorskie ci pomogło? – HCL

Odpowiedz

16

Oto co zrobiliśmy:

private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     if (ForceSoftwareRendering) 
     { 
      HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource; 
      HwndTarget hwndTarget = hwndSource.CompositionTarget; 
      hwndTarget.RenderMode = RenderMode.SoftwareOnly; 
     } 
    } 

To działało OK dla nas, OPRÓCZ ... To musi być zrobione dla każdego okna. W .NET 3.5 nie było sposobu, aby ustawienie zaczęło obowiązywać w całej aplikacji. A jest kilka okien, na które nie będziesz mieć takiej kontroli - na przykład, kliknij prawym przyciskiem myszy okna "kontekstowe". Okazało się, że nie było dobre rozwiązanie dla .NET 3.5 z wyjątkiem ustawienia rejestru.

Edited

Oto logika użyliśmy do określenia, kiedy wymusić renderowania programowego. Zostało to zasugerowane przez inżyniera wsparcia Microsoft.

public bool ForceSoftwareRendering 
{ 
    get 
    { 
     int renderingTier = (System.Windows.Media.RenderCapability.Tier >> 16); 
     return renderingTier == 0; 
    } 
} 

W .NET 4 Microsoft dodał ustawienie dla całej aplikacji, które działa idealnie dla nas. Jest to znacznie lepsza opcja, ponieważ nie trzeba jej ustawiać w każdym oknie. Wystarczy ustawić go raz i dotyczy wszystkich okien.

http://msdn.microsoft.com/en-us/library/system.windows.media.renderoptions.processrendermode(VS.100).aspx

edytowany

Nowy .NET 4.0 nieruchomość może być ustawiona przy starcie aplikacji tak:

public partial class App : Application 
{ 
    protected override void OnStartup(StartupEventArgs e) 
    { 
     if (ForceSoftwareRendering) 
      RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; 
    } 
} 
+0

Skąd pochodzi "ForceSoftwareRendering"? Czy znalazłeś sposób na wykrycie, które komputery uległy awarii wraz z renderowaniem oprogramowania? –

+0

@EduardoWada Zaktualizuję odpowiedź, aby uwzględnić to. –

+0

czy ktoś wie coś tak samo, ale dla WinForms? – user1722669

2

wydarzenie -problem
Dla brakuje hwnd- źródło, wypróbuj następujące:

Dispatcher.BeginInvoke(new Action(delegate {    
     HwndSource hwndSource = PresentationSource.FromVisual(this) as System.Windows.Interop.HwndSource; 
      if (null == hwndSource) { 
       throw new InvalidOperationException("No HWND"); 
      } 
      HwndTarget hwndTarget = hwndSource.CompositionTarget; 
      hwndTarget.RenderMode = RenderMode.SoftwareOnly; 

    }),System.Windows.Threading.DispatcherPriority.ContextIdle, null); 

zakresu RenderMode
O ile mi wiadomo, jest tylko jedno okno Win32 dla każdego okna WPF i cała reszta staje się rodem w WPF. Dlatego uważam, że ustawienie RenderMode dotyczy wszystkich treści w oknie, w którym znajdował się obraz. Zakres jest w tym przypadku w całym oknie.

+0

dzięki. czy możesz wyjaśnić, dlaczego Dispatcher jest wymagany w tym przypadku? –

+0

@appu: Nie jest wymagana - ale jeśli hwnd nie jest obecny w czasie wykonania załadowanego zdarzenia (jeśli jest to problem), to czekając explicitely, aż system zakończy wszystko to ważne zadanie (takie jak renderowanie :) może pomóc. Widziałem już wiele nietypowych scenariuszy z problemami, które można rozwiązać w ten sposób. Ale to tylko pomysł, nie mogę zagwarantować, że to działa. Nawiasem mówiąc, używam powyższego kodu bez dyspozytora i do tej pory nie miałem problemu. Ale używam go tylko w jednej aplikacji i jest to rzadko używana opcja. Dlatego oświadczenie to na pewno nie jest reprezentatywne. – HCL

15

Można również wyłączyć renderowanie sprzętowe dla całego procesu poprzez umieszczenie następnego wiersza w programie obsługi uruchamiania aplikacji:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; 

Możliwe jest również, aby przełączyć się podczas wykonywania

+2

+1 dla możliwego przełączenia podczas pracy. Nie jest to od razu oczywiste z MSDN, ale jest to ważna informacja. – Charlie

+1

.Net 4.0 i wyższe –

Powiązane problemy