HeyCHのブログ

慢性疲労のへいちゃんです

【C#】デスクトップメモを作ってみよう その4

今回の記事は前回の記事の続きとして書いていきます。
今回は、時計やメモが常に表示される設定とメモのウィンドウの色を変更する設定を追加してみたいと思います。
また、時計>終了したときだけではなく、時計が閉じるイベントを拾ってシリアライズ(保存)したいと思います。
heych.hatenablog.com

MainWindowのコード

<Window x:Class="DesktopMemo.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DesktopMemo"
        mc:Ignorable="d"
        Title="MainWindow" Height="120" Width="300" Left="{Binding MainLeft,Mode=TwoWay}" Top="{Binding MainTop,Mode=TwoWay}"
        SizeToContent ="WidthAndHeight"
        WindowStyle="None"
        AllowsTransparency="True"
        Background="Transparent"
        ContentRendered="Window_ContentRendered"
        Closing="Window_Closing">
    <Grid>
        <TextBlock x:Name="textBlock1" Text="{Binding Time}" FontSize="36" FontWeight="Bold">
            <TextBlock.Resources>
                <Style TargetType="TextBlock">
                    <Setter Property="Cursor" Value="Hand"/>
                </Style>
            </TextBlock.Resources>
        </TextBlock>
    </Grid>
    <Window.ContextMenu>
        <ContextMenu Name="_menu" StaysOpen="true">
            <MenuItem Header="メモ追加" Click="MenuItem_Click_3" />
            <MenuItem Header="常に手前に表示" Click="MenuItem_Click_4" />
            <Separator />
            <MenuItem Header="フォント" Click="MenuItem_Click_1" />
            <MenuItem Header="カラー" Click="MenuItem_Click_2" />
            <Separator />
            <MenuItem Header="終了" Click="MenuItem_Click" />
        </ContextMenu>
    </Window.ContextMenu>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows.Forms;
using System.Xml.Serialization;
using System.IO;
using System.Threading;
using System.Xml;

namespace DesktopMemo {
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window {
        ViewModel vm = new ViewModel();
        public MainWindow() {
            InitializeComponent();
            this.DataContext = vm;

            //デシリアライズするとなぜかMainWIndowがnullになってしまう。
            //原因でデシリアライズの際空のコンストラクタが呼ばれ、MainWindow=nullになってしまうから。
            if (File.Exists(@"data.xml")) {
                XmlDocument doc = new XmlDocument();
                doc.Load(@"data.xml");
                var MainLeft = doc.SelectSingleNode("//MainLeft");
                var MainTop = doc.SelectSingleNode("//MainTop");
                var MainFontAsString = doc.SelectSingleNode("//MainFontAsString");
                var MainColorAsString = doc.SelectSingleNode("//MainColorAsString");
                vm.MainLeft = double.Parse(MainLeft.InnerText);
                vm.MainTop = double.Parse(MainTop.InnerText);
                vm.MainFontAsString = MainFontAsString.InnerText;
                vm.MainColorAsString = MainColorAsString.InnerText;

                ChangeFont(vm.MainFont, textBlock1);
                ChangeColor(vm.MainColor, textBlock1);
            }

            BackgroundWorker bw = new BackgroundWorker();
            bw.DoWork += Bw_DoWork;
            bw.RunWorkerAsync();
        }

        private void Bw_DoWork(object sender, DoWorkEventArgs e) {
            while (true) {
                vm.OnPropertyChanged("Time");
                System.Threading.Thread.Sleep(100);
            }
        }
        /// <summary>
        /// label1のフォント変更
        /// </summary>
        private void ChangeFont(System.Drawing.Font font, TextBlock tage) {
            tage.FontFamily = new FontFamily(font.Name);
            tage.FontSize = font.Size * 96.0 / 72.0;
            tage.FontWeight = font.Bold ? FontWeights.Bold : FontWeights.Regular;
            tage.FontStyle = font.Italic ? FontStyles.Italic : FontStyles.Normal;
            TextDecorationCollection tdc = new TextDecorationCollection();
            if (font.Underline) tdc.Add(TextDecorations.Underline);
            if (font.Strikeout) tdc.Add(TextDecorations.Strikethrough);
            tage.TextDecorations = tdc;
        }
        /// <summary>
        /// label1のカラー変更
        /// </summary>
        private void ChangeColor(System.Drawing.Color color, TextBlock tage) {
            tage.Foreground
                = new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
        }
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
            base.OnMouseLeftButtonDown(e);

            try {
                DragMove();
            } catch { }
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e) {
            this.Close();
        }

