20210321のC#に関する記事は4件です。

C#で特定の日時を過ぎたら開けなくする[WPF]

参照:
https://docs.microsoft.com/ja-jp/dotnet/api/system.datetime.compare

コード

DateTime date1 = DateTime.Now;//現在時刻取得
DateTime date2 = new DateTime(2030, 1, 1, 0, 0, 0);//対象先の日付時刻設定(左から、年、月、日、時、分)
int result = DateTime.Compare(date1, date2);//比較

if (result < 0)
{
//現在時刻が対象先の日付時刻よりも早い場合の処理

}
else
{
//現在時刻が対象先の日付時刻よりも遅い場合の処理
    Close();//アプリケーション終了
}

注意点

PCの設定で日付を意図的に遅らせた場合は動作しない可能性がありますのでご注意ください。
aapythonはこのコードを使用したことによるいかなる責任を負いません。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Windows Forms] ボタンに画像を2つ入れる

■概要

画像を2つ設定したボタン
00.png

■環境

  • Windows 10
  • Visual Studio 2019 Community Version 16.9.2
  • .NET Framework 4.7.2

■プロジェクトの作成

新しいプロジェクトを作成します。
検索条件で絞り込んでWindows フォーム アプリケーション(.NET Framework)を選択します。
01_.png

プロジェクト名を入力し、フレームワークを選択します。
ここではプロジェクト名をWindowsFormsApp1
フレームワークは4.5~4.8、ここでは.NET Framework 4.7.2にしました。
02_.png

03_.png

■画面コンテンツ枠の追加

プロジェクトを右クリックし、「追加」-「新しい項目」を選択します。
04.png

「WPF」-「ユーザーコントロール(WPF)」を選択し、名前にForm1Childと入力して追加します。
05.png
06.png

メニューの「ビルド」-「ソリューションのビルド」でビルドしておきます。

Form1を選択し、ツールボックスの「WPF相互運用機能」の「ElementHost」をForm1にドラッグ&ドロップします。
07.png

「ホストするコンテンツの選択」のドロップダウンを開き、Form1Childを選択します。
08.png

「親コンテナーにドッキングする」を選択します。
09.png
10.png

■土台部分作成

デザイナの「Form1Click.xaml」のタブを選択し、メニューの「表示」-「その他のウィンドウ」-「ドキュメントアウトライン」を選択します。
11.png

ドキュメントアウトラインを使いやすい位置に配置します。
12.png

Gridを選択状態にし、デザイナの薄く赤線を引いた部分にマウスポインタを近づけると+マークが付きます。
そこでクリックするとGridを分割できます。
13.png
14.png

ツールボックスから「StackPanel」を行分割したGridの下の行にドラッグ&ドロップします。
20.png

Gridの中にStackPanelが追加されました。
21.png

StackPanelは既定では中に配置したコントロールを縦並びに整列させます。
これを横並びに変更します。
StackPanelを選択し、プロパティウィンドウの「整列」-「Orientation」でHorizontalを選択します。
22.png

■ボタンの追加

ツールボックスから「Button」を画面のStackPanel上にドラッグ&ドロップします。
23.png

続けて2つ、「Button」をStackPanel上にドラッグ&ドロップします。
24.png
25.png

■画像リソースの読み込み

以下のファイルをダウンロードしてgreen.png, orange.pngという名前で保存します。
green.png
orange.png

プロジェクトの「Properties」-「Resources.resx」をダブルクリックし、
「リソースの追加」のをクリックし、「既存のファイルの追加」を選択します。
26.png

green.pngとorange.pngを追加します。
27.png

「Resources」フォルダの「green.png」を選択し、
プロパティウィンドウの「ビルドアクション」でResourcesを選択します。
28.png

「orange.png」も同様に設定します。
29.png

メニューの「ビルド」-「ソリューションのビルド」でビルドしておきます。

■画像付きボタンの作成

◇部品配置

