В моем основном классе я создаю окно 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.Opacity
и MainWindow.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();
}
Dispatcher.Invoke
не создает новый поток, а просто запускает делегат в потоке пользовательского интерфейса. Однако поток пользовательского интерфейса блокируется вызовом Thread.Sleep. Вместо этого используйтеawait Task.Delay(...)
. - person Clemens   schedule 23.10.2017