LoginSignup
89
108

More than 1 year has passed since last update.

.NET 6とVSCodeでデスクトップアプリ(ランチャー)

Last updated at Posted at 2021-11-09

■はじめに

Visual Studio CodeVSCode)と.NET 6.0WPFでGUIアプリ(アプリケーションランチャー)を作ります。
00_3.png

■環境

  • Windows 11(Version 21H2)
  • .NET 6.0~
  • Visual Studio Code

■準備

◇.NET SDKのインストール

Windows - .NET 6.xDownload .NET SDK x64を選択します。
01.png

インストールします。
02.png

◇VSCodeのインストール、起動

VSCodeをインストールして起動してください。

■プロジェクトの作成

左のアクティビティ バーの「エクスプローラー」を選択し、「フォルダーを開く」ボタンを押します。
03.png

任意の作業フォルダを開き、新しいフォルダー WrapLauncherを作成し、そのフォルダを選択します。
04.png
05.png

06.png

ターミナルが表示されていない場合はメニューの「表示」-「ターミナル」でターミナルを表示します。
07.png

ターミナルに以下のコマンドを入力し、バージョンが6.xであることを確認します。

dotnet --version

08.png

ターミナルに以下のコマンドを入力し、プロジェクトを作成します。

dotnet new wpf

09.png

■とりあえず実行

ターミナルで以下のコマンドを実行します。

dotnet run

無地のウィンドウが起動します。
10_1.png

最大化ボタンのスナップレイアウトメニューが表示される、標準的なウィンドウです。
一通り動作確認したら閉じてください。
11.png

■画面の作成

「MainWindow.xaml」を開き、画面を作成します。

MainWindow.xaml
<Window
    x:Class="WrapLauncher.MainWindow"
    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:local="clr-namespace:WrapLauncher"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Title="スタート"
    Width="800"
    Height="450"
    Background="WhiteSmoke"
    Closing="Window_Closing"
    Loaded="Window_Loaded"
    ResizeMode="CanResizeWithGrip"
    mc:Ignorable="d">

    【リソース】

    【コンテキストメニュー】

    <ScrollViewer Margin="0,0,0,16">
        <!--  この中にボタン等を追加していく  -->
        <StackPanel x:Name="MainContainer" />
    </ScrollViewer>
</Window>

【リソース】部分には以下を入力します。

MainWindow.xaml【リソース】部分
    <Window.Resources>
        <!--  ボタンのスタイル  -->
        <Style TargetType="Button">
            <Setter Property="Margin" Value="5" />

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Button}">
                        <!--  角丸ボタン  -->
                        <Border
                            Padding="5,3"
                            Background="{TemplateBinding Background}"
                            BorderBrush="Black"
                            BorderThickness="1"
                            CornerRadius="3">
                            <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>

            <Style.Triggers>
                <!--  マウスオーバー時のスタイル  -->
                <Trigger Property="IsMouseOver" Value="true">
                    <!--  背景色  -->
                    <Setter Property="Background" Value="#bee6fd" />
                </Trigger>
                <!--  押されたときのスタイル  -->
                <Trigger Property="IsPressed" Value="true">
                    <!--  背景色  -->
                    <Setter Property="Background" Value="#88d3fd" />
                </Trigger>
            </Style.Triggers>
        </Style>

        <!--  グループ見出しのスタイル  -->
        <Style x:Key="GroupTitleStyle" TargetType="TextBlock">
            <Setter Property="Margin" Value="5,10,5,0" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Foreground" Value="DarkBlue" />
        </Style>
    </Window.Resources>

【コンテキストメニュー】部分には以下を入力します。