ツールボックスから「StackPanel」を1つめのボタン上にドラッグ&ドロップします。
30.png

ボタンの中にStackPanelが入りました。
31.png

ドキュメントアウトライン上でStackPanelが選択状態になっていることを確認し、
プロパティウィンドウで「レイアウト」-「Orientation」を先程と同じHorizontalに設定します。

ツールボックスからドキュメントアウトラインの「Button」の中の「StackPanel」上に、
「Image」、「TextBlock」、「Image」の順にドラッグ&ドロップします。
32.png
33.png

◇画像設定

ドキュメントアウトラインで1つめの「Image」を選択し、
プロパティウィンドウの「共通」-「Source」のを開き、「green.png」を選択します。
34.png

「Image」をプロパティウィンドウの「レイアウト」で「Width」と「Height」を20に設定します。
35.png

もう一つの「Image」も「orange.png」を読み込ませて同様に設定します。
36.png

◇余白調整、ボタンテキスト変更

ドキュメントアウトラインで「TextBlock」を選択し、
プロパティウィンドウの「レイアウト」-「Margin」で左右余白8を設定します。
「共通」-「Text」に押してくださいを入力します。
37.png
「レイアウト」-「VerticalAlignment」をCenterに設定します。
37-2.png

◇イベント追加

ドキュメントアウトラインで1つめのボタンを選択し、プロパティウィンドウで稲妻マークを選択し、イベント一覧を表示します。
「Click」横のテキストボックスをダブルクリックします。
38.png

メッセージボックスを表示する処理を記述します。

Form1Child.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("押された!", "タイトル", 
        MessageBoxButton.OK, MessageBoxImage.Information);
}

■Gridの行高さ調整

適当に設定していたGridの行高さを調整します。
ドキュメントアウトラインでGridを選択し、デザイナでGridの下の行の左端あたりにマウスポインタを移動します。
40.png

ドロップダウンを開いて「Auto」を選択します。
41.png

Grid行の中の要素(ボタン)に合わせて自動調整されます。
42.png

■ボタン間隔調整

ボタンがぴったりくっついているので間隔を調整します。
以下をUserControlの開始タグとGridの開始タグの間に記述します。

Form1Child.xaml
<UserControl.Resources>
    <Style TargetType="Button">
        <Setter Property="Margin" Value="8" />
    </Style>
</UserControl.Resources>

これでこのUserControlの中にあるすべてのボタンの上下左右に余白8が設定されました。
43.png

ボタンの淵と中身の間隔「Padding」も設定してみます。

<Style TargetType="Button">
    <Setter Property="Margin" Value="8" />
    <Setter Property="Padding" Value="24,8" />
</Style>

44.png

ボタンの淵~中身の左右の間隔は24、上下間隔は8に設定しました。
45.png

■実行

46.png

■おまけ

閉じるボタンを実装します。
3つめのボタンのテキストを閉じるにし、ClickイベントにCloseButton_Clickを入力してEnterします。
50.png

プロパティCloseActionを追加し、CloseButton_Clickの中で呼び出します。

Form1Child.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;

namespace WindowsFormsApp1
{
    /// <summary>
    /// Form1Child.xaml の相互作用ロジック
    /// </summary>
    public partial class Form1Child : UserControl
    {
        public Action CloseAction { get; set; }

        public Form1Child()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("押された!", "タイトル", 
                MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            CloseAction();
        }
    }
}

CloseActionにフォームを閉じる処理を設定します。

Form1.cs
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var child = elementHost1.Child as Form1Child;
            child.CloseAction = () => Close();
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Windows Forms] ボタンに画像を2つ表示

■概要

画像を2つ設定したボタン
00.png

■環境

  • Windows 10
  • Visual Studio 2019 Community Version 16.9.2
  • .NET Framework 4.7.2

■プロジェクトの作成

