سؤال

كيف يمكنني إحضار تطبيق WPF الخاص بي إلى مقدمة سطح المكتب؟لقد حاولت حتى الآن:

SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);

SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);

لا أحد منهم يقوم بهذه المهمة (Marshal.GetLastWin32Error() يقول أن هذه العمليات قد اكتملت بنجاح، وأن سمات P/Invine لكل تعريف موجودة SetLastError=true).

إذا قمت بإنشاء تطبيق WPF فارغ جديد، واتصل SwitchToThisWindow باستخدام المؤقت، يعمل تمامًا كما هو متوقع، لذا لست متأكدًا من سبب عدم عمله في حالتي الأصلية.

يحرر:أفعل هذا بالتزامن مع مفتاح التشغيل السريع العالمي.

هل كانت مفيدة؟

المحلول 11

وحسنا أنا أحسب عمل حول. أنا جعل المكالمة من ربط لوحة المفاتيح المستخدمة لتنفيذ هوتكي. تعمل هذه الدعوة كما هو متوقع إذا وضعت قبل أن تتحول إلى BackgroundWorker مع وقفة. انها حل مشكلة، ولكن ليس لدي فكرة لماذا لا يعمل أصلا.

void hotkey_execute()
{
    IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(delegate
        {
            Thread.Sleep(10);
            SwitchToThisWindow(handle, true);
        });
    bg.RunWorkerAsync();
}

نصائح أخرى

myWindow.Activate();

محاولات لجعل النافذة إلى المقدمة وينشط فيه.

وهذا ينبغي أن تفعل خدعة، إلا إذا كنت أسيء فهمها وتريد دائما على السلوك أعلى. في هذه الحالة تريد:

myWindow.TopMost = true;

ولقد وجدت الحل الذي يجلب نافذة إلى أعلى، ولكنه يتصرف على إطار عادي:

if (!Window.IsVisible)
{
    Window.Show();
}

if (Window.WindowState == WindowState.Minimized)
{
    Window.WindowState = WindowState.Normal;
}

Window.Activate();
Window.Topmost = true;  // important
Window.Topmost = false; // important
Window.Focus();         // important

في حال كنت بحاجة النافذة لتكون أمام أول مرة يقوم بتحميل ثم يجب عليك استخدام ما يلي:

private void Window_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
}

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}

لجعل هذا سريعة النسخ واللصق واحد - منتديات تستخدم هذه الفئة 'طريقة DoOnProcess لتحريك عملية "النافذة الرئيسية لالمقدمة (ولكن ليس لسرقة التركيز من النوافذ الأخرى)

public class MoveToForeground
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);

    const int SWP_NOMOVE        = 0x0002;
    const int SWP_NOSIZE        = 0x0001;            
    const int SWP_SHOWWINDOW    = 0x0040;
    const int SWP_NOACTIVATE    = 0x0010;
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    public static void DoOnProcess(string processName)
    {
        var allProcs = Process.GetProcessesByName(processName);
        if (allProcs.Length > 0)
        {
            Process proc = allProcs[0];
            int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
            // Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
            SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
        }
    }
}

وHTH

وأعرف أن هذا السؤال هو قديمة نوعا ما، ولكن جئت للتو عبر هذا السيناريو الدقيق وأراد أن يشارك الحل لقد تنفيذها.

وكما ذكر في تعليقات على هذه الصفحة، والعديد من الحلول المقترحة لا تعمل على XP، وأنا بحاجة إلى دعم في السيناريو بلدي. بينما أنا أتفق مع المشاعر التي كتبهاMatthew كزافييه أن عموما هذا هو ممارسة سيئة UX، هناك أوقات حيث انها تماما على UX plausable.

وقدمت الحل لجلب نافذة WPF إلى الأعلى الواقع لي نفس رمز أنا باستخدام لتوفير هوتكي العالمي. مادة بلوق من قبل جوزيف كوني يحتوي على href="https://bitbucket.org/josephcooney/learnwpf.com.samples"> الرابط الذي يحتوي على التعليمات البرمجية الأصلية.

