Add Fluent MessageBoxes

thats a lot of updated files huh
This commit is contained in:
pizzaboxer 2023-06-29 17:54:05 +01:00
parent d27ca05c32
commit 5ef20a79c7
No known key found for this signature in database
GPG Key ID: 59D4A1DBAD0F2BA8
22 changed files with 371 additions and 130 deletions

View File

@ -17,8 +17,9 @@ using Bloxstrap.Extensions;
using Bloxstrap.Models;
using Bloxstrap.Models.Attributes;
using Bloxstrap.UI.BootstrapperDialogs;
using Bloxstrap.UI.Menu.Views;
using Bloxstrap.UI.MessageBox;
using Bloxstrap.Utility;
using Bloxstrap.UI;
namespace Bloxstrap
{
@ -57,15 +58,6 @@ namespace Bloxstrap
public static System.Windows.Forms.NotifyIcon Notification { get; private set; } = null!;
// shorthand
public static MessageBoxResult ShowMessageBox(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK)
{
if (IsQuiet)
return MessageBoxResult.None;
return MessageBox.Show(message, ProjectName, buttons, icon);
}
public static void Terminate(int code = Bootstrapper.ERROR_SUCCESS)
{
Logger.WriteLine($"[App::Terminate] Terminating with exit code {code}");
@ -198,7 +190,7 @@ namespace Bloxstrap
{
IsSetupComplete = false;
FastFlags.Load();
new MainWindow().ShowDialog();
Controls.ShowMenu();
}
}
else
@ -246,10 +238,13 @@ namespace Bloxstrap
}
else
{
if (Process.GetProcessesByName(ProjectName).Length > 1)
ShowMessageBox($"{ProjectName} is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances.", MessageBoxImage.Information);
if (Process.GetProcessesByName(ProjectName).Length > 1 && !IsQuiet)
FluentMessageBox.Show(
$"{ProjectName} is currently running, likely as a background Roblox process. Please note that not all your changes will immediately apply until you close all currently open Roblox instances.",
MessageBoxImage.Information
);
new MainWindow().ShowDialog();
Controls.ShowMenu();
}
}
else if (LaunchArgs.Length > 0)
@ -261,7 +256,10 @@ namespace Bloxstrap
else if (LaunchArgs[0].StartsWith("roblox:"))
{
if (Settings.Prop.UseDisableAppPatch)
ShowMessageBox("Roblox was launched via a deeplink, however the desktop app is required for deeplink launching to work. Because you've opted to disable the desktop app, it will temporarily be re-enabled for this launch only.", MessageBoxImage.Information);
Controls.ShowMessageBox(
"Roblox was launched via a deeplink, however the desktop app is required for deeplink launching to work. Because you've opted to disable the desktop app, it will temporarily be re-enabled for this launch only.",
MessageBoxImage.Information
);
commandLine = $"--app --deeplink {LaunchArgs[0]}";
}

View File

@ -17,6 +17,10 @@
<Resource Include="Resources\Fonts\Rubik-VariableFont_wght.ttf" />
<Resource Include="Resources\BootstrapperStyles\ByfronDialog\ByfronLogoDark.jpg" />
<Resource Include="Resources\BootstrapperStyles\ByfronDialog\ByfronLogoLight.jpg" />
<Resource Include="Resources\MessageBox\Error.png" />
<Resource Include="Resources\MessageBox\Information.png" />
<Resource Include="Resources\MessageBox\Question.png" />
<Resource Include="Resources\MessageBox\Warning.png" />
</ItemGroup>
<ItemGroup>

View File