MainWindow.xaml【コンテキストメニュー】部分
    <Window.ContextMenu>
        <!--  コンテキストメニュー  -->
        <ContextMenu x:Name="WindowContextMenu">
            <MenuItem Click="MenuReload_Click" Header="設定再読み込み(_R)" />
            <MenuItem Click="MenuFolderOpen_Click" Header="ランチャーの場所を開く(_O)" />

            <Separator />

            <MenuItem
                x:Name="MinimizedMenuItem"
                Header="アプリを起動したらランチャー最小化(_M)"
                IsCheckable="True"
                IsChecked="False"
                ToolTip="※Ctrlキーを押しながらアプリを起動した場合は最小化しません" />

            <StackPanel x:Name="ScaleMenu" Orientation="Horizontal">
                <TextBlock Margin="0,0,10,0" Text="表示倍率" />
                <RadioButton
                    x:Name="DefaultScaleItem"
                    Margin="5,0"
                    Click="ScaleItem_Click"
                    Content="1.0"
                    IsChecked="True" />
                <RadioButton
                    Margin="5,0"
                    Click="ScaleItem_Click"
                    Content="1.5" />
                <RadioButton
                    Margin="5,0"
                    Click="ScaleItem_Click"
                    Content="2.0" />
                <RadioButton
                    Margin="5,0"
                    Click="ScaleItem_Click"
                    Content="3.0" />
            </StackPanel>

            <Separator />

            <MenuItem
                x:Name="InfoMenuItem"
                Click="MenuInfo_Click"
                Header="情報(_I)" />

            <Separator />

            <MenuItem Click="MenuHelp_Click" Header="ヘルプ(_H)" />
        </ContextMenu>
    </Window.ContextMenu>

■ロジックの作成

Appクラスに設定ファイル関連の処理を書きます。
設定ファイルはアプリケーション設定と、ランチャー定義(起動ボタン等)の2種類です。

App.xaml.cs
using System;
using System.IO;
using System.Windows;

namespace WrapLauncher
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        /// <summary>
        /// アプリケーション設定ファイル名
        /// </summary>
        public const string AppSettingsFileName = "appsettings.json";

        /// <summary>
        /// ランチャー定義ファイル名
        /// </summary>
        public const string LaunchDefFileName = "WrapLauncher.path";

        /// <summary>
        /// アプリケーションパス取得
        /// </summary>
        /// <returns></returns>
        public static string GetAppPath()
        {
            string? appPath = AppContext.BaseDirectory;
            if (appPath is null)
            {
                throw new DirectoryNotFoundException("実行ファイルのパス取得失敗");
            }

            return appPath;
        }

        /// <summary>
        /// アプリケーション設定ファイルパス取得
        /// </summary>
        /// <returns></returns>
        public static string GetAppSettingsFilePath()
        {
            return Path.Combine(GetAppPath(), AppSettingsFileName);
        }

        /// <summary>
        /// ランチャー定義ファイルパス取得
        /// </summary>
        /// <returns></returns>
        public static string GetLaunchDefFilePath()
        {
            return Path.Combine(GetAppPath(), LaunchDefFileName);
        }
    }
}

設定ファイル関連のコードを入れるSettingsフォルダを作成します。
13.png
14.png

Settingsフォルダの中にAppSettings.csを作成します。
15.png
16.png

AppSettings.cs
namespace WrapLauncher.Settings
{
    /// <summary>
    /// アプリケーション設定
    /// </summary>
    public class AppSettings
    {
        /// <summary>
        /// アプリ起動後にランチャー最小化
        /// </summary>
        public bool MinimizedAfterLaunch { get; set; } = false;

        /// <summary>
        /// 表示倍率
        /// </summary>
        /// <value></value>
        public double Scale { get; set; } = 1.0;
    }
}

同様にSettingsフォルダの中に以下を作成します。

  • AppSettingsReader.cs
  • AppSettingsWriter.cs
  • LauncherDefinition.cs

17.png

AppSettingsReader.cs
using System.IO;
using System.Text.Json;

namespace WrapLauncher.Settings
{
    /// <summary>
    /// アプリケーション設定読み込み
    /// </summary>
    public class AppSettingsReader
    {
        /// <summary>
        /// ファイル存在確認
        /// </summary>
        /// <returns></returns>
        public bool ExistsFile()
        {
            return File.Exists(App.GetAppSettingsFilePath());
        }