ولقد تنظيف وتعديل قانون قليلا، وتنفيذه باعتباره طريقة التمديد لSystem.Windows.Window. لقد اختبرت هذا على XP 32 بت و Win7 64 بت، وكلاهما يعمل بشكل صحيح.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace System.Windows
{
    public static class SystemWindows
    {
        #region Constants

        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 SWP_SHOWWINDOW = 0x0040;

        #endregion

        /// <summary>
        /// Activate a window from anywhere by attaching to the foreground window
        /// </summary>
        public static void GlobalActivate(this Window w)
        {
            //Get the process ID for this window's thread
            var interopHelper = new WindowInteropHelper(w);
            var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);

            //Get the process ID for the foreground window's thread
            var currentForegroundWindow = GetForegroundWindow();
            var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            //Attach this window's thread to the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            //Set the window position
            SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

            //Detach this window's thread from the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            //Show and activate the window
            if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
            w.Show();
            w.Activate();
        }

        #region Imports

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion
    }
}

وآمل أن يكون هذا يساعد الرمز الآخرين الذين يواجهون هذه المشكلة.

إذا كان المستخدم يتفاعل مع تطبيق آخر، فقد لا يكون من الممكن عرض تطبيقك في المقدمة.كقاعدة عامة، لا يمكن للعملية أن تتوقع تعيين النافذة الأمامية إلا إذا كانت هذه العملية هي العملية الأمامية بالفعل.(توثق Microsoft القيود في ملف سيتفورجروند ويندوو () إدخال MSDN.) وذلك للأسباب التالية:

  1. المستخدم "يمتلك" المقدمة.على سبيل المثال، سيكون الأمر مزعجًا للغاية إذا سرق برنامج آخر المقدمة أثناء قيام المستخدم بالكتابة، على الأقل مقاطعة سير عمله، وربما يتسبب في عواقب غير مقصودة حيث أن ضغطات المفاتيح المخصصة لتطبيق واحد يساء تفسيرها من قبل المخالف حتى تلاحظ التغيير .
  2. تخيل أن كل برنامج من البرنامجين يتحقق لمعرفة ما إذا كانت نافذته هي المقدمة ويحاول تعيينها في المقدمة إذا لم تكن كذلك.بمجرد تشغيل البرنامج الثاني، يصبح الكمبيوتر عديم الفائدة حيث ترتد المقدمة بين الاثنين عند كل تبديل مهمة.

ولقد كان لي مشكلة مماثلة مع تطبيق WPF أن يحصل على استدعاء من تطبيق Access عبر الكائن شل.

وبلدي الحل هو التالي - يعمل في XP و Win7 إلى x64 مع التطبيق المترجمة إلى الهدف إلى x86

.

ويهمني كثيرا بدلا من القيام بذلك من محاكاة بديل التبويب.

void Window_Loaded(object sender, RoutedEventArgs e)
{
    // make sure the window is normal or maximised
    // this was the core of the problem for me;
    // even though the default was "Normal", starting it via shell minimised it
    this.WindowState = WindowState.Normal;

    // only required for some scenarios
    this.Activate();
}

وأنا أعلم أن هذا هو وقت متأخر من الجواب، وربما مفيدة للباحثين

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }

لماذا بعض الإجابات في هذه الصفحة خاطئة!

  • أي إجابة تستخدم window.Focus() خطأ.

    • لماذا؟إذا ظهرت رسالة إعلام، window.Focus() سوف يجذب التركيز بعيدًا عن كل ما يكتبه المستخدم في ذلك الوقت.وهذا أمر محبط بجنون للمستخدمين النهائيين، خاصة إذا كانت النوافذ المنبثقة تحدث بشكل متكرر.
  • أي إجابة تستخدم window.Activate() خطأ.

    • لماذا؟سيجعل أي نوافذ رئيسية مرئية أيضًا.
  • أي إجابة تغفل window.ShowActivated = false خطأ.
    • لماذا؟سوف يجذب التركيز بعيدًا عن نافذة أخرى عندما تنبثق الرسالة وهو أمر مزعج للغاية!
  • أي إجابة لا تستخدم Visibility.Visible لإخفاء/إظهار النافذة خطأ.
    • لماذا؟إذا كنا نستخدم Citrix، إذا لم يتم طي النافذة عند إغلاقها، فسوف تترك مستطيلًا أسود غريبًا على الشاشة.وبالتالي، لا يمكننا استخدام window.Show() و window.Hide().

