0

在我的主类中,我创建了一个 wpf 窗口(p)和一个函数,用于在标签(内容)中显示带有给定消息的窗口。

public partial class MainWindow : Window
{
    ///Creates Window
    public static Wils0n.Window1 p = new Wils0n.Window1();

    /// <summary>
    /// creates notif bar with message
    /// </summary>
    /// <param name="message">Message for notif bar</param>
    public static void NotifProc(string message)
    {
        ///sets global string to message
        Commands.MyGlobals.inputtext = message;

        p.Dispatcher.Invoke(new Action(delegate ()
        {
        MainWindow.p.Topmost = true;
        MainWindow.p.Top = 0;

        ///sets label content to global string (this only works once)
        MainWindow.p.content.Content = Commands.MyGlobals.inputtext;

        MainWindow.p.Left = System.Windows.SystemParameters.WorkArea.Width / 2 - (MainWindow.p.Width / 2);
        MainWindow.p.Show();
        Thread.Sleep(2000);
        while (MainWindow.p.Top != -114)
        {
            MainWindow.p.Top -= 3;
            Thread.Sleep(15);
        }
        MainWindow.p.Hide();
        }
        ));
    }
}

然后在另一个命名空间的另一个类中,我这样称呼它..

namespace Wilson.Utils
{
    class Commands
    {
        public void start()
        {
             ///creates notification window thats reads "hello world"
             MainWindow.NotifProc("hello world");

             ///creates notification window thats reads "test1"
             ///For some reason reads "hello world"
             MainWindow.NotifProc("test1");

             ///creates notification window thats reads "test2"
             ///For some reason reads "hello world"
             MainWindow.NotifProc("test2");            
        }

        ///creates global string
        public static class MyGlobals
        {
            public static string inputtext = "";
        }
    }
}

这仅在第一次时工作得很好,如果我用不同的消息再次调用它,它不会更新消息,但通知仍然有效,它只会显示旧消息。

我也有这个问题,改变MainWindow.p.OpacityMainWindow.p.Background

如果没有 Dispatcher.Invoke,我会收到错误消息“无法访问对象,因为不同的线程拥有它”。

如果我删除Commands.MyGlobals.inputtext = message;并放在它Commans.MyGlobals.inputtext = "test1"之前MainWindow.NotifProc("test1");仍然不起作用。

我也尝试过创建这样的类:

public static class ExtensionMethods
{
    private static Action EmptyDelegate = delegate () { };

    public static void Refresh(this UIElement uiElement)
    {
        uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
    }
}

并添加:

p.content.Refresh();

但没有运气。任何帮助都会很棒。:/

编辑

尽管它可能不是最好的,但我设法找到了解决方法:每次调用窗口动画时,我都会创建一个新窗口,而不是在开始时创建一个新窗口。VS 说线程必须是 STA,所以我在 STA 线程中调用它,最后我在窗口动画的末尾添加了一个检查,以便在第一个完成之前不能创建新窗口。

我的新 NotifProc 函数如下所示:

    public static void NotifProc(string message)
    {
        Tools.MyGlobals.notifmessage = message;
        var thread = new Thread(new ThreadStart(STAThread));
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        thread.Join();
    }
    private static void STAThread()
    {
        Wils0n.Window1 p = new Wils0n.Window1();
        p.content.Content = Tools.MyGlobals.notifmessage;
        p.content.Refresh();
        p.Topmost = true;
        p.Top = 0;
        p.Left = System.Windows.SystemParameters.WorkArea.Width / 2 - (p.Width / 2);
        p.Show();

        Thread.Sleep(2000);
        while (p.Top != -114)
        {
            p.Top -= 3;
            Thread.Sleep(15);
        }
        p.Close();
    }
4

1 回答 1

0

与其调用Thread.SleepUI 线程并因此阻塞它,不如简单地为 Window 位置设置动画,如下所示:

public static void NotifProc(string message)
{
    p.Content.Content = message;
    p.Left = SystemParameters.WorkArea.Width / 2 - (p.Width / 2);
    p.Top = 0;
    p.Topmost = true;
    p.Show();

    var animation = new DoubleAnimation
    {
        To = -114,
        BeginTime = TimeSpan.FromSeconds(2),
        Duration = TimeSpan.FromSeconds(0.57)
    };

    animation.Completed += (s, e) => p.Hide();

    p.BeginAnimation(TopProperty, animation);
}

如果要从 UI 线程以外的线程调用该方法,请执行以下操作:

Application.Current.Dispatcher.Invoke(() => NotifProc(...));

或者

MainWindow.p.Dispatcher.Invoke(() => NotifProc(...));
于 2017-10-23T05:49:02.557 回答