        /// <summary>
        /// ファイル読み込み
        /// </summary>
        /// <returns>設定情報</returns>
        public AppSettings ReadFromFile()
        {
            if (!ExistsFile())
            {
                // ファイルがなければ初期値を返す
                return new AppSettings();
            }

            // 読み込み
            string jsonStr = File.ReadAllText(App.GetAppSettingsFilePath());
            var stg = JsonSerializer.Deserialize<AppSettings>(jsonStr);

            return stg ?? new AppSettings();
        }
    }
}
AppSettingsWriter.cs
using System.IO;
using System.Text.Json;
using JE = System.Text.Encodings.Web;
using UN = System.Text.Unicode;

namespace WrapLauncher.Settings
{
    /// <summary>
    /// アプリケーション設定書き込み
    /// </summary>
    public class AppSettingsWriter
    {
        /// <summary>
        /// ファイル書き込み
        /// </summary>
        /// <param name="stg"></param>
        public void WriteToFile(AppSettings stg)
        {
            var opt = new JsonSerializerOptions
            {
                // シリアライズするUnicodeの範囲
                Encoder = JE.JavaScriptEncoder.Create(UN.UnicodeRanges.All),
                // インデントする
                WriteIndented = true,
            };

            // JSONオブジェクトを文字列化
            string jsonStr = JsonSerializer.Serialize(stg, opt);
            // ファイル書き込み
            File.WriteAllText(App.GetAppSettingsFilePath(), jsonStr);
        }
    }
}
LauncherDefinition.cs
using System.Collections.Generic;

namespace WrapLauncher.Settings
{
    /// <summary>
    /// ランチャー定義情報
    /// </summary>
    public class LauncherDefinition
    {
        /// <summary>
        /// 区切り文字
        /// </summary>
        public const char Delimiter = '\t';

        /// <summary>
        /// グループ見出しの先頭記号
        /// </summary>
        public const string GroupTitleHeader = "//";

        /// <summary>
        /// グループ見出しのカラム位置
        /// </summary>
        public const int GroupTitleColumnIndex = 0;

        /// <summary>
        /// カラム位置
        /// </summary>
        public static IReadOnlyDictionary<string, int> Columns = new Dictionary<string, int>
        {
            {"Color", 0},
            {"ButtonTitle", 1},
            {"Path", 2},
        };

        /// <summary>
        /// グループ見出し判定
        /// </summary>
        /// <param name="values"></param>
        /// <returns>グループ見出しならtrue</returns>
        public bool IsGroupTitle(string[] values)
        {
            return values[GroupTitleColumnIndex].StartsWith(GroupTitleHeader);
        }

        /// <summary>
        /// グループ見出し取得
        /// </summary>
        /// <param name="values"></param>
        /// <returns></returns>
        public string GetGroupTitle(string[] values)
        {
            return values[GroupTitleColumnIndex].Substring(GroupTitleHeader.Length);
        }

    }
}

プロジェクトの直下にShellExecution.csを作成します。
18.png

ShellExecution.cs
using System.Diagnostics;

namespace WrapLauncher
{

    public static class ShellExecution
    {
        /// <summary>
        /// プログラム実行
        /// </summary>
        /// <param name="cmd">実行するコマンド</param>
        public static void Run(string cmd)
        {
            var p = new Process();
            p.StartInfo.FileName = cmd;
            p.StartInfo.UseShellExecute = true;
            // 実行
            p.Start();
        }
    }

}

メインの処理を書きます。

MainWindow.xaml.cs
using System;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using WrapLauncher.Settings;

namespace WrapLauncher
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private readonly LauncherDefinition _btnDef = new();

        // ヘルプテキスト
        private const string HelpText = @"設定ファイルはEXEと同じ場所に「WrapLauncher.path」のファイル名で配置する。
文字コードはBOM無しのUTF8。

データ構造
------------------------------
//グループ見出し
色名  ボタンテキスト   起動プログラム/フォルダのフルパス
色名  ボタンテキスト   起動プログラム/フォルダのフルパス
:
//グループ見出し
色名  ボタンテキスト   起動プログラム/フォルダのフルパス
:
------------------------------
グループ見出しは先頭「//」で始める。
色名、ボタンテキスト、起動するパスはTABで区切る。