بشكل أساسي:

  • يجب ألا تقوم النافذة بجذب التركيز بعيدًا عن أي نافذة أخرى عند تنشيطها؛
  • يجب ألا تقوم النافذة بتنشيط الأصل الخاص بها عند ظهورها؛
  • يجب أن تكون النافذة متوافقة مع Citrix.

حل MVVM

هذا الرمز متوافق بنسبة 100% مع Citrix (لا توجد مناطق فارغة في الشاشة).تم اختباره باستخدام كل من WPF وDevExpress العاديين.

هذه الإجابة مخصصة لأي حالة استخدام حيث نريد نافذة إعلام صغيرة تكون دائمًا أمام النوافذ الأخرى (إذا قام المستخدم بتحديد ذلك في التفضيلات).

إذا كانت هذه الإجابة تبدو أكثر تعقيدًا من غيرها، فذلك لأنها رمز قوي على مستوى المؤسسة.بعض الإجابات الأخرى في هذه الصفحة بسيطة، ولكنها لا تعمل في الواقع.

XAML - الخاصية المرفقة

أضف هذه الخاصية المرفقة إلى أي UserControl داخل النافذة.الخاصية المرفقة سوف:

  • انتظر حتى Loaded يتم إطلاق الحدث (وإلا فلن يتمكن من البحث عن الشجرة المرئية للعثور على النافذة الرئيسية).
  • أضف معالج حدث يضمن أن تكون النافذة مرئية أم لا.

في أي وقت، يمكنك ضبط النافذة لتكون في المقدمة أم لا، عن طريق قلب قيمة الخاصية المرفقة.

<UserControl x:Class="..."
         ...
         attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
             "{Binding EnsureWindowInForeground, Mode=OneWay}">

C# - الطريقة المساعدة

public static class HideAndShowWindowHelper
{
    /// <summary>
    ///     Intent: Ensure that small notification window is on top of other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoForeground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Visible)
            {
                window.Visibility = Visibility.Visible;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = true;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }

    /// <summary>
    ///     Intent: Ensure that small notification window can be hidden by other windows.
    /// </summary>
    /// <param name="window"></param>
    public static void ShiftWindowIntoBackground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Collapsed)
            {
                window.Visibility = Visibility.Collapsed;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = false;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }
}

الاستخدام

لاستخدام هذا، تحتاج إلى إنشاء النافذة في ViewModel الخاص بك:

private ToastView _toastViewWindow;
private void ShowWindow()
{
    if (_toastViewWindow == null)
    {
        _toastViewWindow = new ToastView();
        _dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
    }
    ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
    HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}

private void HideWindow()
{
    if (_toastViewWindow != null)
    {
        HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
    }
}

روابط إضافية

للحصول على نصائح حول كيفية التأكد من عودة نافذة الإشعارات دائمًا إلى الشاشة المرئية، راجع إجابتي: في WPF، كيفية تحويل نافذة إلى الشاشة إذا كانت خارج الشاشة؟.

حسنا، لأن هذا هو مثل هذا الموضوع الساخن ... هنا هو ما يعمل بالنسبة لي. حصلت أخطاء إذا لم تفعل ذلك بهذه الطريقة لتنشيط () سوف خطأ خارجا على لك إذا كنت لا تستطيع رؤية نافذة.

وXAML:

<Window .... 
        Topmost="True" 
        .... 
        ContentRendered="mainWindow_ContentRendered"> .... </Window>

وCodebehind:

private void mainWindow_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
    this.Activate();
    _UsernameTextBox.Focus();
}

وكانت هذه هي الطريقة الوحيدة بالنسبة لي للحصول على نافذة لعرضها على القمة. ثم تفعيلها بحيث يمكنك كتابة في مربع دون الحاجة إلى تعيين التركيز مع الماوس. control.Focus () لن يعمل إلا إذا كان الإطار النشط ()؛

لإظهار أي المفتوحة حاليا نافذة استيراد تلك DLL:

public partial class Form1 : Form
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);
    [DllImportAttribute("User32.dll")]
    private static extern int SetForegroundWindow(int hWnd);