新しいプロジェクトを作成します。
検索条件で絞り込んでWindows フォーム アプリケーション(.NET Framework)を選択します。
01_.png

プロジェクト名を入力し、フレームワークを選択します。
ここではプロジェクト名をWindowsFormsApp1
フレームワークは4.5~4.8、ここでは.NET Framework 4.7.2にしました。
02_.png

03_.png

■画面コンテンツ枠の追加

プロジェクトを右クリックし、「追加」-「新しい項目」を選択します。
04.png

「WPF」-「ユーザーコントロール(WPF)」を選択し、名前にForm1Childと入力して追加します。
05.png
06.png

メニューの「ビルド」-「ソリューションのビルド」でビルドしておきます。

Form1を選択し、ツールボックスの「WPF相互運用機能」の「ElementHost」をForm1にドラッグ&ドロップします。
07.png

「ホストするコンテンツの選択」のドロップダウンを開き、Form1Childを選択します。
08.png

「親コンテナーにドッキングする」を選択します。
09.png
10.png

■土台部分作成

デザイナの「Form1Child.xaml」のタブを選択し、メニューの「表示」-「その他のウィンドウ」-「ドキュメントアウトライン」を選択します。
11.png

ドキュメントアウトラインを使いやすい位置に配置します。
12.png

Gridを選択状態にし、デザイナの薄く赤線を引いた部分にマウスポインタを近づけると+マークが付きます。
そこでクリックするとGridを分割できます。
13.png
14.png

ツールボックスから「StackPanel」を行分割したGridの下の行にドラッグ&ドロップします。
20.png

Gridの中にStackPanelが追加されました。
21.png

StackPanelは既定では中に配置したコントロールを縦並びに整列させます。
これを横並びに変更します。
StackPanelを選択し、プロパティウィンドウの「整列」-「Orientation」でHorizontalを選択します。
22.png

■ボタンの追加

ツールボックスから「Button」を画面のStackPanel上にドラッグ&ドロップします。
23.png

続けて2つ、「Button」をStackPanel上にドラッグ&ドロップします。
24.png
25.png

■画像リソースの読み込み

以下のファイルをダウンロードしてgreen.png, orange.pngという名前で保存します。
green.png
orange.png

プロジェクトの「Properties」-「Resources.resx」をダブルクリックし、
「リソースの追加」のをクリックし、「既存のファイルの追加」を選択します。
26.png

green.pngとorange.pngを追加します。
27.png

「Resources」フォルダの「green.png」を選択し、
プロパティウィンドウの「ビルドアクション」でResourcesを選択します。
28.png

「orange.png」も同様に設定します。
29.png

メニューの「ビルド」-「ソリューションのビルド」でビルドしておきます。

■画像付きボタンの作成

◇部品配置

ツールボックスから「StackPanel」を1つめのボタン上にドラッグ&ドロップします。
30.png

ボタンの中にStackPanelが入りました。
31.png

ドキュメントアウトライン上でStackPanelが選択状態になっていることを確認し、
プロパティウィンドウで「レイアウト」-「Orientation」を先程と同じHorizontalに設定します。

ツールボックスからドキュメントアウトラインの「Button」の中の「StackPanel」上に、
「Image」、「TextBlock」、「Image」の順にドラッグ&ドロップします。
32.png
33.png

◇画像設定

ドキュメントアウトラインで1つめの「Image」を選択し、
プロパティウィンドウの「共通」-「Source」のを開き、「green.png」を選択します。
34.png

「Image」をプロパティウィンドウの「レイアウト」で「Width」と「Height」を20に設定します。
35.png

もう一つの「Image」も「orange.png」を読み込ませて同様に設定します。
36.png

◇余白調整、ボタンテキスト変更

ドキュメントアウトラインで「TextBlock」を選択し、
プロパティウィンドウの「レイアウト」-「Margin」で左右余白8を設定します。
「共通」-「Text」に押してくださいを入力します。
37.png
「レイアウト」-「VerticalAlignment」をCenterに設定します。
37-2.png