        private void MenuItem_Click_1(object sender, RoutedEventArgs e) {
            FontDialog fd = new FontDialog();
            if (fd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                vm.MainFont = fd.Font;
                ChangeFont(vm.MainFont, textBlock1);
            }
        }

        private void MenuItem_Click_2(object sender, RoutedEventArgs e) {
            ColorDialog cd = new ColorDialog();
            if (cd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                vm.MainColor = cd.Color;
                ChangeColor(vm.MainColor, textBlock1);
            }
        }

        private void MenuItem_Click_3(object sender, RoutedEventArgs e) {
            Memo m = new Memo();
            m.Owner = this;
            m.Show();
            //コレクションの処理
            vm.Memos.Add((MemoViewModel)m.DataContext);
        }

        private void MenuItem_Click_4(object sender, RoutedEventArgs e) {
            if (!this.Topmost)
                this.Topmost = true;
            else
                this.Topmost = false;
        }

        private void Window_ContentRendered(object sender, EventArgs e) {
            if (File.Exists(@"data.xml")) {
                XmlDocument doc = new XmlDocument();
                doc.Load(@"data.xml");
                //Memoの処理
                var Memos = doc.SelectNodes(".//MemoViewModel");
                foreach (XmlElement memo in Memos) {
                    var Text = memo.SelectSingleNode(".//Text");
                    var MemoLeft = memo.SelectSingleNode(".//MemoLeft");
                    var MemoTop = memo.SelectSingleNode(".//MemoTop");
                    var MemoHeight = memo.SelectSingleNode(".//MemoHeight");
                    var MemoWidth = memo.SelectSingleNode(".//MemoWidth");
                    var MemoFontAsString = memo.SelectSingleNode(".//MemoFontAsString");
                    var MemoColorAsString = memo.SelectSingleNode(".//MemoColorAsString");
                    var MemoWindowColorAsString = memo.SelectSingleNode(".//MemoWindowColorAsString");
                    var mvm = new MemoViewModel();
                    mvm.Text = Text.InnerText;
                    mvm.MemoLeft = double.Parse(MemoLeft.InnerText);
                    mvm.MemoTop = double.Parse(MemoTop.InnerText);
                    mvm.MemoHeight = double.Parse(MemoHeight.InnerText);
                    mvm.MemoWidth = double.Parse(MemoWidth.InnerText);
                    mvm.MemoFontAsString = MemoFontAsString.InnerText;
                    mvm.MemoColorAsString = MemoColorAsString.InnerText;
                    mvm.MemoWindowColorAsString = MemoWindowColorAsString.InnerText;
                    vm.Memos.Add(mvm);
                    var m = new Memo();
                    m.DataContext = mvm;
                    m.ChangeFont(mvm.MemoFont, m.textBox1);
                    m.ChangeColor(mvm.MemoColor, m.textBox1);
                    m.ChangeWindowColor(mvm.MemoWindowColor, m, m.textBox1);
                    m.Owner = this;
                    m.Show();
                }
            }
        }