ووفي برنامج نحن نبحث عن التطبيق مع عنوان محدد (عنوان الكتابة دون الحرف الأول (مؤشر> 0))

  foreach (Process proc in Process.GetProcesses())
                {
                    tx = proc.MainWindowTitle.ToString();
                    if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
                    {
                        tx = proc.MainWindowTitle;
                        hWnd = proc.Handle.ToInt32(); break;
                    }
                }
                hWnd = FindWindow(null, tx);
                if (hWnd > 0)
                {
                    SetForegroundWindow(hWnd);
                }

ويمكن أن تكون المشكلة أن موضوع استدعاء التعليمات البرمجية الخاصة بك من ورطتها لم تتم تهيئة قبل وقت يدعو لذلك أساليب وقت التشغيل لا تعمل.

وربما قد تتمكن من محاولة القيام على استدعاء لحشد التعليمات البرمجية إلى موضوع UI لاستدعاء التعليمات البرمجية التي يجلب نافذة إلى المقدمة.

وهذه الرموز سوف تعمل بشكل جيد جميع الأوقات.

في البداية تعيين معالج الحدث تفعيلها في XAML:

Activated="Window_Activated"

إضافة إلى تحت خط الرئيسي كتلة النافذة منشئ الخاص بك:

public MainWindow()
{
    InitializeComponent();
    this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}

وداخل معالج الحدث تنشيط نسخ هذه الرموز:

private void Window_Activated(object sender, EventArgs e)
{
    if (Application.Current.Windows.Count > 1)
    {
        foreach (Window win in Application.Current.Windows)
            try
            {
                if (!win.Equals(this))
                {
                    if (!win.IsVisible)
                    {
                        win.ShowDialog();
                    }

                    if (win.WindowState == WindowState.Minimized)
                    {
                        win.WindowState = WindowState.Normal;
                    }

                    win.Activate();
                    win.Topmost = true;
                    win.Topmost = false;
                    win.Focus();
                }
            }
            catch { }
    }
    else
        this.Focus();
}

وهذه الخطوات سوف يعمل بشكل جيد، وسوف تجلب إلى الأمام جميع النوافذ الأخرى في نافذة والديهم.

إذا كنت تحاول إخفاء النافذة، على سبيل المثال يمكنك تصغير النافذة، ولقد وجدت أن استخدام

    this.Hide();

وسوف إخفائه بشكل صحيح، ثم ببساطة باستخدام

    this.Show();

وبعد ذلك سوف تظهر نافذة كأفضل معظم البند مرة أخرى.

وأردت فقط أن إضافة حل آخر لهذه المسألة. هذا التطبيق يعمل لبلدي السيناريو، حيث CaliBurn المسؤول عن عرض النافذة الرئيسية.

protected override void OnStartup(object sender, StartupEventArgs e)
{
    DisplayRootViewFor<IMainWindowViewModel>();

    Application.MainWindow.Topmost = true;
    Application.MainWindow.Activate();
    Application.MainWindow.Activated += OnMainWindowActivated;
}

private static void OnMainWindowActivated(object sender, EventArgs e)
{
    var window = sender as Window;
    if (window != null)
    {
        window.Activated -= OnMainWindowActivated;
        window.Topmost = false;
        window.Focus();
    }
}

وتذكر عدم وضع التعليمات البرمجية التي تظهر تلك النافذة داخل معالج PreviewMouseDoubleClick كما الإطار النشط ستتحول إلى نافذة الذين عالجوا هذا الحدث. مجرد وضعها في معالج الأحداث MouseDoubleClick أو وقف السطح من خلال وضع e.Handled إلى True.

في حالتي أنا كان التعامل مع PreviewMouseDoubleClick على Listview ولم يكن وضع e.Handled = صحيح ثم رفع ساحرة الحدث MouseDoubleClick جلس التركيز مرة أخرى إلى الإطار الأصلي.

ولقد بنيت طريقة التمديد لجعل لسهولة إعادة استخدامها.

using System.Windows.Forms;
    namespace YourNamespace{
        public static class WindowsFormExtensions {
            public static void PutOnTop(this Form form) {
                form.Show();
                form.Activate();
            }// END PutOnTop()       
        }// END class
    }// END namespace

والدعوة في منشئ نموذج

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top