◇イベント追加

ドキュメントアウトラインで1つめのボタンを選択し、プロパティウィンドウで稲妻マークを選択し、イベント一覧を表示します。
「Click」横のテキストボックスをダブルクリックします。
38.png

メッセージボックスを表示する処理を記述します。

Form1Child.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("押された!", "タイトル", 
        MessageBoxButton.OK, MessageBoxImage.Information);
}

■Gridの行高さ調整

適当に設定していたGridの行高さを調整します。
ドキュメントアウトラインでGridを選択し、デザイナでGridの下の行の左端あたりにマウスポインタを移動します。
40.png

ドロップダウンを開いて「Auto」を選択します。
41.png

Grid行の中の要素(ボタン)に合わせて自動調整されます。
42.png

■ボタン間隔調整

ボタンがぴったりくっついているので間隔を調整します。
以下をUserControlの開始タグとGridの開始タグの間に記述します。

Form1Child.xaml
<UserControl.Resources>
    <Style TargetType="Button">
        <Setter Property="Margin" Value="8" />
    </Style>
</UserControl.Resources>

これでこのUserControlの中にあるすべてのボタンの上下左右に余白8が設定されました。
43.png

ボタンの淵と中身の間隔「Padding」も設定してみます。

<Style TargetType="Button">
    <Setter Property="Margin" Value="8" />
    <Setter Property="Padding" Value="24,8" />
</Style>

44.png

ボタンの淵~中身の左右の間隔は24、上下間隔は8に設定しました。
45.png

■実行

46.png

■おまけ

閉じるボタンを実装します。
3つめのボタンのテキストを閉じるにし、ClickイベントにCloseButton_Clickを入力してEnterします。
50.png

プロパティCloseActionを追加し、CloseButton_Clickの中で呼び出します。

Form1Child.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;

namespace WindowsFormsApp1
{
    /// <summary>
    /// Form1Child.xaml の相互作用ロジック
    /// </summary>
    public partial class Form1Child : UserControl
    {
        public Action CloseAction { get; set; }

        public Form1Child()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("押された!", "タイトル", 
                MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            CloseAction();
        }
    }
}

CloseActionにフォームを閉じる処理を設定します。

Form1.cs
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();

            var child = elementHost1.Child as Form1Child;
            child.CloseAction = () => Close();
        }
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MaskedTextProviderを利用してみる

はじめに

時刻入力用のTextBoxが必要なことがあり、MaskedTextProviderを使えばいいらしいことは分かったのですが、実装がうまくできませんでした。

欲しかった画面はこんな感じでした。
image.png
日付を入力して、そのあと、時間を入力するというもの。
時刻はText(string)で使えるようにしたいです。

MaterialDesignのExsampleにMaskedTextBoxがあったので使えるかなと思ったのですが、これはXceed SoftwareのExtended.Wpf.Toolkitを利用していました。
Extended.Wpf.Toolkitはライセンスが以前はMS-PLライセンスだったみたいですが、ライセンスが変わって、非商用でも10人以上のユーザーがいれば商用ライセンスが必要となったようで、採用するのは難しいと思いました。

そこで、いろいろと調べていたところ、Blindmeis's BlogにWPF – Masked Textbox Behaviorがとても参考になりました。
ブログの記事だと、汎用的だったので、参考にしながら、時刻用の設定を追加したりして完成できました。

詳細は後で記事にするかもしれませんが、まずは参考にしていただければと思い、全コードを記載しておきます。
ちなみに、ビヘイビアとして作成しています。

MaskedTextBoxBehavior : Behavior