[色名一覧]
";

        private int _buttonCount = 0;
        private int _groupCount = 0;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 起動時
        /// </summary>
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                // アプリケーション設定読み込み、画面に反映
                LoadAppSettings();
                // ボタン設定読み込み、画面に反映
                LoadLauncherDef();
            }
            catch (Exception ex)
            {
                ShowException(ex);
            }
        }

        /// <summary>
        /// 終了時
        /// </summary>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            try
            {
                // アプリケーション設定保存
                SaveAppSettings();
            }
            catch (Exception ex)
            {
                MessageBox.Show(
                    $"アプリケーション設定の保存に失敗しました。\n{ex}",
                    "エラー", MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }

        /// <summary>
        /// コンテキストメニュー「設定再読み込み」
        /// </summary>
        private void MenuReload_Click(object sender, RoutedEventArgs e)
        {
            // 画面クリア
            MainContainer.Children.Clear();

            try
            {
                // 設定読み込み、画面に反映
                LoadLauncherDef();
            }
            catch (Exception ex)
            {
                ShowException(ex);
            }
        }

        /// <summary>
        /// コンテキストメニュー「ランチャーの場所を開く」
        /// </summary>
        private void MenuFolderOpen_Click(object sender, RoutedEventArgs e)
        {
            string appPath = App.GetAppPath();
            Execute(appPath);
        }

        /// <summary>
        /// コンテキストメニュー「表示倍率」
        /// </summary>
        private void ScaleItem_Click(object sender, RoutedEventArgs e)
        {
            string? scaleStr = (sender as RadioButton)?.Content?.ToString();
            if (!double.TryParse(scaleStr, out double scale))
            {
                scale = 1.0;
                DefaultScaleItem.IsChecked = true;
            }
            SetContainerScale(scale);
            WindowContextMenu.IsOpen = false;
        }

        /// <summary>
        /// コンテナ拡大縮小処理
        /// </summary>
        /// <param name="scaleXY"></param>
        private void SetContainerScale(double scaleXY)
        {
            MainContainer.LayoutTransform = new ScaleTransform(scaleXY, scaleXY);
        }

        /// <summary>
        /// コンテキストメニュー「情報」
        /// </summary>
        private void MenuInfo_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show($"グループ数:{_groupCount}\nボタン数:{_buttonCount}", "情報");
        }

        /// <summary>
        /// コンテキストメニュー「ヘルプ」
        /// </summary>
        private void MenuHelp_Click(object sender, RoutedEventArgs e)
        {
            ShowHelp();
        }

        /// <summary>
        /// エラー情報表示
        /// </summary>
        private void ShowException(Exception ex)
        {
            MainContainer.Children.Clear();

            var txt = new TextBox
            {
                TextWrapping = TextWrapping.Wrap,
                Margin = new Thickness(5),
                IsReadOnly = true,
                Text = ex.ToString()
            };

            MainContainer.Children.Add(txt);
        }

        /// <summary>
        /// ヘルプ内容表示
        /// </summary>
        private void ShowHelp()
        {
            MainContainer.Children.Clear();

            var helpText = new RichTextBox
            {
                IsReadOnly = true,
                FontSize = 16
            };

            // テキストの説明文追加
            helpText.Document.Blocks.Add(new Paragraph(new Run(HelpText)));

            var bc = new BrushConverter();
            var docList = new System.Windows.Documents.List();

            // 色名一覧作成
            var bList = typeof(Brushes).GetProperties()
                .Where(x => x.Name != "Transparent")
                .OrderBy(x => x.Name);
            foreach (var b in bList)
            {
                var li = new ListItem();
                var p = new Paragraph();
                var r = new Run("■ ")
                {
                    Foreground = (Brush)bc.ConvertFromString(b.Name)!
                };
                p.Inlines.Add(r);
                p.Inlines.Add(new Run(b.Name));

                li.Blocks.Add(p);
                docList.ListItems.Add(li);
            }

            helpText.Document.Blocks.Add(docList);
            MainContainer.Children.Add(helpText);
        }

        /// <summary>
        /// アプリケーション設定読み込み、画面に反映
        /// </summary>
        private void LoadAppSettings()
        {
            var asr = new AppSettingsReader();
            SetScreen(asr.ReadFromFile());
        }

        /// <summary>
        /// アプリケーション設定を画面に反映
        /// </summary>
        /// <param name="appStg"></param>
        private void SetScreen(AppSettings appStg)
        {
            // アプリを起動したらランチャー最小化
            MinimizedMenuItem.IsChecked = appStg.MinimizedAfterLaunch;
            // 表示倍率
            DefaultScaleItem.IsChecked = true;
            foreach (var child in LogicalTreeHelper.GetChildren(ScaleMenu))
            {
                if (child is RadioButton radio)
                {
                    if (double.TryParse(radio.Content.ToString(), out double scale))
                    {
                        if (scale == appStg.Scale)
                        {
                            radio.IsChecked = true;
                            SetContainerScale(scale);
                            break;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// アプリケーション設定保存
        /// </summary>
        private void SaveAppSettings()
        {
            // 画面から設定取得
            var appStg = GetScreen();

            var asw = new AppSettingsWriter();

            // 書き込み
            asw.WriteToFile(appStg);
        }

        /// <summary>
        /// 画面からアプリケーション設定取得
        /// </summary>
        /// <returns></returns>
        private AppSettings GetScreen()
        {
            var appStg = new AppSettings
            {
                // アプリを起動したらランチャー最小化
                MinimizedAfterLaunch = MinimizedMenuItem.IsChecked
            };
            // 表示倍率
            double scale = 1.0;
            foreach (var child in LogicalTreeHelper.GetChildren(ScaleMenu))
            {
                if (child is RadioButton radio)
                {
                    if (radio.IsChecked == true)
                    {
                        if (double.TryParse(radio.Content.ToString(), out scale))
                        {
                            break;
                        }
                    }
                }
            }
            appStg.Scale = scale;

            return appStg;
        }

        /// <summary>
        /// ランチャー定義読み込み、画面に反映
        /// </summary>
        private void LoadLauncherDef()
        {
            // 設定ファイルのフルパス取得
            string filePath = App.GetLaunchDefFilePath();

            // 設定ファイルが見つからなければ終了
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("設定ファイルなし");
            }

            // 設定ファイル読み込み
            using var reader = new StreamReader(filePath);
            WrapPanel? btnContainer = null;

            _buttonCount = 0;
            _groupCount = 0;

            while (!reader.EndOfStream)
            {
                // TABで分解
                var item = reader.ReadLine()?.Split(LauncherDefinition.Delimiter);
                if (item is null ||
                    item.Length < 1)
                {
                    // データなしの行
                    continue;
                }

                /*
                MainContainer           ..... StackPanel
                    grpContainer        ..... StackPanel
                        見出し          ..... TextBlock
                        btnContainer    ..... WrapPanel
                            ボタン
                            ボタン
                            :
                    grpContainer        ..... StackPanel
                        見出し          ..... TextBlock
                        btnContainer    ..... WrapPanel
                            ボタン
                            ボタン
                            :
                */

                // グループ作成するローカル関数
                void MakeGroup(ref WrapPanel? btnContainer, string grpTitle = "")
                {
                    // グループコンテナ作成
                    var grpContainer = new StackPanel();
                    // グループコンテナをメインコンテナに追加
                    MainContainer.Children.Add(grpContainer);

                    if (string.IsNullOrEmpty(grpTitle) == false)
                    {
                        // グループ見出しを生成し、グループコンテナに追加
                        grpContainer.Children.Add(CreateGroupTitle(grpTitle));
                    }

                    // ボタンコンテナを作成
                    btnContainer = new WrapPanel();
                    // ボタンコンテナをグループコンテナに追加
                    grpContainer.Children.Add(btnContainer);
                    _groupCount++;
                }

                if (_btnDef.IsGroupTitle(item))
                {
                    // 見出し

                    // グループ作成
                    MakeGroup(ref btnContainer, _btnDef.GetGroupTitle(item));
                }
                else if (item.Length == LauncherDefinition.Columns.Count)
                {
                    // ボタン

                    // まだボタンコンテナが作成されていない?
                    if (btnContainer is null)
                    {
                        // グループ作成(見出し無し)
                        MakeGroup(ref btnContainer);
                    }

                    // ボタン作成
                    Button btn = CreateLaunchButton(
                        item[LauncherDefinition.Columns["Color"]],
                        item[LauncherDefinition.Columns["ButtonTitle"]],
                        item[LauncherDefinition.Columns["Path"]]);
                    // ボタンコンテナにボタンを追加
                    btnContainer?.Children.Add(btn);
                    _buttonCount++;
                }
                else
                {
                    throw new Exception($"カラム数不正\n{string.Join(LauncherDefinition.Delimiter, item)}");
                }
            }

            if (_buttonCount == 0 &&
                _groupCount == 0)
            {
                throw new Exception("定義内容なし");
            }
        }

        /// <summary>
        /// グループ見出し生成
        /// </summary>
        /// <param name="title"></param>
        /// <returns></returns>
        private TextBlock CreateGroupTitle(string title)
        {
            var txt = new TextBlock
            {
                Style = (Style)(this.Resources["GroupTitleStyle"]),
                Text = title
            };

            return txt;
        }

        /// <summary>
        /// ボタン作成
        /// </summary>
        /// <param name="colorName">色名</param>
        /// <param name="text">ボタンテキスト</param>
        /// <param name="execute">起動プログラムのファイルパス</param>
        private Button CreateLaunchButton(string colorName, string text, string execute)
        {
            var btn = new Button();
            var txtContainer = new StackPanel
            {
                Orientation = Orientation.Horizontal
            };
            // ■テキスト作成
            var txtMark = new TextBlock
            {
                Text = "■",
                Margin = new Thickness(0, 0, 2, 0)
            };

            try
            {
                // 色指定が有効なら■の色を変える。無効な色名なら例外発生で終了させる。
                var bcnv = new BrushConverter();
                txtMark.Foreground = (Brush)bcnv.ConvertFromString(colorName)!;
            }
            catch
            {
                throw new Exception($"無効な色名[{colorName}]");
            }

            txtContainer.Children.Add(txtMark);

            // ボタン名テキスト作成
            var txt = new TextBlock
            {
                Text = text
            };
            txtContainer.Children.Add(txt);

            // ボタンテキスト設定
            btn.Content = txtContainer;
            // ボタンクリック時の処理
            btn.Click += (_, _) =>
            {
                if (Execute(execute) &&
                    MinimizedMenuItem.IsChecked &&
                    !Keyboard.IsKeyDown(Key.LeftCtrl) &&
                    !Keyboard.IsKeyDown(Key.RightCtrl))
                {
                    // ウィンドウ最小化(Ctrl+クリックの場合は最小化しない)
                    WindowState = WindowState.Minimized;
                }
            };

            return btn;
        }

        /// <summary>
        /// プログラム実行
        /// </summary>
        /// <param name="cmd">実行するコマンド</param>
        /// <returns>成否</returns>
        private bool Execute(string cmd)
        {
            try
            {
                ShellExecution.Run(cmd);
                return true;
            }
            catch
            {
                MessageBox.Show(
                    $"起動に失敗しました。\n{cmd}", "エラー", MessageBoxButton.OK, MessageBoxImage.Error);
                return false;
            }
        }

    }
}

ここまでで一度ビルドしてエラーがないか確認しておきます。
ソースファイルを保存し、ターミナルで以下のコマンドを実行します。

dotnet build

19.png

■ランチャー定義ファイルの作成

「bin\Debug\net6.0-windows」にWrapLauncher.pathという名前でファイルを作成します。
20.png

定義ファイルに起動したいフォルダパスやドキュメントファイルパス、プログラムパスなどを記述します。
ファイルの文字コードはBOM無しUTF-8。
色名、ボタン名、パスの間はTAB区切りです。
色名にはGreenBlueなどを書きます。

使える色名の一覧は、プログラム完成後、ヘルプページで見ることができます。

定義ファイルのフォーマット
//グループ見出しA
色名	ボタン名1	パス1
色名	ボタン名2	パス2
:
//グループ見出しB
色名	ボタン名3	パス3
:

定義ファイル入力例)

色名 ボタン名 パス
CadetBlue ダウンロード↓ shell:Downloads
DeepSkyBlue デスクトップ shell:Desktop
Silver ドキュメント shell:Personal
DodgerBlue ピクチャ shell:My Pictures
BlueViolet ビデオ shell:My Video
Chocolate ミュージック♪ shell:My Music
Silver Cドライブ C:\
Silver Dドライブ D:\
Gold Local shell:Local AppData
Gold Apps/2.0 shell:Local AppData\Apps\2.0
Gold Roaming shell:AppData
Gold Program Files (x86) shell:ProgramFilesX86
Gold Program Files shell:ProgramFiles
Gold プロファイル👤 shell:Profile
Gold スタート/プログラム shell:Programs
Gold プログラム/スタートアップ shell:Startup
Gold 送る shell:SendTo
Gold スクリーンショット📷 shell:My Pictures\Screenshots
Gold drivers/etc shell:System\drivers\etc
Gray 電卓 shell:AppsFolder\Microsoft.WindowsCalculator_8wekyb3d8bbwe!App
LightSkyBlue メモ帳 notepad.exe
SkyBlue ペイント🎨 mspaint.exe
ForestGreen Excel excel.exe
RoyalBlue Word Winword.exe
Coral PowerPoint Powerpnt.exe
DodgerBlue Outlook Outlook.exe
Purple OneNote Onenote.exe
Black コマンドプロンプト cmd.exe
DodgerBlue Win PowerShell PowerShell.exe
Navy PowerShell pwsh.exe
DimGray Win Terminal wt.exe
White MSストア shell:AppsFolder\Microsoft.WindowsStore_8wekyb3d8bbwe!App
SkyBlue コンパネ shell:ControlPanelFolder
Gray システムの詳細設定 SystemPropertiesAdvanced.exe
Gray システム/ディスプレイ ms-settings:display
Gray システム/バージョン情報 ms-settings:about
Gray 個人用設定/色 ms-settings:personalization-colors
Gray 個人用設定/スタート ms-settings:personalization-start
Gray アプリ/アプリと機能 ms-settings:appsfeatures
Gray 時刻と言語/言語と地域/Microsoft IME ms-settings:regionlanguage-jpnime

TAB入力でSPACEになってしまう場合は、「ファイル」-「ユーザー設定」-「設定」で検索ボックスに
insertを入力し、「Editor:Insert Spaces」のチェックを外してください。

ついでにwhiteで検索して「Editor:Render Whitespace」をallにしておくとタブ文字が見えるようになります。

21.png

■実行

定義ファイルを保存したら実行します。
ターミナルで以下のコマンドを実行してください。

dotnet run

22.png

ウィンドウの幅を狭めるとボタンが折り返して表示されます。
23.png

右クリックからヘルプ表示。
元の画面に戻るには右クリックから「設定再読み込み」。
24.png

ボタンを大きく表示するには右クリックから「表示倍率」を変更します。
25.png

リリースビルドするときはターミナルで以下のコマンドを実行します。

dotnet build -c Release

「Debug」フォルダの「WrapLauncher.path」を「Release」フォルダにもコピーしておきます。
「WrapLauncher.exe」を実行すればランチャーが起動します。
26.png

■おまけ

◇アイコンの設定

実行ファイルとウィンドウ左上のアイコンを設定します。
やり方は、アイコンを用意(参考)し、プロジェクトのフォルダに配置、プロジェクトファイルに記述を追加します。

27.png

アイコンファイル名は任意の名前を付けられます。

WrapLauncher.csproj(追加分)
  <PropertyGroup>
    <ApplicationIcon>appIcon.ico</ApplicationIcon>
  </PropertyGroup>

◇お勧めの使い方

WrapLauncher.exeを右クリックして「タスクバーにピン留め」します。
30.png

ピン留めされたランチャーを一番左端に移動します。
31.png

ランチャーをShiftを押しながら右クリックし、プロパティを表示します。
32.png

「実行時の大きさ」を「最大化」に設定します。
33_.png

これでWin + 1でランチャーが起動して
スタートメニューと同じような使用感で使えます。

40.png

■参考URL

◇発展形

89
108
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
89
108