@ -17,6 +17,7 @@ using Bloxstrap.Extensions;
using Bloxstrap.Integrations;
using Bloxstrap.Models;
using Bloxstrap.Tools;
using Bloxstrap.UI;
using Bloxstrap.UI.BootstrapperDialogs;
namespace Bloxstrap
@ -126,6 +127,8 @@ namespace Bloxstrap
{
App.Logger.WriteLine("[Bootstrapper::Run] Running bootstrapper");
Controls.ShowMessageBox("hi :D", MessageBoxImage.Error, MessageBoxButton.YesNoCancel);
if (App.IsUninstall)
{
Uninstall();
@ -230,7 +233,9 @@ namespace Bloxstrap
if (!String.IsNullOrEmpty(switchDefaultPrompt))
{
MessageBoxResult result = App.Settings.Prop.ChannelChangeMode == ChannelChangeMode.Automatic ? MessageBoxResult.Yes : App.ShowMessageBox(switchDefaultPrompt, MessageBoxImage.Question, MessageBoxButton.YesNo);
MessageBoxResult result = App.Settings.Prop.ChannelChangeMode == ChannelChangeMode.Prompt
? Controls.ShowMessageBox(switchDefaultPrompt, MessageBoxImage.Question, MessageBoxButton.YesNo)
: MessageBoxResult.Yes;
if (result == MessageBoxResult.Yes)
{
@ -263,7 +268,10 @@ namespace Bloxstrap
if (!File.Exists("C:\\Windows\\System32\\mfplat.dll"))
{
App.ShowMessageBox("Roblox requires the use of Windows Media Foundation components. You appear to be missing them, likely because you are using an N edition of Windows. Please install them first, and then launch Roblox.", MessageBoxImage.Error);
Controls.ShowMessageBox(
"Roblox requires the use of Windows Media Foundation components. You appear to be missing them, likely because you are using an N edition of Windows. Please install them first, and then launch Roblox.",
MessageBoxImage.Error
);
Utilities.ShellExecute("https://support.microsoft.com/en-us/topic/media-feature-pack-list-for-windows-n-editions-c1c6fffa-d052-8338-7a79-a4bb980a700a");
Dialog?.CloseBootstrapper();
return;
@ -637,7 +645,14 @@ namespace Bloxstrap
{
App.Logger.WriteLine($"[Bootstrapper::Uninstall] Prompting to shut down all open Roblox instances");
Dialog?.PromptShutdown();
MessageBoxResult result = Controls.ShowMessageBox(
"Roblox is currently running, but must be closed before uninstalling Bloxstrap. Would you like close Roblox now?",
MessageBoxImage.Information,
MessageBoxButton.OKCancel
);
if (result != MessageBoxResult.OK)
Environment.Exit(ERROR_INSTALL_USEREXIT);
try
{
@ -742,7 +757,11 @@ namespace Bloxstrap
if (Utilities.GetFreeDiskSpace(Directories.Base) < totalSizeRequired)
{
App.ShowMessageBox($"{App.ProjectName} does not have enough disk space to download and install Roblox. Please free up some disk space and try again.", MessageBoxImage.Error);
Controls.ShowMessageBox(
$"{App.ProjectName} does not have enough disk space to download and install Roblox. Please free up some disk space and try again.",
MessageBoxImage.Error
);
App.Terminate(ERROR_INSTALL_FAILURE);
return;
}
@ -910,7 +929,7 @@ namespace Bloxstrap
if (File.Exists(injectorLocation))
{
App.ShowMessageBox(
Controls.ShowMessageBox(
"Roblox has now finished rolling out the new game client update, featuring 64-bit support and the Hyperion anticheat. ReShade does not work with this update, and so it has now been disabled and removed from Bloxstrap.\n\n"+
"Your ReShade configuration files will still be saved, and you can locate them by opening the folder where Bloxstrap is installed to, and navigating to the Integrations folder. You can choose to delete these if you want.",
MessageBoxImage.Warning

View File

@ -7,6 +7,7 @@ using System.Windows;
using Microsoft.Win32;
using Bloxstrap.Enums;
using Bloxstrap.UI;
namespace Bloxstrap
{
@ -59,7 +60,9 @@ namespace Bloxstrap
{
if (val.ToLowerInvariant() != App.Settings.Prop.Channel.ToLowerInvariant() && App.Settings.Prop.ChannelChangeMode != ChannelChangeMode.Ignore)
{
MessageBoxResult result = App.Settings.Prop.ChannelChangeMode == ChannelChangeMode.Automatic ? MessageBoxResult.Yes : App.ShowMessageBox(
MessageBoxResult result = App.Settings.Prop.ChannelChangeMode == ChannelChangeMode.Automatic
? MessageBoxResult.Yes
: Controls.ShowMessageBox(
$"{App.ProjectName} was launched with the Roblox build channel set to {val}, however your current preferred channel is {App.Settings.Prop.Channel}.\n\n" +
$"Would you like to switch channels from {App.Settings.Prop.Channel} to {val}?",
MessageBoxImage.Question,

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -0,0 +1,24 @@
using System;
using System.Windows;
namespace Bloxstrap.UI.BootstrapperDialogs
{
static class BaseFunctions
{
public static void ShowSuccess(string message, Action? callback)
{
Controls.ShowMessageBox(message, MessageBoxImage.Information);
if (callback is not null)
callback();
App.Terminate();
}
public static void ShowError(string message)
{
Controls.ShowMessageBox($"An error occurred while starting Roblox\n\nDetails: {message}", MessageBoxImage.Error);
App.Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
}
}
}

View File

@ -16,6 +16,5 @@ namespace Bloxstrap.UI.BootstrapperDialogs
void CloseBootstrapper();
void ShowSuccess(string message, Action? callback = null);
void ShowError(string message);
void PromptShutdown();
}
}

View File

@ -91,33 +91,9 @@ namespace Bloxstrap.UI.BootstrapperDialogs.WPF.Views
public void CloseBootstrapper() => Dispatcher.BeginInvoke(this.Close);
public void ShowSuccess(string message, Action? callback)
{
App.ShowMessageBox(message, MessageBoxImage.Information);
public void ShowSuccess(string message, Action? callback) => BaseFunctions.ShowSuccess(message, callback);
if (callback is not null)
callback();
App.Terminate();
}
public void ShowError(string message)
{
App.ShowMessageBox($"An error occurred while starting Roblox\n\nDetails: {message}", MessageBoxImage.Error);
App.Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
}
public void PromptShutdown()
{
MessageBoxResult result = App.ShowMessageBox(
"Roblox is currently running, but needs to close. Would you like close Roblox now?",
MessageBoxImage.Information,
MessageBoxButton.OKCancel
);
if (result != MessageBoxResult.OK)
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
}
public void ShowError(string message) => BaseFunctions.ShowError(message);
#endregion
}
}

View File

@ -24,7 +24,7 @@
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Margin="0,12,0,0" Width="48" Height="48" VerticalAlignment="Top">
<Border.Background>
<ImageBrush ImageSource="{Binding Icon, Mode=OneWay}" />
<ImageBrush ImageSource="{Binding Icon, Mode=OneWay}" RenderOptions.BitmapScalingMode="HighQuality" />
</Border.Background>
</Border>
<StackPanel Grid.Column="1">

View File

@ -84,34 +84,9 @@ namespace Bloxstrap.UI.BootstrapperDialogs.WPF.Views
public void CloseBootstrapper() => Dispatcher.BeginInvoke(this.Close);
// TODO: make prompts use dialog view natively rather than using message dialog boxes
public void ShowSuccess(string message, Action? callback) => BaseFunctions.ShowSuccess(message, callback);
public void ShowSuccess(string message, Action? callback)
{
App.ShowMessageBox(message, MessageBoxImage.Information);
if (callback is not null)
callback();
App.Terminate();
}
public void ShowError(string message)
{
App.ShowMessageBox($"An error occurred while starting Roblox\n\nDetails: {message}", MessageBoxImage.Error);
App.Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
}
public void PromptShutdown()
{
MessageBoxResult result = App.ShowMessageBox(
"Roblox is currently running, but needs to close. Would you like close Roblox now?",
MessageBoxImage.Information,
MessageBoxButton.OKCancel
);
if (result != MessageBoxResult.OK)
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
}
public void ShowError(string message) => BaseFunctions.ShowError(message);
#endregion
}
}

View File

@ -1,5 +1,4 @@
using System;
using System.Windows;
using System.Windows.Forms;
using Bloxstrap.Extensions;
@ -101,33 +100,9 @@ namespace Bloxstrap.UI.BootstrapperDialogs.WinForms
Close();
}
public virtual void ShowSuccess(string message, Action? callback)
{
App.ShowMessageBox(message, MessageBoxImage.Information);
public virtual void ShowSuccess(string message, Action? callback) => BaseFunctions.ShowSuccess(message, callback);
if (callback is not null)
callback();
App.Terminate();
}
public virtual void ShowError(string message)
{
App.ShowMessageBox($"An error occurred while starting Roblox\n\nDetails: {message}", MessageBoxImage.Error);
App.Terminate(Bootstrapper.ERROR_INSTALL_FAILURE);
}
public void PromptShutdown()
{
MessageBoxResult result = App.ShowMessageBox(
"Roblox is currently running, but needs to close. Would you like close Roblox now?",
MessageBoxImage.Information,
MessageBoxButton.OKCancel
);
if (result != MessageBoxResult.OK)
Environment.Exit(Bootstrapper.ERROR_INSTALL_USEREXIT);
}
public virtual void ShowError(string message) => BaseFunctions.ShowError(message);
#endregion
}
}

26
Bloxstrap/UI/Controls.cs Normal file
View File

@ -0,0 +1,26 @@
using System.Windows;
using Bloxstrap.Enums;
using Bloxstrap.UI.Menu.Views;
using Bloxstrap.UI.MessageBox;
namespace Bloxstrap.UI
{
static class Controls
{
public static void ShowMenu() => new MainWindow().ShowDialog();
public static MessageBoxResult ShowMessageBox(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxResult defaultResult = MessageBoxResult.None)
{
switch (App.Settings.Prop.BootstrapperStyle)
{
case BootstrapperStyle.FluentDialog:
case BootstrapperStyle.ByfronDialog:
return FluentMessageBox.Show(message, icon, buttons, defaultResult);
default:
return NativeMessageBox.Show(message, icon, buttons, defaultResult);
}
}
}
}

View File

@ -10,6 +10,8 @@ using CommunityToolkit.Mvvm.Input;
using Wpf.Ui.Controls.Interfaces;
using Wpf.Ui.Mvvm.Contracts;
using Bloxstrap.UI.MessageBox;
namespace Bloxstrap.UI.Menu.ViewModels
{
public class MainWindowViewModel
@ -35,7 +37,7 @@ namespace Bloxstrap.UI.Menu.ViewModels
{
if (string.IsNullOrEmpty(App.BaseDirectory))
{
App.ShowMessageBox("You must set an install location", MessageBoxImage.Error);
FluentMessageBox.Show("You must set an install location", MessageBoxImage.Error);
return;
}
@ -50,12 +52,15 @@ namespace Bloxstrap.UI.Menu.ViewModels
}
catch (UnauthorizedAccessException)
{
App.ShowMessageBox($"{App.ProjectName} does not have write access to the install location you selected. Please choose another install location.", MessageBoxImage.Error);
FluentMessageBox.Show(
$"{App.ProjectName} does not have write access to the install location you selected. Please choose another install location.",
MessageBoxImage.Error
);
return;
}
catch (Exception ex)
{
App.ShowMessageBox(ex.Message, MessageBoxImage.Error);
FluentMessageBox.Show(ex.Message, MessageBoxImage.Error);
return;
}
@ -67,7 +72,11 @@ namespace Bloxstrap.UI.Menu.ViewModels
if (App.BaseDirectory != _originalBaseDirectory)
{
App.Logger.WriteLine($"[MainWindowViewModel::ConfirmSettings] Changing install location from {_originalBaseDirectory} to {App.BaseDirectory}");
App.ShowMessageBox($"{App.ProjectName} will install to the new location you've set the next time it runs.", MessageBoxImage.Information);
FluentMessageBox.Show(
$"{App.ProjectName} will install to the new location you've set the next time it runs.",
MessageBoxImage.Information
);
using RegistryKey registryKey = Registry.CurrentUser.CreateSubKey($@"Software\{App.ProjectName}");
registryKey.SetValue("InstallLocation", App.BaseDirectory);

View File

@ -0,0 +1,47 @@
<ui:UiWindow x:Class="Bloxstrap.UI.MessageBox.FluentMessageBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
xmlns:local="clr-namespace:Bloxstrap.UI.MessageBox"
mc:Ignorable="d"
Title="Bloxstrap"
MinWidth="180"
MaxWidth="480"
Width="180"
MinHeight="160"
SizeToContent="Height"
ResizeMode="NoResize"
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
ExtendsContentIntoTitleBar="True"
WindowBackdropType="Mica"
WindowCornerPreference="Round"
WindowStartupLocation="CenterScreen">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" Background="{ui:ThemeResource ApplicationBackgroundBrush}" x:Name="RootTitleBar" Title="Bloxstrap" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" />
<Grid Grid.Row="1" Margin="15,15,15,15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image x:Name="IconImage" Grid.Column="0" RenderOptions.BitmapScalingMode="HighQuality" Width="32" Height="32" Margin="0,0,15,0" VerticalAlignment="Top" />
<TextBlock x:Name="MessageTextBlock" Grid.Column="1" VerticalAlignment="Center" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorPrimaryBrush}" />
</Grid>
<Border Grid.Row="2" Margin="0,10,0,0" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
<StackPanel Grid.Row="2" Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
<Button x:Name="ButtonOne" MinWidth="100" Content="Button 1" />
<Button x:Name="ButtonTwo" MinWidth="100" Margin="12,0,0,0" Content="Button 2" />
<Button x:Name="ButtonThree" MinWidth="100" Margin="12,0,0,0" Content="Button 3" />
</StackPanel>
</Border>
</Grid>
</ui:UiWindow>

View File

@ -0,0 +1,144 @@
using System;
using System.Configuration;
using System.Media;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media.Imaging;
using Bloxstrap.Utility;
namespace Bloxstrap.UI.MessageBox
{
// wpfui does have its own messagebox control but it SUCKS so heres this instead
/// <summary>
/// Interaction logic for FluentMessageBox.xaml
/// </summary>
public partial class FluentMessageBox
{
public MessageBoxResult Result = MessageBoxResult.None;
public static MessageBoxResult Show(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxResult defaultResult = MessageBoxResult.None)
{
if (App.IsQuiet)
return defaultResult;
// threading weirdness lol
MessageBoxResult result = Application.Current.Dispatcher.Invoke(new Func<MessageBoxResult>(() =>
{
var messagebox = new FluentMessageBox(message, icon, buttons);
messagebox.ShowDialog();
return messagebox.Result;
}));
return result;
}
public FluentMessageBox(string message, MessageBoxImage image, MessageBoxButton buttons)
{
InitializeComponent();
string? iconFilename = null;
SystemSound? sound = null;
switch (image)
{
case MessageBoxImage.Error:
iconFilename = "Error";
sound = SystemSounds.Hand;
break;
case MessageBoxImage.Question:
iconFilename = "Question";
sound = SystemSounds.Question;
break;
case MessageBoxImage.Warning:
iconFilename = "Warning";
sound = SystemSounds.Asterisk;
break;
case MessageBoxImage.Information:
iconFilename = "Information";
sound = SystemSounds.Asterisk;
break;
}
if (iconFilename is null)
IconImage.Visibility = Visibility.Collapsed;
else
IconImage.Source = new BitmapImage(new Uri($"pack://application:,,,/Resources/MessageBox/{iconFilename}.png"));
Title = App.ProjectName;
MessageTextBlock.Text = message;
ButtonOne.Visibility = Visibility.Collapsed;
ButtonTwo.Visibility = Visibility.Collapsed;
ButtonThree.Visibility = Visibility.Collapsed;
switch (buttons)
{
case MessageBoxButton.YesNo:
SetButton(ButtonOne, MessageBoxResult.Yes);
SetButton(ButtonTwo, MessageBoxResult.No);
break;
case MessageBoxButton.YesNoCancel:
SetButton(ButtonOne, MessageBoxResult.Yes);
SetButton(ButtonTwo, MessageBoxResult.No);
SetButton(ButtonThree, MessageBoxResult.Cancel);
break;
case MessageBoxButton.OKCancel:
SetButton(ButtonOne, MessageBoxResult.OK);
SetButton(ButtonTwo, MessageBoxResult.Cancel);
break;
case MessageBoxButton.OK:
default:
SetButton(ButtonOne, MessageBoxResult.OK);
break;
}
// we're doing the width manually for this because ye
if (ButtonThree.Visibility == Visibility.Visible)
Width = 356;
else if (ButtonTwo.Visibility == Visibility.Visible)
Width = 245;
double textWidth = Math.Ceiling(Rendering.GetTextWidth(MessageTextBlock));
// offset to account for box size
textWidth += 40;
// offset to account for icon
if (image != MessageBoxImage.None)
textWidth += 50;
if (textWidth > MaxWidth)
Width = MaxWidth;
else if (textWidth > Width)
Width = textWidth;
sound?.Play();
Loaded += delegate
{
IntPtr hWnd = new WindowInteropHelper(this).Handle;
NativeMethods.FlashWindow(hWnd, true);
};
}
public void SetButton(Button button, MessageBoxResult result)
{
button.Visibility = Visibility.Visible;
button.Content = result.ToString();
button.Click += (_, _) =>
{
Result = result;
Close();
};
}
}
}

View File

@ -0,0 +1,15 @@
using System.Windows;
namespace Bloxstrap.UI.MessageBox
{
static class NativeMessageBox
{
public static MessageBoxResult Show(string message, MessageBoxImage icon = MessageBoxImage.None, MessageBoxButton buttons = MessageBoxButton.OK, MessageBoxResult defaultResult = MessageBoxResult.None)
{
if (App.IsQuiet)
return defaultResult;
return System.Windows.MessageBox.Show(message, App.ProjectName, buttons, icon);
}
}
}

View File

@ -5,7 +5,7 @@ using System.Windows;
using System.Threading;
using System.Threading.Tasks;
using Bloxstrap.UI.Menu.Views;
using Bloxstrap.UI;
namespace Bloxstrap
{
@ -33,7 +33,7 @@ namespace Bloxstrap
}
else
{
result = App.ShowMessageBox(
result = Controls.ShowMessageBox(
$"The version of {App.ProjectName} you've launched is different to the version you currently have installed.\nWould you like to upgrade your currently installed version?",
MessageBoxImage.Question,
MessageBoxButton.YesNo
@ -91,13 +91,13 @@ namespace Bloxstrap
}
else if (!App.IsQuiet)
{
App.ShowMessageBox(
Controls.ShowMessageBox(
$"{App.ProjectName} has been updated to v{currentVersionInfo.ProductVersion}",
MessageBoxImage.Information,
MessageBoxButton.OK
);
new MainWindow().ShowDialog();
Controls.ShowMenu();
App.Terminate();
}
}

View File

@ -11,5 +11,8 @@ namespace Bloxstrap.Utility
{
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool FlashWindow(IntPtr hWnd, bool bInvert);
}
}

View File

@ -0,0 +1,24 @@
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace Bloxstrap.Utility
{
static class Rendering
{
public static double GetTextWidth(TextBlock textBlock)
{
return new FormattedText(
textBlock.Text,
CultureInfo.CurrentCulture,
FlowDirection.LeftToRight,
new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
textBlock.FontSize,
Brushes.Black,
new NumberSubstitution(),
VisualTreeHelper.GetDpi(textBlock).PixelsPerDip
).Width;
}
}
}