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

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

新規登録して質問してみよう
ただいま回答率
85.51%
C#

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

XAML

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

継承

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

WPF

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

Q&A

解決済

2回答

5216閲覧

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

noppuku

総合スコア13

C#

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

XAML

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

継承

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

WPF

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

0グッド

0クリップ

投稿2017/01/10 01:46

編集2017/01/10 03:34

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

###該当のソースコード

C#

1 //グローバル変数 2 private TextBox Textbox; 3 4 //追加チェンジイベント 5 private void NumberChanged(object sender, TextChangedEventArgs e) 6 { 7 int liValue; 8 9 10 if (Textbox.IsFocused == true) 11 { 12 13 if (Textbox.Text == "" || Textbox.Text.Substring(0,1) == "0") 14 { 15 Textbox.Text = "0"; 16 } 17 else 18 { 19 liValue = Int32.Parse(Textbox.Text); 20 //if (liValue > MaxValue || liValue < MinValue || Textbox.SelectionStart == 0) 21 if (liValue > MaxValue || liValue < MinValue ) 22 { 23 Textbox.Text = gsText; 24 } 25 } 26 if (Textbox.Text == "") 27 { 28 Textbox.Text = "0"; 29 } 30 } 31 else 32 { 33 int i = 0; 34 bool result = int.TryParse(Textbox.Text, out i); 35 36 37 if (result == false) 38 { 39 MessageBox.Show("プロパティの値が不正です。", "Microsoft Visual Studio", 40 MessageBoxButton.OK, 41 MessageBoxImage.Error); 42 43 44 Text = "0"; 45 46 47 return; 48 } 49 50 liValue = Int32.Parse(Textbox.Text); 51 52 if (liValue > MaxValue || liValue < MinValue) 53 { 54 55 MessageBox.Show("プロパティの値が不正です。", "Microsoft Visual Studio", 56 MessageBoxButton.OK, 57 MessageBoxImage.Error); 58 59 Text = "0"; 60 61 } 62 63 } 64 65 } 66 67 public override void OnApplyTemplate() 68 { 69 base.OnApplyTemplate(); 70 71 this.Textbox = GetTemplateChild("Textbox") as TextBox; 72 if (this.Textbox != null) 73 { 74 this.Textbox.TextChanged += this.NumberChanged; 75 //DataObject.AddPastingHandler(Textbox, TextBoxPastingEventHandler); 76 } 77 78 } 79 80 //最大数値設定 81 [Browsable(true)] 82 [Category("NumberConfig")] 83 public int MaxValue { get; set; } 84 85 86 //最小数値設定 87 [Browsable(true)] 88 [Category("NumberConfig")] 89 public int MinValue { get; set; } 90 91XAML 92<ResourceDictionary 93 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 94 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 95 xmlns:local="clr-namespace:NumberTextBox"> 96 <Style TargetType="{x:Type local:NumberTextBox}"> 97 <Setter Property="Focusable" Value="False"/> 98 <Setter Property="IsTabStop" Value="False"/> 99 <Setter Property="Template"> 100 <Setter.Value> 101 <ControlTemplate TargetType="{x:Type local:NumberTextBox}"> 102 <TextBox x:Name="Textbox" Text="{Binding Path=Text,RelativeSource={RelativeSource TemplatedParent}}" FontWeight="Normal" TextAlignment="Right" MinWidth="120" 103 InputMethod.PreferredImeState="On" InputMethod.PreferredImeConversionMode="Alphanumeric" 104 InputMethod.IsInputMethodEnabled="False" SpellCheck.IsEnabled="True" 105 /> 106 </ControlTemplate> 107 </Setter.Value> 108 </Setter> 109 </Style> 110</ResourceDictionary>

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

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

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

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

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

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

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

NumberTextBox.xaml

xml

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

NumberTextBox.xaml.cs

C#