using Microsoft.Xaml.Behaviors;
using System;
using System.ComponentModel;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace Sample.WPF.Behaviors
{
     public class MaskedTextBoxBehavior : Behavior<TextBox> 
    {
        #region DependencyProperties
        public string InputMask
        {
            get { return (string)GetValue(InputMaskProperty); }
            set { SetValue(InputMaskProperty, value); }
        }

        public static readonly DependencyProperty InputMaskProperty =
          DependencyProperty.Register("InputMask", typeof(string), 
                                        typeof(MaskedTextBoxBehavior),  
                                        null);


        public char PromptChar
        {
            get { return (char)GetValue(PromptCharProperty); }
            set { SetValue(PromptCharProperty, value); }
        }

        public static readonly DependencyProperty PromptCharProperty =
           DependencyProperty.Register("PromptChar", typeof(char), 
                                        typeof(MaskedTextBoxBehavior),
                                        new PropertyMetadata('_'));


        public bool IsTime
        {
            get { return (bool)GetValue(IsTimeProperty); }
            set { SetValue(IsTimeProperty, value); }
        }

        public static readonly DependencyProperty IsTimeProperty =
            DependencyProperty.Register("MyProperty", typeof(bool), 
                                        typeof(MaskedTextBoxBehavior), 
                                        new PropertyMetadata(false));

        #endregion

        public MaskedTextProvider Provider { get; private set; }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Loaded += AssociatedObjectLoaded;
            AssociatedObject.PreviewTextInput += AssociatedObjectPreviewTextInput;
            AssociatedObject.PreviewKeyDown += AssociatedObjectPreviewKeyDown;
            AssociatedObject.LostFocus += AccociateObjectLostFocus;
            AssociatedObject.GotFocus += AssociatedObjectGotFocus;

            DataObject.AddPastingHandler(AssociatedObject, Pasting);
        }


        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Loaded -= AssociatedObjectLoaded;
            AssociatedObject.PreviewTextInput -= AssociatedObjectPreviewTextInput;
            AssociatedObject.PreviewKeyDown -= AssociatedObjectPreviewKeyDown;
            AssociatedObject.LostFocus -= AccociateObjectLostFocus;
            AssociatedObject.GotFocus -= AssociatedObjectGotFocus;

            DataObject.RemovePastingHandler(AssociatedObject, Pasting);
        }


        /// <summary>
        /// カーソルを最初の位置にする
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void AssociatedObjectGotFocus(object sender, RoutedEventArgs e)
        {
            AssociatedObject.Select(0, 0);

            //選択時にSelectAllにする場合はこちら
            //AssociatedObject.Select(0, AssociatedObject.Text.Length);
        }


        void AssociatedObjectLoaded(object sender, System.Windows.RoutedEventArgs e)
        {
            Provider = new MaskedTextProvider(InputMask, CultureInfo.CurrentCulture);
            Provider.PromptChar = PromptChar;

            Provider.Set(AssociatedObject.Text);

            //ToDisplayString:表示できる形式で書式設定された文字列
            AssociatedObject.Text = Provider.ToDisplayString();

            var textProp = DependencyPropertyDescriptor.FromProperty(TextBox.TextProperty, typeof(TextBox));
            if (textProp != null)
            {
                textProp.AddValueChanged(AssociatedObject, (s, args) => UpdateText());
            }
        }

        void AssociatedObjectPreviewTextInput(object sender, System.Windows.Input.TextCompositionEventArgs e)
        {
            TreatSelectedText();

            var position = GetNextCharacterPosition(AssociatedObject.SelectionStart);

            if (Keyboard.IsKeyToggled(Key.Insert))
            {
                //上書きモード
                if (Provider.Replace(e.Text, position))
                    position++;
            }
            else
            {
                //挿入モード
                if (Provider.InsertAt(e.Text, position))
                    position++;
            }

            position = GetNextCharacterPosition(position);

            RefreshText(position);

            e.Handled = true;
        }

        void AssociatedObjectPreviewKeyDown(object sender, KeyEventArgs e)
        {

            if (e.Key == Key.Space)
            {
                TreatSelectedText();

                var position = GetNextCharacterPosition(AssociatedObject.SelectionStart);

                if (Provider.InsertAt(" ", position))
                    RefreshText(position);

                e.Handled = true;
            }

            if (e.Key == Key.Back)
            {
                if (TreatSelectedText())
                {
                    RefreshText(AssociatedObject.SelectionStart);
                }
                else
                {
                    if (AssociatedObject.SelectionStart != 0)
                    {
                        if (Provider.RemoveAt(AssociatedObject.SelectionStart - 1))
                            RefreshText(AssociatedObject.SelectionStart - 1);
                    }
                }

                e.Handled = true;
            }

            if (e.Key == Key.Delete)
            {
                if (TreatSelectedText())
                {
                    RefreshText(AssociatedObject.SelectionStart);
                }
                else
                {

                    if (Provider.RemoveAt(AssociatedObject.SelectionStart))
                        RefreshText(AssociatedObject.SelectionStart);

                }

                e.Handled = true;
            }

        }

        private void AccociateObjectLostFocus(object sender, RoutedEventArgs e)
        {
            if (IsTime)
            {
                if(CheckTime(AssociatedObject.Text) != null)
                {
                    // Time is correct!
                }
                else
                {
                    AssociatedObject.Text = null;
                }
            }
        }

        /// <summary>
        /// 00:00形式のテキスト入力が正しくできているかどうか、違う場合はnullにする
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        private string CheckTime(string time)
        {
            if (time == null) return null;

            if (string.IsNullOrWhiteSpace(time)) return null;

            string[] HHmm = time.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries);
            if (HHmm.Length != 2) return null;

            int hour;
            int minute;
            if (!int.TryParse(HHmm[0], out hour)) return null;
            if (!int.TryParse(HHmm[1], out minute)) return null;

            if (hour < 0 || hour > 24) return null;
            if (minute < 0 || minute > 59) return null;

            return time;
        }

        /// <summary>
        /// ペースト対応
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Pasting(object sender, DataObjectPastingEventArgs e)
        {
            if (e.DataObject.GetDataPresent(typeof(string)))
            {
                var pastedText = (string)e.DataObject.GetData(typeof(string));

                TreatSelectedText();

                var position = GetNextCharacterPosition(AssociatedObject.SelectionStart);

                if (Provider.InsertAt(pastedText, position))
                {
                    RefreshText(position);
                }
            }

            e.CancelCommand();
        }

        /// <summary>
        /// Textの更新
        /// </summary>
        private void UpdateText()
        {
            //同じときは更新なし
            if (Provider.ToDisplayString().Equals(AssociatedObject.Text))
                return;

            var isSet = Provider.Set(AssociatedObject.Text);

            SetText(isSet ? Provider.ToDisplayString() : AssociatedObject.Text);
        }

        /// <summary>
        /// Provider.Textの整理
        /// </summary>
        /// <returns></returns>
        private bool TreatSelectedText()
        {
            if (AssociatedObject.SelectionLength > 0)
            {
                return Provider.RemoveAt(AssociatedObject.SelectionStart,
                                        AssociatedObject.SelectionStart + AssociatedObject.SelectionLength - 1);
            }
            return false;
        }

        private void RefreshText(int position)
        {
            SetText(Provider.ToDisplayString());

            AssociatedObject.SelectionStart = position;
        }

        /// <summary>
        /// Textをセットします
        /// </summary>
        /// <param name="text"></param>
        private void SetText(string text)
        {
            AssociatedObject.Text = string.IsNullOrWhiteSpace(text) ? string.Empty : text;
        }

        private int GetNextCharacterPosition(int startPosition)
        {
            var position = Provider.FindEditPositionFrom(startPosition, true);

            if (position == -1)
                return startPosition;
            else
                return position;
        }
    }
}

参考)
Blindmeis's Blog WPF – Masked Textbox Behavior  (ドイツ語のブログでした?)
Microsoft Document MaskedTextProvider クラス

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む