Override von Windows 10/11 Desktop-Skalierung in WPF

  • WPF MVVM
  • .NET (FX) 4.5–4.8

Es gibt 18 Antworten in diesem Thema. Der letzte Beitrag () ist von DTF.

    Override von Windows 10/11 Desktop-Skalierung in WPF

    Hallo miteinander,

    ich habe ein kleines Problem, und zwar wird mein Programm grafisch nicht optimal dargestellt, d.h. Text wird abgeschnitten usw., wenn ich eine andere Skalierung als 100% in den Windowseinstellungen festlege.

    Nun zur Frage:

    Ist es möglich, diese Einstellung nur für mein Programm programmatisch zu overriden?

    Also wie hier beschrieben (wobei selbst das bei mit nicht funzt, irgendwas mach ich falsch...):

    support.microsoft.com/de-de/wi…0f45938#ID0EBH=Windows_10

    Hier im Forum gibts ja ne Menge Posts zum Thema Skalierung, aber soweit ich gesehen habe, bezieht sich das alles auf WinForms....

    Ich wäre wirklich froh wenn mir hier einer helfen könnte.
    DPI Awareness:
    stackoverflow.com/questions/13…eness-for-wpf-application

    Schon nervig diese besch****** gemachte Skallierung. Schaut aus wie 800x600 pixel auf UHD, wo default 300% sind.(Die Bildqualität ist furchtbar)

    PS.
    Da ist es besser selbst eine eigene Skallierung einzubauen und den User Fontsize usw. selbst wählen zu lassen. Mit WPF zum Glück ein klacks.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D
    So hab bis jetzt drei Sachen probiert (von dem Link von @DTF), aber keine davon haben funktioniert:

    (1) Das hier in der AssemblyInfo.vb:

    [assembly: System.Windows.Media.DisableDpiAwareness]

    (2) Das hier in der App.manifest:

    XML-Quellcode

    1. <application xmlns="urn:schemas-microsoft-com:asm.v3">
    2. <windowsSettings>
    3. <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">false</dpiAware>
    4. </windowsSettings>
    5. </application>


    (3) Und den ganzen Inhalt des Fensters hab ich auch in eine Viewbox gelegt...

    Jetzt bleibt noch z.B. das hier:

    SetProcessDPIAware aufrufen:

    msdn.microsoft.com/en-gb/libra…op/ms633543(v=vs.85).aspx

    Aber wie aussieht, muss man da die user32.dll einbinden. Kann ich die denn einfach so ohne Gefahr einbinden? Bzw. kann ich sicher sein, dass mein User die dann auch tatsächlich hat?
    Ich hab mal vorsichtshalber versucht, eine Kopie davon über die Projekteigenschaften als Verweis zuzufügen, aber da kam ne Fehlermeldung, dass man diese dll net einbinden kann...

    Oder hat jemand doch noch ein funktinierendes Codeschnipsel?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Okay sieht vielversprechend aus. Aber wie wende ich das an? Ich will ja glaube ich die DPIAwareness auf False haben. Gibts da eine konträre Funktion, ich habe nichts gefunden...

    ...Bis auf das:
    learn.microsoft.com/en-us/wind…rocessdpiawarenesscontext
    Aber da komm ich auch ins Straucheln. Bis jetzt hab ich das:

    VB.NET-Quellcode

    1. Declare Function SetProcessDPIAwareness Lib "user32.dll" (value As DPI_AWARENESS_CONTEXT) As Boolean


    Da kommt "Der Typ DPI_AWARENESS_CONTEXT ist nicht definiert." und IntelliSense schlägt auch nix vor.
    Sorry hatte den zweiten Link übersehen.

    Edit: @petaod

    Hab jetzt Folgendes:

    VB.NET-Quellcode

    1. Public Enum PROCESS_DPI_AWARENESS
    2. PROCESS_DPI_UNAWARE = 0
    3. PROCESS_SYSTEM_DPI_AWARE = 1
    4. PROCESS_PER_MONITOR_DPI_AWARE = 2
    5. End Enum
    6. Class Application
    7. Declare Function SetProcessDpiAwarenessContext Lib "user32.dll" (ByVal value As PROCESS_DPI_AWARENESS) As Boolean
    8. Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
    9. SetProcessDpiAwarenessContext(PROCESS_DPI_AWARENESS.PROCESS_DPI_UNAWARE)
    10. End Function
    11. End Class


    Damit müsste es doch eigentlich gehen oder? ...tut es halt nicht...

    Deswegen bin ich etwas verwirrt weil ich hab ja:

    PROCESS_DPI_UNAWARE = 0

    und in den MS Docs heisst es:

    #define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)

    Wo kommt denn da das DPI_AWARENESS_CONTEXT her?

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „kafffee“ ()

    Ich habe das Problem auch mit meinen .NET Anwendungen.
    Kann man das hier auch verhindern, dass die Skalierung auf die eigene Anwendung/Form automatisch angewendet wird?
    Liebe Grüße
    Roland Berghöfer

    Meine aktuellen und kostenlos verwendbaren Tools (mit VB.NET erstellt): freeremarkabletools.com | priconman.com | SimpleCalendar | AudibleTouch | BOComponent.com | bonit.at
    @Der flotte Johann

    Auslesen kannst du so:

    VB.NET-Quellcode

    1. Private Function HoleScreenSkalierung() As Double
    2. Dim resHeight As Integer = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height
    3. Dim actualHeight As Integer = CInt(SystemParameters.PrimaryScreenHeight)
    4. Dim ratio As Double = actualHeight / resHeight
    5. Return resHeight / actualHeight
    6. End Function


    Edit an alle: Hab doch noch eine easy Lösung gefunden (über den Link von @DTF in Post #2):
    Folgende Klasse ins ViewModel:

    VB.NET-Quellcode

    1. Imports System.Windows
    2. Imports System.Windows.Controls
    3. Imports System.Windows.Media
    4. Namespace SkalierenVerhindern
    5. Public Class DpiDecorator
    6. Inherits Decorator
    7. Public Sub New()
    8. AddHandler Me.Loaded, AddressOf VerhindereSkalieren
    9. End Sub
    10. Public Function VerhindereSkalieren(s, e)
    11. Dim m As Matrix = PresentationSource.FromVisual(Me).CompositionTarget.TransformToDevice
    12. Dim dpiTransform As ScaleTransform = New ScaleTransform(1 / m.M11, 1 / m.M22)
    13. If dpiTransform.CanFreeze Then dpiTransform.Freeze()
    14. Me.LayoutTransform = dpiTransform
    15. End Function
    16. End Class
    17. End Namespace


    Dann in der MainWindow.xaml den Namespace (SkalierenVerhindern) importieren:

    Und um alles, was nicht skaliert werden soll (das wäre bei mir alles, also das äusserste Grid):

    XML-Quellcode

    1. <Skalierung:DpiDecorator>
    2. <Grid>
    3. <TextBlock Text="Dies ist ein Test!!"/>
    4. </Grid>
    5. </Skalierung:DpiDecorator>


    Dass die anderen Sachen nicht funtkioniert haben, lag wahrscheinlich daran, dass das auf irgend eine Weise veraltet ist, oder bzw. nur für manche Windows-Versionen gilt, wenn ihr mich fragt....

    Wie immer, danke an alle, die beigetragen haben :)

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „kafffee“ ()

    kafffee schrieb:

    Wo kommt denn da das DPI_AWARENESS_CONTEXT her?


    Wenn ein Funktionsname mit Set beginnt, lohnt es sich nach den Funktionsnamen, aber halt mit Get zu suchen.

    SetProcessDpiAwarenessContext:
    learn.microsoft.com/en-us/wind…rocessdpiawarenesscontext

    GetThreadDpiAwarenessContext:
    learn.microsoft.com/de-de/wind…threaddpiawarenesscontext

    GetProcessDpiAwareness:
    learn.microsoft.com/en-us/wind…pi-getprocessdpiawareness

    Ich kann dir mal nahelegen, solches WinAPI Zeug mit C++ und Konsole zu üben, in C++ ist das alles vorhanden, man muss nur die passenden Header includieren. Das macht alles einfacher, danach kann man das mit nem Fingerschnipp mit VB nachbauen. Solltest du mal einen Wert suchen, von irgendwas, weil du das in VB brauchst, auch eine C++ KonsolenApp und den Wert von irgendwas ausgeben. Ich kann gerade leider nicht schauen, ob ich das hinbekomme, hatte letzte Woche einen Mainboard und CPU Schaden, neues System steht jetzt und muss eingerichtet werden.(Das is ne umstellung auf Win11, vermisse das Startmenu, sonst Top)
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    Ja, eine Wrapper DLL kann man auch machen, genau so wie es die BassNet ist. Reicht aber auch eine Klasse die man sich dann zu jedem Projekt hinzufügen kann. NativeMethods ist ein guter Name für solch eine Klasse.

    PS. @kafffee nicht das es ein Missverständniss gab.
    Du musst nun nicht eine C++ dll machen, das wäre nicht nötig. So wie da die Deklarationen gemacht werden(C#), so deklarierst du die API funktionen in einer Klasse(und was dazu gehört), hast dann deinen "API-Wrapper".
    Zum üben meinte ich eine C++ Konsole. Mach damit einfach mal GetWindowRect und SetWindowRect, dann machste das in VB, kennst ja dann die Signaturen, musst halt noch schauen welcher Datentyp in Frage kommt. Aber das lernste mit der Zeit, irgendwann brauchste nur noch die C++ Doku und tippst das so runter.

    Schau einfach mal nach einem Tutorial wie man mit c++ in Windows ein Fenster erstellt, aber richtiges C++, kein Managed C++. Danach verstehst du Windows besser, geht mit der Nachrichtenschleife los und du lernst direkt die API kennen.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „DTF“ ()

    @DTF

    Weiss nicht ob dus gelesen hast:

    MIDI-Befehl zum Abspielen eines VST2-Plugins?

    Das heisst ich könnte mir die Funktionalität einer Funktion einer C++ dll sozusagen extrahieren und verwenden in meinem Projekt. Weil dann muss ich mir das echt genauer anschauen, das würde sich bei diesem Problem echt lohnen...
    Beachte oben meinen Edit, da warst du schneller. C++ ist sehr gut um Windows kennenzulernen, das schrieb ich ja eben. Fang mal mit so einem leeren Fenster an, dann buttons und klicks. Lass für den Anfang erstmal die RessourcenDatei weg, danach mal mit. Also am Anfang API pur. Du kannst auch DLLs laden und nutzen, wenn die DLL nativ ist, eine Wrapper klasse machen wie z.B. die BassNet.

    Ganz am Anfang, ist es evtl. leichter mit einer Konsolenanwendung.
    Zitat von mir 2023:
    Was interessiert mich Rechtschreibung? Der Compiler wird meckern wenn nötig :D