質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.61%

  • C#

    6870questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • WPF

    680questions

    Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

  • XAML

    246questions

    XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

  • 継承

    38questions

    継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。

WPF プロパティウィンドウのTEXT TEXTのXAML更新タイミング

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,640

noppuku

score 5

現在visual studio2013proでWPFカスタムコントロールを使い、テキストボックスを継承した
Number型のテキストボックスを作成しています。
作成したナンバー型のテキストボックスを実際に使った時のプロパティウィンドウでText欄があるのですが、
このText欄に文字が入力された場合エラーメッセージを出してText欄を0に戻すように作っています。
以下プログラム一部抜粋

該当のソースコード

 //グローバル変数
        private TextBox Textbox;

        //追加チェンジイベント
        private void NumberChanged(object sender, TextChangedEventArgs e)
      {
            int liValue;


            if (Textbox.IsFocused == true)
            {

                if (Textbox.Text == "" || Textbox.Text.Substring(0,1) == "0")
                {
                    Textbox.Text = "0";
                }
                else
                {
                    liValue = Int32.Parse(Textbox.Text);
                    //if (liValue > MaxValue || liValue < MinValue || Textbox.SelectionStart == 0)
                    if (liValue > MaxValue || liValue < MinValue )
                    {
                        Textbox.Text = gsText;
                    }
                }
                if (Textbox.Text == "")
                {
                    Textbox.Text = "0";
                }
            }
            else
            {
                int i = 0;
                bool result = int.TryParse(Textbox.Text, out i);


                if (result == false)
                {
                    MessageBox.Show("プロパティの値が不正です。", "Microsoft Visual Studio",
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Error);


                    Text = "0";


                    return;
                }

                liValue = Int32.Parse(Textbox.Text);

                if (liValue > MaxValue || liValue < MinValue)
                {

                    MessageBox.Show("プロパティの値が不正です。", "Microsoft Visual Studio",
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Error);

                    Text = "0";

                }

            }

        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            this.Textbox = GetTemplateChild("Textbox") as TextBox;
            if (this.Textbox != null)
            {
                this.Textbox.TextChanged += this.NumberChanged;
                //DataObject.AddPastingHandler(Textbox, TextBoxPastingEventHandler);
            }

        }

    //最大数値設定
        [Browsable(true)]
        [Category("NumberConfig")]
        public int MaxValue { get; set; }


        //最小数値設定
        [Browsable(true)]
        [Category("NumberConfig")]
        public int MinValue { get; set; }

XAML
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:NumberTextBox">
    <Style TargetType="{x:Type local:NumberTextBox}">
        <Setter Property="Focusable" Value="False"/>
        <Setter Property="IsTabStop" Value="False"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:NumberTextBox}">
                    <TextBox x:Name="Textbox" Text="{Binding Path=Text,RelativeSource={RelativeSource TemplatedParent}}" FontWeight="Normal" TextAlignment="Right" MinWidth="120" 
                      InputMethod.PreferredImeState="On" InputMethod.PreferredImeConversionMode="Alphanumeric"   
                       InputMethod.IsInputMethodEnabled="False" SpellCheck.IsEnabled="True"           
                     />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>


上記のプログラムの構成は新しくテキストチェンジイベントを作成しチェンジイベントに対して
if文でフォーカス判定をします。フォーカスがない場合はIDEのプロパティウィンドウのテキストが
変更された場合の処理になっています。
このフォーカスがないパターンで実際に文字が入力された場合や、自前で作ったプロパティのMaxvalue
とMinvalueの範囲外だった場合はエラーメッセージを表示しプロパティウィンドウのテキストを0に戻しますが、
この時0に更新されたと同時にXAML側のTextも0に更新されてほしいのですが更新されません。
例としては
1.プロパティウィンドウのテキスト欄に"aaaa"と文字を入力します。
2.文字が入力されたのでプロパティウィンドウのテキスト欄が0に更新されます(デザイナの方も0に更新されます)。
3.XAMLも0に更新して欲しいが現状"aaaa"のままになってしまう。

WPFをやり始めたばかりゆえ根本的にやり方が間違っている可能性があるとは思うのですが、
問題の解決方法が分かる方がいましたらよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

ご提示いただいたソースはビルドが通らなかったので未検証です(gsTextが不明。コード足りない?)