1public partial class NumberTextBox : UserControl 2{ 3 private decimal _text; 4 5 public decimal Text //Binding 等したい場合は DependencyProperty にしてもいい 6 { 7 get 8 { 9 return _text; 10 } 11 set 12 { 13 if (_text == value) return; 14 _text = value; 15 refreshInnerTextBox(); 16 } 17 } 18 19 //外からTextBoxへ設定したいプロパティは こんなふうに透過する 20 public TextAlignment TextAlignment 21 { 22 get 23 { 24 return innerTextBox.TextAlignment; 25 } 26 set 27 { 28 innerTextBox.TextAlignment = value; 29 } 30 } 31 32 public NumberTextBox() 33 { 34 InitializeComponent(); 35 refreshInnerTextBox(); 36 } 37 38 //TextChangedじゃなくてLostFocusのタイミングでやったほうが使いやすいかも 39 private void innerTextBox_TextChanged(object sender, TextChangedEventArgs e) 40 { 41 decimal val; 42 if (!decimal.TryParse(innerTextBox.Text, out val)) 43 { 44 MessageBox.Show("ダメです"); 45 refreshInnerTextBox(); 46 return; 47 } 48 49 this.Text = val; 50 } 51 52 private void refreshInnerTextBox() 53 { 54 innerTextBox.Text = this.Text.ToString(); 55 } 56 57}

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

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

C#

1public class NumericTextBox : TextBox 2{ 3 static NumericTextBox() 4 { 5 TextProperty.OverrideMetadata(typeof(NumericTextBox), new FrameworkPropertyMetadata("0", onTextChanged)); 6 } 7 8 private static void onTextChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) 9 { 10 var input = e.NewValue as string; 11 12 decimal _; 13 if (!decimal.TryParse(input, out _)) 14 { 15 MessageBox.Show("ダメです"); 16 17 if (DesignerProperties.GetIsInDesignMode(sender)) 18 { 19 //デザイナ上では例外をなげる 20 throw new ArgumentException("ダメです"); 21 } 22 23 //実行中は0に戻す 24 (sender as NumericTextBox).Text = "0"; 25 } 26 } 27}

投稿2017/01/10 13:17

編集2017/01/11 01:15
oika

総合スコア425

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

noppuku

2017/01/11 00:32 編集

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

2017/01/11 01:16

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

2017/01/11 01:46

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

2017/01/11 02:00

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

2017/01/11 02:57

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

2017/01/11 03:16

通常のクラスをプロジェクトに追加するのと同様の手順という意味です。 カスタムコントロールならば、プロジェクトに対し新しい項目の追加で「カスタム コントロール (WPF)」を選択して作成すると思います。 その際に、ただ代わりに「クラス」を選択して作成するだけです。 試しに適当なHogeTextBoxクラスを作って、 `public class HogeTextBox` の右に `: TextBox` と書き足して(上に `using System.Windows.Controls;` も追加して)ビルドしてみてください。 デザイナ上でカスタムコントロールと同じように使えると思います。 というか、すでに作ったカスタムコントロールがあるならば、そこに、上に追記した処理(staticコンストラクタとTextChangedのハンドラ)を書き足していただく形でも良いと思います。 とりあえず試してみてから、うまくいかないところがあれば質問してください。
noppuku

2017/01/11 04:18

こちらのやりたいことが本文の中に抜けている部分のせいで、恐らく認識のずれがありそうなので確認を致します(違ってたらすみません)。 コントロールの作成なのですが、これは作成したコントロールをdllにして誰でも使えるようにするというのが目標となっています。 つまり、ツールボックスを右クリックしアイテムの選択より自作したコントロールのdllを参照より追加することでツールボックスから使えるようにするといった形です。 もしかしたらこのやり方自体が間違っているのかもしれませんが、こういう風な形で進めている状況です。
oika

2017/01/11 04:46

> コントロールの作成なのですが、これは作成したコントロールをdllにして誰でも使えるようにするというのが目標となっています。 上記のように試してみたがうまくいかなかったということでしょうか? dll化する場合も、カスタムコントロールでも普通のクラスでも手順は変わらないと思います。 1. dll用のクラスライブラリプロジェクトを作成 2. そのプロジェクトに自作テキストボックスクラスを作ってビルドする 3. それを使用するWPFプロジェクト側で参照して利用 試してうまくいかないということであれば、どの点がうまくいかないのかを教えてください (さすがにVisualStudioの使い方全部は説明できないです…)
noppuku

2017/01/12 04:26

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

2017/01/12 05:04

> 1.新規プロジェクトWPFアプリケーションを作成 ・dllプロジェクトを「WPFアプリケーション」として作る場合、プロジェクトのプロパティで  「出力の種類」を「クラス ライブラリ」にしてください  (ビルドできてるとのことなので大丈夫かと思いますが) > 6.ツールボックスよりdllを参照から追加しようとするとエラー「ツールボックスに配置できるコンポーネントがありません」とでます。 ・「参照の追加」は、dllのプロジェクト側ではなく、dllを利用するWPFアプリのプロジェクト側で行います  (そうされているようでしたら問題ないです) ・「参照の追加」は「ツールボックス」ではなく、「ソリューションエクスプローラー」から行います  (プロジェクトの「参照設定」上で右クリック>参照の追加>「ソリューション」からプロジェクトを選ぶか、「参照」でdllを選択) ・上記のとおり参照を追加してからビルドすると、WPFアプリ側のXAMLデザイナで、  「ツールボックス」に「NumericTextBox」が表示されるかと思います  ※表示されない場合、NumericTextBox のclassがpublic になっているか確認してください
oika

2017/01/12 05:10

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

2017/01/12 05: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は更新されないものなのでしょうか? 何度も同じようなことを聞いてすみません。
oika

2017/01/12 06:11

少なくとも僕の知識の範囲内では「仕方ない」という回答になります。すみません。 コード側からXAMLを書き換えることはできないため、代案として ・そもそもTextプロパティに文字列を代入させない(=数値型にする) ・IDE上でエラーを意味する下線を表示させる(XAMLでWidth="aa"などと書いた場合と同じ) という2点を提案させていただきました。 以下は完全に個人的な意見ですが、 「dllにして誰でも使えるようにする」という目的でしたらなおのこと、 XAMLを勝手に書き換えたり、デザイナ上でエラーダイアログを出したりなど独特の動きをさせるよりも 他の標準部品の作法に沿って作っておくほうが使いやすいものになるのではないかと思います。
noppuku

2017/01/12 06:23

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

0

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

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

投稿2017/01/10 04:00

編集2017/01/10 04:07
dn315

総合スコア200

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

noppuku

2017/01/10 04:25

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

2017/01/10 05:26

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問