Обновление для CMake 3.0 и новее:
продолжение строки возможно с \
. см. cmake-3.0-doc
message("\
This is the first line of a quoted argument. \
In fact it is the only line but since it is long \
the source code uses line continuation.\
")
Debian Wheezy (2013): 2.8.9 Debian Wheezy-backports: 2.8 .11 Debian Jessy (2015): 3.0.2 Ubuntu 14.04 (LTS): 2.8.12 Ubuntu 15.04: 3.0.2 Mac OSX: cmake-3 доступен через Homebrew , Macports и Fink Windows: cmake-3 доступен через Chocolatey
Ну, для приложения ClickOnce, которое я развернул в прошлом, мы использовали пространство имен Microsoft.VisualBasic для обработки потока заставки. Вы можете ссылаться и использовать сборку Microsoft.VisualBasic из C # в .NET 2.0, и она предоставляет множество приятных сервисов.
protected override void OnCreateSplashScreen()
{
this.SplashScreen = new SplashForm();
this.SplashScreen.TopMost = true;
}
Очень просто, он показывает вашу SplashForm (которую вы должны создать) во время загрузки, а затем автоматически закрывает ее после того, как основная форма завершила загрузку.
Это действительно делает вещи простыми, и VisualBasic.WindowsFormsApplicationBase, конечно, хорошо протестирован Microsoft и имеет множество функций, которые могут сделать вашу жизнь намного проще в Winforms, даже в приложении, которое является 100% C #.
В конце концов, это все IL и байт-код в любом случае, так почему бы не использовать его?
Просматривая все решения Google и SO, это мой любимый: http://bytes.com/topic/c-sharp/answers/277446-winform-startup-splash-screen
FormSplash.cs:
public partial class FormSplash : Form
{
private static Thread _splashThread;
private static FormSplash _splashForm;
public FormSplash() {
InitializeComponent();
}
/// <summary>
/// Show the Splash Screen (Loading...)
/// </summary>
public static void ShowSplash()
{
if (_splashThread == null)
{
// show the form in a new thread
_splashThread = new Thread(new ThreadStart(DoShowSplash));
_splashThread.IsBackground = true;
_splashThread.Start();
}
}
// called by the thread
private static void DoShowSplash()
{
if (_splashForm == null)
_splashForm = new FormSplash();
// create a new message pump on this thread (started from ShowSplash)
Application.Run(_splashForm);
}
/// <summary>
/// Close the splash (Loading...) screen
/// </summary>
public static void CloseSplash()
{
// need to call on the thread that launched this splash
if (_splashForm.InvokeRequired)
_splashForm.Invoke(new MethodInvoker(CloseSplash));
else
Application.ExitThread();
}
}
Program.cs:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
// splash screen, which is terminated in FormMain
FormSplash.ShowSplash();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// this is probably where your heavy lifting is:
Application.Run(new FormMain());
}
}
FormMain.cs
...
public FormMain()
{
InitializeComponent();
// bunch of database access, form loading, etc
// this is where you could do the heavy lifting of "loading" the app
PullDataFromDatabase();
DoLoadingWork();
// ready to go, now close the splash
FormSplash.CloseSplash();
}
У меня было проблемы с решением Microsoft.VisualBasic
- работала находка на XP, но на сервере терминалов Windows 2003 основная форма приложения отображалась (после заставки) в фоновом режиме, а панель задач мигала. И приведение окна на передний план / фокус в коде - это целая другая червь червей, с которой вы можете использовать Google / SO.
Хитрость заключается в том, чтобы создать отдельный поток, отвечающий за отображение заставки. При запуске приложения .net создает основной поток и загружает указанную (основную) форму. Чтобы скрыть тяжелую работу, вы можете скрыть основную форму до завершения загрузки.
Предполагая, что Form1 - ваша основная форма, а SplashForm - верхний уровень, сглаживает приятную форму всплеска:
private void Form1_Load(object sender, EventArgs e)
{
Hide();
bool done = false;
ThreadPool.QueueUserWorkItem((x) =>
{
using (var splashForm = new SplashForm())
{
splashForm.Show();
while (!done)
Application.DoEvents();
splashForm.Close();
}
});
Thread.Sleep(3000); // Emulate hardwork
done = true;
Show();
}
Мне очень нравится ответ Aku, но код для C # 3.0 и выше, поскольку он использует функцию лямбда. Для людей, нуждающихся в использовании кода в C # 2.0, вот код, использующий анонимный делегат вместо функции лямбда. Вам нужна самая верхняя winform с именем formSplash
с FormBorderStyle = None
. Параметр TopMost = True
формы важен, потому что заставка может выглядеть так, как будто она появляется, а затем быстро исчезает, если она не самая верхняя. Я также выбираю StartPosition=CenterScreen
, поэтому он выглядит так, как профессиональное приложение будет делать с заставкой. Если вам нужен еще более холодный эффект, вы можете использовать свойство TrasparencyKey
, чтобы создать заставку неправильной формы.
private void formMain_Load(object sender, EventArgs e)
{
Hide();
bool done = false;
ThreadPool.QueueUserWorkItem(delegate
{
using (formSplash splashForm = new formSplash())
{
splashForm.Show();
while (!done)
Application.DoEvents();
splashForm.Close();
}
}, null);
Thread.Sleep(2000);
done = true;
Show();
}
Я не согласен с другими ответами, рекомендующими WindowsFormsApplicationBase
. По моему опыту, это может замедлить ваше приложение. Если быть точным, в то время как он запускает конструктор формы параллельно с заставкой, он откладывает событие Shown.
Рассмотрите приложение (без экрана всплесков) с конструктором, который занимает 1 секунду, и обработчик события на Показано, что занимает 2 секунды. Это приложение можно использовать через 3 секунды.
Но предположим, что вы устанавливаете заставку с помощью WindowsFormsApplicationBase
. Вы можете подумать, что MinimumSplashScreenDisplayTime
из 3 секунд разумно и не замедлит ваше приложение. Но попробуйте, ваше приложение теперь займет 5 секунд.
class App : WindowsFormsApplicationBase
{
protected override void OnCreateSplashScreen()
{
this.MinimumSplashScreenDisplayTime = 3000; // milliseconds
this.SplashScreen = new Splash();
}
protected override void OnCreateMainForm()
{
this.MainForm = new Form1();
}
}
и
public Form1()
{
InitializeComponent();
Shown += Form1_Shown;
Thread.Sleep(TimeSpan.FromSeconds(1));
}
void Form1_Shown(object sender, EventArgs e)
{
Thread.Sleep(TimeSpan.FromSeconds(2));
Program.watch.Stop();
this.textBox1.Text = Program.watch.ElapsedMilliseconds.ToString();
}
Вывод: не используйте WindowsFormsApplicationBase
, если ваше приложение имеет обработчик в событии Slown. Вы можете написать лучший код, который запускает всплеск параллельно как конструктору, так и событию Shown.
Я думаю, что использование некоторого метода, такого как aku's или Guy's , - это путь, но несколько вещей, которые нужно убрать из конкретных примеров:
Наконец, я бы предпочел создать splash (если не использовать перегрузку VB) в основном методе вашего кода. Для меня это лучше, чем если бы основная форма выполняла создание объекта и была настолько тесно связана с ним. Если вы примете такой подход, я бы предложил создать простой интерфейс, который реализует экран заставки - что-то вроде IStartupProgressListener - который получает обновления прогона обновления через функцию-член. Это позволит вам легко переключаться в любом классе по мере необходимости и красиво отделять код. Форма всплеска также может знать, когда закрыть себя, если вы сообщите, когда пуск завершен.
Я рекомендую вызывать Activate();
непосредственно после последнего Show();
в ответе, предоставленном aku.
Цитата MSDN:
Активация формы приводит ее к если это активное приложение, или мигает заголовок окна, если это не активное приложение. Форма должна быть видимой для этого эффекта.
blockquote>Если вы не активируете свою основную форму, она может отображаться за любыми другими открытыми окнами , что делает его немного глупым.
На самом деле mutlithreading здесь не требуется.
Пусть ваша бизнес-логика генерирует событие всякий раз, когда вы хотите обновить заставку.
Затем пусть ваша форма обновит заставку соответствующим образом в методе, подключенном к обработчику событий.
Чтобы различать обновления, вы можете запускать разные события или предоставлять данные в классе, унаследованном от EventArgs.
Таким образом, у вас может быть приятный сменный всплеск без какой-либо многопоточной головной боли.
Фактически с этим вы можете даже поддерживать, например, gif-изображение в форме всплеска. Чтобы он работал, вызовите Application.DoEvents () в вашем обработчике:
private void SomethingChanged(object sender, MyEventArgs e)
{
formSplash.Update(e);
Application.DoEvents(); //this will update any animation
}
Это старый вопрос, но я все время сталкивался с ним, пытаясь найти решение для WPF с многопоточным экраном, которое могло бы включать анимацию.
Вот что я в итоге собрал вместе:
App.XAML:
<Application Startup="ApplicationStart" …
App.XAML.cs:
void ApplicationStart(object sender, StartupEventArgs e)
{
var thread = new Thread(() =>
{
Dispatcher.CurrentDispatcher.BeginInvoke ((Action)(() => new MySplashForm().Show()));
Dispatcher.Run();
});
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
// call synchronous configuration process
// and declare/get reference to "main form"
thread.Abort();
mainForm.Show();
mainForm.Activate();
}
Я опубликовал статью о включении заставки в приложении в codeproject. Он многопоточен и может вас заинтересовать
private void MainForm_Load(object sender, EventArgs e)
{
FormSplash splash = new FormSplash();
splash.Show();
splash.Update();
System.Threading.Thread.Sleep(3000);
splash.Hide();
}
Я получил это из Интернета где-то, но не могу найти его снова. Простой, но эффективный.
Один простой способ - использовать это как main ():
<STAThread()> Public Shared Sub Main()
splash = New frmSplash
splash.Show()
' Your startup code goes here...
UpdateSplashAndLogMessage("Startup part 1 done...")
' ... and more as needed...
splash.Hide()
Application.Run(myMainForm)
End Sub
Когда .NET CLR запускает ваше приложение, он создает «основной» поток и начинает выполнение вашего основного () по этой теме. Application.Run (myMainForm) в конце делает две вещи:
Нет необходимости запускать нить, чтобы заботиться о всплывающем окне, и на самом деле это плохая идея, потому что тогда вам придется использовать поточно-безопасные методы для обновления содержимого всплеска из main ().
Если вам нужно другие темы для фоновых операций в вашем приложении, вы можете создать их из main (). Не забудьте установить Thread.IsBackground в значение True, чтобы они погибли, когда поток main / GUI завершился. В противном случае вам придется договориться о завершении всех ваших других потоков самостоятельно или они будут поддерживать ваше приложение в живых (но без графического интерфейса), когда основной поток завершается.