ただ、XAMLの編集欄を強制的に書き換えるようなことは恐らくできないと思います
(逆にそれができてしまうとコードが勝手に書き換わっちゃうことになるので、嫌がる人も多いのでは?とも思います)

もっといえば、プロパティウィンドウに値を入れたタイミングでエラーダイアログを出すというのも、
ちょっと一般的な動きではないかなと思います。
例えばWidth欄などに数字以外を入れて確定しようとすると、無視されて元の値に戻りますよね?
(visual studio2013proを使っているわけではないので、もし違ったらすみません)

というわけでちょっとご質問の内容からずれてしまって恐縮ですが、
Width欄のように、単純に数字以外を設定させないようにするだけであれば、
TextBoxを内包(≠継承)するコントロールを作って、数値型でTextプロパティを作ってやれば実現できるので
これで良いなら簡単です。

一応サンプル載せておきます。
※カスタムコントロールだと何かとめんどくさいので、「ユーザーコントロール」を使ってます。
要件に合わなかったらすみません。

NumberTextBox.xaml

<UserControl x:Class="NumberTextBoxProj.NumberTextBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <TextBox x:Name="innerTextBox" MinWidth="120" TextChanged="innerTextBox_TextChanged" />
</UserControl>

NumberTextBox.xaml.cs

public partial class NumberTextBox : UserControl
{
    private decimal _text;

    public decimal Text //Binding 等したい場合は DependencyProperty にしてもいい
    {
        get
        {
            return _text;
        }
        set
        {
            if (_text == value) return;
            _text = value;
            refreshInnerTextBox();
        }
    }

    //外からTextBoxへ設定したいプロパティは こんなふうに透過する
    public TextAlignment TextAlignment
    {
        get
        {
            return innerTextBox.TextAlignment;
        }
        set
        {
            innerTextBox.TextAlignment = value;
        }
    }

    public NumberTextBox()
    {
        InitializeComponent();
        refreshInnerTextBox();
    }

    //TextChangedじゃなくてLostFocusのタイミングでやったほうが使いやすいかも
    private void innerTextBox_TextChanged(object sender, TextChangedEventArgs e)
    {
        decimal val;
        if (!decimal.TryParse(innerTextBox.Text, out val))
        {
            MessageBox.Show("ダメです");
            refreshInnerTextBox();
            return;
        }

        this.Text = val;
    }

    private void refreshInnerTextBox()
    {
        innerTextBox.Text = this.Text.ToString();
    }

}

※継承で実現したいとのことだったので、以下に別案を追記します。

TextChanged内で例外を投げるようにしておけば、
XAML編集欄を勝手に書き換えないまでも、エラーの下線は表示されるので事足りるのではないかと思います。

public class NumericTextBox : TextBox
{
    static NumericTextBox()
    {
        TextProperty.OverrideMetadata(typeof(NumericTextBox), new FrameworkPropertyMetadata("0", onTextChanged));
    }