        private void Window_Closing(object sender, CancelEventArgs e) {
            //終了する時にシリアライズして保存
            XmlSerializer xs = new XmlSerializer(typeof(ViewModel));
            using (var sw = new StreamWriter(@"data.xml", false, Encoding.UTF8)) {
                xs.Serialize(sw, vm);
            }
        }
    }

    public class ViewModel : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName) {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        public string Time {
            get {
                return DateTime.Now.ToString("HH:mm:ss");
            }
        }
        double _MainLeft = 0;
        public double MainLeft {
            get {
                return _MainLeft;
            }
            set {
                _MainLeft = value;
                OnPropertyChanged("MainLeft");
            }
        }
        double _MainTop = 0;
        public double MainTop {
            get {
                return _MainTop;
            }
            set {
                _MainTop = value;
                OnPropertyChanged("MainTop");
            }
        }
        ObservableCollection<MemoViewModel> _Memos = new ObservableCollection<MemoViewModel>();
        public ObservableCollection<MemoViewModel> Memos {
            get {
                return _Memos;
            }
            set {
                _Memos = value;
                OnPropertyChanged("Memos");
            }
        }
        System.Drawing.Font _MainFont = System.Drawing.SystemFonts.DefaultFont;
        [XmlIgnore]
        public System.Drawing.Font MainFont {
            get {
                return _MainFont;
            }
            set {
                _MainFont = value;
                OnPropertyChanged("MainFont");
            }
        }
        public string MainFontAsString {
            get { return ConvertToString(MainFont); }
            set { MainFont = ConvertFromString<System.Drawing.Font>(value); }
        }

        System.Drawing.Color _MainColor = System.Drawing.Color.Black;
        [XmlIgnore]
        public System.Drawing.Color MainColor {
            get {
                return _MainColor;
            }
            set {
                _MainColor = value;
                OnPropertyChanged("MainColor");
            }
        }
        public string MainColorAsString {
            get { return ConvertToString(MainColor); }
            set { MainColor = ConvertFromString<System.Drawing.Color>(value); }
        }

        //FontやColorを文字列にしてくれる奴
        public static string ConvertToString<T>(T value) {
            return TypeDescriptor.GetConverter(typeof(T)).ConvertToString(value);
        }
        public static T ConvertFromString<T>(string value) {
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(value);
        }
    }
}
  • Window_ContentRendered部分にMemoのウィンドウの色の内容を追加
  • Window_Closingイベントにシリアライズ(保存)の処理を移動

MemoWindowのコード

<Window x:Class="DesktopMemo.Memo"
        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:local="clr-namespace:DesktopMemo"
        mc:Ignorable="d"
        Title="Memo" Height="{Binding MemoHeight,Mode=TwoWay}" Width="{Binding MemoWidth,Mode=TwoWay}" Left="{Binding MemoLeft,Mode=TwoWay}" Top="{Binding MemoTop,Mode=TwoWay}"
         MinWidth="130" MinHeight="40"
        SizeToContent ="WidthAndHeight"
        WindowStyle="None"
        AllowsTransparency="True">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="15"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <TextBox Grid.Row="1" x:Name="textBox1" Text="{Binding Text,UpdateSourceTrigger=PropertyChanged}" MinWidth="130" MinHeight="25" AcceptsReturn="True" />
    </Grid>
    <Window.ContextMenu>
        <ContextMenu Name="_menu" StaysOpen="true">
            <MenuItem Header="フォント" Click="MenuItem_Click_1" />
            <MenuItem Header="カラー" Click="MenuItem_Click_2" />
            <MenuItem Header="ウィンドウカラー" Click="MenuItem_Click_3" />
            <Separator />
            <MenuItem Header="終了" Click="MenuItem_Click" />
        </ContextMenu>
    </Window.ContextMenu>
</Window>
  • コンテキストメニューに「ウィンドウカラー」追加
  • Window全体の色を付けたい場合「AllowsTransparency="True"」をつけないと白い部分が残る
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Xml.Serialization;

namespace DesktopMemo {
    /// <summary>
    /// Memo.xaml の相互作用ロジック
    /// </summary>
    public partial class Memo : Window {
        internal MemoViewModel mvm = new MemoViewModel();
        public Memo() {
            InitializeComponent();
            this.DataContext = mvm;
        }

        /// <summary>
        /// TextBoxのフォント変更
        /// </summary>
        internal void ChangeFont(System.Drawing.Font font, System.Windows.Controls.TextBox tage) {
            tage.FontFamily = new FontFamily(font.Name);
            tage.FontSize = font.Size * 96.0 / 72.0;
            tage.FontWeight = font.Bold ? FontWeights.Bold : FontWeights.Regular;
            tage.FontStyle = font.Italic ? FontStyles.Italic : FontStyles.Normal;
            TextDecorationCollection tdc = new TextDecorationCollection();
            if (font.Underline) tdc.Add(TextDecorations.Underline);
            if (font.Strikeout) tdc.Add(TextDecorations.Strikethrough);
            tage.TextDecorations = tdc;
        }
        /// <summary>
        /// TextBoxのカラー変更
        /// </summary>
        internal void ChangeColor(System.Drawing.Color color, System.Windows.Controls.TextBox tage) {
            tage.Foreground
                = new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
        }
        /// <summary>
        /// Windowのカラー変更
        /// </summary>
        internal void ChangeWindowColor(System.Drawing.Color color, Window tage1, System.Windows.Controls.TextBox tage2) {
            tage1.Background
                = new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
            tage2.Background
                = new SolidColorBrush(System.Windows.Media.Color.FromRgb(color.R, color.G, color.B));
        }
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) {
            base.OnMouseLeftButtonDown(e);

            try {
                DragMove();
            } catch { }
        }

