メモ帳を作ります。
ファイル名:NoXAML40Notepad.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
<ApplicationIcon>J:\csharp\wpf\NoXAML40Notepad\app.ico</ApplicationIcon>
</PropertyGroup>
</Project>
ファイル名:App.cs
using System.IO;
using System.Windows;
using System.Windows.Media;
namespace NoXAML40Notepad;
public class App : Application
{
[STAThread]
public static void Main(string[] args)
{
string path = "";
if (args.Length > 0) path = args[0];
AppHost.Run(() => Notepad.Build(path));
}
}
ファイル名:AppHost.cs
using System.Windows;
static class AppHost
{
public static void Run(Func<Window> factory,
string title = "App", double width = 900, double height = 600,
WindowStartupLocation startup = WindowStartupLocation.CenterScreen)
{
var app = new Application();
var w = factory();
Win.Init(w, title, width, height, startup);
app.Run(w);
}
}
ファイル名:AssemblyInfo.cs
using System.Windows;
[assembly:ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
ファイル名:Dialog.cs
using Microsoft.Win32;
static class Dialogs
{
public static string? Open(string filter = "Text|*.txt;*.log;*.md|All|*.*")
{
var d = new OpenFileDialog { Filter = filter };
return d.ShowDialog() == true ? d.FileName : null;
}
public static string? SaveAs(string suggest = "untitled.txt", string filter = "Text|*.txt|All|*.*")
{
var d = new SaveFileDialog { FileName = suggest, Filter = filter };
return d.ShowDialog() == true ? d.FileName : null;
}
}
ファイル名:DnD.cs
using System.Windows;
static class DnD
{
public static void AcceptFiles(UIElement target, Action<string[]> onFiles, string[]? exts = null)
{
if (target is FrameworkElement fe) fe.AllowDrop = true;
target.Drop += (_, e) =>
{
if (!e.Data.GetDataPresent(DataFormats.FileDrop)) return;
var files = (string[])e.Data.GetData(DataFormats.FileDrop)!;
if (exts is null) { onFiles(files); return; }
onFiles(Array.FindAll(files, f
=> Array.Exists(exts, x => f.EndsWith(x, StringComparison.OrdinalIgnoreCase))));
};
}
}
ファイル名:Hotkeys.cs
using System.Windows;
using System.Windows.Input;
static class Hotkeys
{
public static void Add(Window w, ICommand cmd, Key key, ModifierKeys mods,
ExecutedRoutedEventHandler exec, CanExecuteRoutedEventHandler? can = null)
{
w.CommandBindings.Add(
new CommandBinding(cmd, exec, can ?? ((_, e) => e.CanExecute = true)));
w.InputBindings.Add(
new KeyBinding(cmd, key, mods));
}
}
ファイル名:Notepad.cs
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace NoXAML40Notepad;
static class Notepad
{
private static string? _path;
public static Window Build(string path="")
{
var tb = UI.Txt();
var w = new Window();
Win.Content(w, tb);
// D&Dで開く
DnD.AcceptFiles(w, files => { if (files.Length > 0) Load(tb, w, files[0]); },
new[] { ".txt", ".log", ".md", ".cs", ".json", ".xml" });
// ホットキー
Hotkeys.Add(w,
ApplicationCommands.Open,
Key.O,
ModifierKeys.Control, (_, __) => Open(tb, w));
Hotkeys.Add(w,
ApplicationCommands.Save,
Key.S, ModifierKeys.Control,
(_, __) => Save(tb, w, asNew: false));
Hotkeys.Add(w,
ApplicationCommands.SaveAs,
Key.S,
ModifierKeys.Control | ModifierKeys.Shift, (_, __) => Save(tb, w, asNew: true));
if (!string.IsNullOrWhiteSpace(path)) Load(tb, w, path);
return w; // タイトル等は AppHost.Run 側で既定設定
}
static void Load(TextBox tb, Window w, string path)
{
tb.Text = File.ReadAllText(path);
_path = path;
w.Title = $"MiniPad - {System.IO.Path.GetFileName(path)}";
}
static void Open(TextBox tb, Window w)
{
var p = Dialogs.Open();
if (p is not null) Load(tb, w, p);
}
static void Save(TextBox tb, Window w, bool asNew)
{
var p = _path;
if (asNew || string.IsNullOrEmpty(p))
p = Dialogs.SaveAs(string.IsNullOrEmpty(_path) ? "untitled.txt" : Path.GetFileName(_path!));
if (p is null) return;
File.WriteAllText(p, tb.Text);
_path = p;
w.Title = $"MiniPad - {System.IO.Path.GetFileName(p)}";
}
}
ファイル名:UI.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
static class UI
{
public static TextBox Txt(bool multiline = true, bool wrap = false, string font = "Consolas", double size = 14)
{
var t = new TextBox
{
AcceptsReturn = multiline,
AcceptsTab = multiline,
HorizontalScrollBarVisibility = wrap ? ScrollBarVisibility.Disabled : ScrollBarVisibility.Auto,
VerticalScrollBarVisibility = ScrollBarVisibility.Auto,
TextWrapping = wrap ? TextWrapping.Wrap : TextWrapping.NoWrap,
FontFamily = new FontFamily(font),
FontSize = size
};
return t;
}
}
ファイル名:Win.cs
using System.Windows;
static class Win
{
public static T Init<T>(T w, string title = "App", double width = 900, double height = 600,
WindowStartupLocation startup = WindowStartupLocation.CenterScreen) where T : Window
{ w.Title = title; w.Width = width; w.Height = height; w.WindowStartupLocation = startup; return w; }
public static T Content<T>(T w, UIElement content) where T : Window
{ w.Content = content; return w; }
}
更新履歴
20250819 初出
20250819 コマンドライン引数(args)対応
コメント