    private static void onTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
    {
        var input = e.NewValue as string;

        decimal _;
        if (!decimal.TryParse(input, out _))
        {
            MessageBox.Show("ダメです");

            if (DesignerProperties.GetIsInDesignMode(sender))
            {
                //デザイナ上では例外をなげる
                throw new ArgumentException("ダメです");
            }

            //実行中は0に戻す
            (sender as NumericTextBox).Text = "0";
        }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/11 09:21 編集

    回答ありがとうございます。
    背景を説明するとややこしくなりそうなので本文に一切書いてないのですが、実際はTextboxを継承したカラーテキストボックスがあり、それを継承して現在のナンバーテキストボックスを作るような形で作っております。
    今後コントロールを作っていく中で機能を継承してコントロールを作るような形にしていきたいと考えているので継承が望ましいのでは思っています。
    テキストボックスを内包するというようなやり方は知りませんでしたので、今後の制作の参考にしたいと思います。
    本文に関して、こちらの目的をもう少しはっきりさせておくべきでした申し訳ないです。

    キャンセル

  • 2017/01/11 10:16

    継承で実現する別案を追記しました。

    キャンセル

  • 2017/01/11 10:46

    継承での方法の追記ありがとうございます。
    何度も申し訳ないのですが、XAMLの方も追記してただけると非常に助かります。

    キャンセル

  • 2017/01/11 11:00

    XAMLは無いです。
    普通にクラスの追加でTextBox継承クラスを作っただけですが、TextBoxと同じようにデザイナで扱えます。
    自前のColorTextBox的なのを継承したいということでしたら、継承元クラスをTextBoxでなくそのColorTextBoxにして、同じように作っていただければ。

    キャンセル

  • 2017/01/11 11:57

    普通にクラスの追加で作るというのは新規作成でWPFアプリケーションを選択してプロジェクトを作り、そのプロジェクトにクラスの追加をしビルドをしてDLLを作成ということでしょうか?
    WPFカスタムコントロールかWPFユーザコントロールでしかコントロールを作成したことがないのでその辺が曖昧ですみません。

    キャンセル

  • 2017/01/11 12:16

    通常のクラスをプロジェクトに追加するのと同様の手順という意味です。

    カスタムコントロールならば、プロジェクトに対し新しい項目の追加で「カスタム コントロール (WPF)」を選択して作成すると思います。
    その際に、ただ代わりに「クラス」を選択して作成するだけです。

    試しに適当なHogeTextBoxクラスを作って、 `public class HogeTextBox` の右に `: TextBox` と書き足して(上に `using System.Windows.Controls;` も追加して)ビルドしてみてください。
    デザイナ上でカスタムコントロールと同じように使えると思います。

    というか、すでに作ったカスタムコントロールがあるならば、そこに、上に追記した処理(staticコンストラクタとTextChangedのハンドラ)を書き足していただく形でも良いと思います。

    とりあえず試してみてから、うまくいかないところがあれば質問してください。

    キャンセル

  • 2017/01/11 13:18

    こちらのやりたいことが本文の中に抜けている部分のせいで、恐らく認識のずれがありそうなので確認を致します(違ってたらすみません)。

    コントロールの作成なのですが、これは作成したコントロールをdllにして誰でも使えるようにするというのが目標となっています。
    つまり、ツールボックスを右クリックしアイテムの選択より自作したコントロールのdllを参照より追加することでツールボックスから使えるようにするといった形です。
    もしかしたらこのやり方自体が間違っているのかもしれませんが、こういう風な形で進めている状況です。

    キャンセル

  • 2017/01/11 13:46

    > コントロールの作成なのですが、これは作成したコントロールをdllにして誰でも使えるようにするというのが目標となっています。

    上記のように試してみたがうまくいかなかったということでしょうか?
    dll化する場合も、カスタムコントロールでも普通のクラスでも手順は変わらないと思います。
    1. dll用のクラスライブラリプロジェクトを作成
    2. そのプロジェクトに自作テキストボックスクラスを作ってビルドする
    3. それを使用するWPFプロジェクト側で参照して利用

    試してうまくいかないということであれば、どの点がうまくいかないのかを教えてください
    (さすがにVisualStudioの使い方全部は説明できないです…)

    キャンセル

  • 2017/01/12 13:26

    自分の方でやった手順について書いてみましたので、おかしい箇所を教えていただけたらと思います。

    手順
    1.新規プロジェクトWPFアプリケーションを作成
    2.app.xaml削除、MainWindow.xaml削除
    3.プロジェクトに新しい項目の追加でClassを追加
    4.追加したクラスに回答いただいたTextboxクラスを継いだNumericTextBoxを作成
    5.ビルドはOK
    6.ツールボックスよりdllを参照から追加しようとするとエラー「ツールボックスに配置できるコンポーネントがありません」とでます。

    以上です。

    キャンセル

  • 2017/01/12 14:04

    > 1.新規プロジェクトWPFアプリケーションを作成

    ・dllプロジェクトを「WPFアプリケーション」として作る場合、プロジェクトのプロパティで
     「出力の種類」を「クラス ライブラリ」にしてください
     (ビルドできてるとのことなので大丈夫かと思いますが)

    > 6.ツールボックスよりdllを参照から追加しようとするとエラー「ツールボックスに配置できるコンポーネントがありません」とでます。

    ・「参照の追加」は、dllのプロジェクト側ではなく、dllを利用するWPFアプリのプロジェクト側で行います
     (そうされているようでしたら問題ないです)
    ・「参照の追加」は「ツールボックス」ではなく、「ソリューションエクスプローラー」から行います
     (プロジェクトの「参照設定」上で右クリック>参照の追加>「ソリューション」からプロジェクトを選ぶか、「参照」でdllを選択)
    ・上記のとおり参照を追加してからビルドすると、WPFアプリ側のXAMLデザイナで、
     「ツールボックス」に「NumericTextBox」が表示されるかと思います
     ※表示されない場合、NumericTextBox のclassがpublic になっているか確認してください

    キャンセル

  • 2017/01/12 14:10

    追記です。
    もう1点、VisualStudioの設定で、
    ツール>オプション>Windows フォームデザイナー>「ツールボックスを自動取得する」
    がTrueになっていることを確認してください。

    キャンセル

  • 2017/01/12 14:42

    アドバイスありがとうございます。
    初歩的な話でPublicをつけ忘れていました。大変申し訳ございません。

    実際に動かしてみたのですが、やはりプロパティウィンドウの値とXAMLの値が
    違ってしまうのはは仕方ないことなのでしょうか?

    手順
    1.作成したNumericTextBoxをデザイナに張り付け
    2.張り付けたNumericTextBoxのプロパティウィンドウのテキスト欄に
     文字「aaaa」を入力
    3.プロパティウィンドウのテキスト欄「aaaa」→「0に更新」
     デザイナのテキスト欄「aaaa」→「0に更新」
    XAMLのText「aaaa」のままになる
    <WpfApplication5:NumericTextBox HorizontalAlignment="Left" TextWrapping="Wrap" Ve rticalAlignment="Top" Margin="245,205,0,0" Text="aaaa"/>
                                ↑
                            ここの「aaaa」が「0」に変わってほしい
    やはりこれは回答をいただいたように、仕様でコード上から更新した場合はXAMLは更新されないものなのでしょうか?
    何度も同じようなことを聞いてすみません。

    キャンセル

  • 2017/01/12 15:11

    少なくとも僕の知識の範囲内では「仕方ない」という回答になります。すみません。

    コード側からXAMLを書き換えることはできないため、代案として
    ・そもそもTextプロパティに文字列を代入させない(=数値型にする)
    ・IDE上でエラーを意味する下線を表示させる(XAMLでWidth="aa"などと書いた場合と同じ)
    という2点を提案させていただきました。

    以下は完全に個人的な意見ですが、
    「dllにして誰でも使えるようにする」という目的でしたらなおのこと、
    XAMLを勝手に書き換えたり、デザイナ上でエラーダイアログを出したりなど独特の動きをさせるよりも
    他の標準部品の作法に沿って作っておくほうが使いやすいものになるのではないかと思います。

    キャンセル

  • 2017/01/12 15:23

    私の疑問に長々とお付き合いただき、本当にありがとうございました。
    やはりコード上からXAMLの書き換えは無理なのですね。
    できないものは仕方ないので、提案して頂いた案を参考にコントロールを作成していきたいと
    思います。

    キャンセル

-1

こんにちは
私もほぼ初心者なので、合っているかわかりませんが
Binding Path=Text,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged
に変えてみたらどうでしょうか

もしくは、MVVMモデルに変更して
INotifyPropertyChangedを実装してみたらいいと思います

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/10 13:25

    回答ありがとうございます。
    UpdateSourceTriggerは既に使ってみたのですが,プロパティウィンドウでは作用しないようです。
    INotifyPropertyChangedは調べてるうちに方法としてあるのは知っていたのですが、使い方がよくわからなかったので実装していませんでした。
    調べてみて実装できないか改めて検討してみます。

    キャンセル

  • 2017/01/10 14:26

    すみません。的外れでした
    INotifyPropertyChangedでは駄目みたいです

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C#

    6870questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • WPF

    680questions

    Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

  • XAML

    246questions

    XAML(Extensible Application Markup Language)はWPF、Silverlight、Windows PhoneそしてWindows Store appsでユーザーインターフェースを定義するために使われるXML言語です。

  • 継承

    38questions

    継承(インヘリタンス)はオブジェクト指向プログラミングに存在するシステムです。継承はオブジェクトが各自定義する必要をなくし、継承元のオブジェクトで定義されている内容を引き継ぎます。