        private void MenuItem_Click(object sender, RoutedEventArgs e) {
            //コレクションの処理
            var vm = (ViewModel)this.Owner.DataContext;
            vm.Memos.Remove((MemoViewModel)this.DataContext);
            this.Close();
        }

        private void MenuItem_Click_1(object sender, RoutedEventArgs e) {
            FontDialog fd = new FontDialog();
            if (fd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                mvm.MemoFont = fd.Font;
                ChangeFont(mvm.MemoFont, textBox1);
            }
        }

        private void MenuItem_Click_2(object sender, RoutedEventArgs e) {
            ColorDialog cd = new ColorDialog();
            if (cd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                mvm.MemoColor = cd.Color;
                ChangeColor(mvm.MemoColor, textBox1);
            }
        }

        private void MenuItem_Click_3(object sender, RoutedEventArgs e) {
            ColorDialog cd = new ColorDialog();
            if (cd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
                mvm.MemoWindowColor = cd.Color;
                ChangeWindowColor(mvm.MemoWindowColor, this, textBox1);
            }
        }
    }
    public class MemoViewModel : INotifyPropertyChanged {
        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName) {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
        string _Text = "";
        public string Text {
            get {
                return _Text;
            }
            set {
                _Text = value;
                OnPropertyChanged("Text");
            }
        }
        double _MemoLeft = 0;
        public double MemoLeft {
            get {
                return _MemoLeft;
            }
            set {
                _MemoLeft = value;
                OnPropertyChanged("MemoLeft");
            }
        }
        double _MemoTop = 0;
        public double MemoTop {
            get {
                return _MemoTop;
            }
            set {
                _MemoTop = value;
                OnPropertyChanged("MemoTop");
            }
        }
        double _MemoHeight = 0;
        public double MemoHeight {
            get {
                return _MemoHeight;
            }
            set {
                _MemoHeight = value;
                OnPropertyChanged("MemoHeight");
            }
        }
        double _MemoWidth = 0;
        public double MemoWidth {
            get {
                return _MemoWidth;
            }
            set {
                _MemoWidth = value;
                OnPropertyChanged("MemoWidth");
            }
        }
        System.Drawing.Font _MemoFont = System.Drawing.SystemFonts.DefaultFont;
        [XmlIgnore]
        public System.Drawing.Font MemoFont {
            get {
                return _MemoFont;
            }
            set {
                _MemoFont = value;
                OnPropertyChanged("MemoFont");
            }
        }
        public string MemoFontAsString {
            get { return ConvertToString(MemoFont); }
            set { MemoFont = ConvertFromString<System.Drawing.Font>(value); }
        }

        System.Drawing.Color _MemoColor = System.Drawing.Color.Black;
        [XmlIgnore]
        public System.Drawing.Color MemoColor {
            get {
                return _MemoColor;
            }
            set {
                _MemoColor = value;
                OnPropertyChanged("MemoColor");
            }
        }
        public string MemoColorAsString {
            get { return ConvertToString(MemoColor); }
            set { MemoColor = ConvertFromString<System.Drawing.Color>(value); }
        }

        System.Drawing.Color _MemoWindowColor = System.Drawing.Color.White;
        [XmlIgnore]
        public System.Drawing.Color MemoWindowColor {
            get {
                return _MemoWindowColor;
            }
            set {
                _MemoWindowColor = value;
                OnPropertyChanged("MemoWindowColor");
            }
        }
        public string MemoWindowColorAsString {
            get { return ConvertToString(MemoWindowColor); }
            set { MemoWindowColor = ConvertFromString<System.Drawing.Color>(value); }
        }

        //FontやColorを文字列にしてくれる奴
        public static string ConvertToString<T>(T value) {
            return TypeDescriptor.GetConverter(typeof(T)).ConvertToString(value);
        }
        public static T ConvertFromString<T>(string value) {
            return (T)TypeDescriptor.GetConverter(typeof(T)).ConvertFromString(value);
        }
    }
}
  • ウィンドウカラーを変えるためにWindowのBackgroundとTextBoxのBackgroundを変更するよう修正

f:id:HeyCH:20200508004620p:plain

DesktopMemo.exe - Google ドライブ