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

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

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

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

WPF

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

Q&A

解決済

2回答

2046閲覧

WPFでアプリ起動時にテキストボックスがNullエラーになってしまいます

Wind

総合スコア442

C#

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

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

WPF

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

1グッド

0クリップ

投稿2022/12/21 00:32

編集2022/12/21 02:23

前提

アプリ起動時にテキストボックスがNullエラーになるのを回避したいです。

実現したいこと

現在はテキストボックスがnullなら抜ける様にして回避していますが、WinFormsのように意識せず動くようにしたいです。

発生している問題・エラーメッセージ

System.NullReferenceException HResult=0x80004003 Message=オブジェクト参照がオブジェクト インスタンスに設定されていません。 Source=WpfApp2 スタック トレース: at WpfApp2.MainWindow.DatePicker_SelectedDateChanged(Object sender, SelectionChangedEventArgs e) in C:\VS2022\CS\wfp\Test\WpfApp2\WpfApp2\MainWindow.xaml.cs:line 32

該当のソースコード

XAML

1<Window x:Class="WpfApp2.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfApp2" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="450" Width="800"> 9 <Grid> 10 <DatePicker HorizontalAlignment="Left" Height="39" Margin="203,66,0,0" VerticalAlignment="Top" Width="113" SelectedDate="2023/01/01" SelectedDateChanged="DatePicker_SelectedDateChanged"/> 11 <TextBox Name="txtBox" HorizontalAlignment="Left" Height="52" Margin="203,165,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="113"/> 12 </Grid> 13</Window>

C#

1namespace WpfApp2 2{ 3 public partial class MainWindow : Window 4 { 5 public MainWindow() 6 { 7 InitializeComponent(); 8 } 9 10 private void DatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) 11 { 12 //if (txtBox == null) return; // これが無いと、起動時にNullエラーとなる 13 txtBox.Text = "test"; 14 } 15 } 16}

試したこと

テキストボックスがnullならreturnで回避した。

補足情報(FW/ツールのバージョンなど)

Visual Studio 2022
Framework 4.7.2

[追記:質問文以外に原因があるか、キャプチャ画像で表示]
Xaml画面
C#画面

TN8001👍を押しています

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2022/12/21 01:16

> WPFでアプリ起動時にテキストボックスがNullエラーになってしまいます DatePicker と TextBox だけ配置して SelectedDateChanged イベントのハンドラを追加したコードでそういうことはないのですが? 質問に書いてない何かが影響しているのでは?
Wind

2022/12/21 02:15

コメントありがとうございます。 新規プロジェクトにて作成しエラー確認したミニマムコードを貼り付けていますので、usingや自動生成のコメントは省きましたが、質問に書いている事が全てになります。 キャプチャ画像も表示した方がよろしいでしょうか?
Zuishin

2022/12/21 02:36

試していませんが、DatePicker が作成された時に TextBox が無いならそういうこともあるかもしれませんね。 基本はコントロールから別のコントロールを直接操作せず、データバインディングを使うことです。 直接使いたいなら null チェックはむしろ行うべきです。 #nullable enable を一行目に書けば、null チェックをしない場合に警告が表示されると思います。
退会済みユーザー

退会済みユーザー

2022/12/21 03:56

念のため質問者さんと同じ .NET Framework 4.7.2 で新たにプロジェクトを作り、デザイン画面でツールボックスから DatePicker と TextBox を MainWindow にドラッグ&ドロップして、イベントハンドラを設定して試してみましたが、 > WPFでアプリ起動時にテキストボックスがNullエラーになってしまいます ということはなかったです。あとで回答欄に画像などを貼っておきます。
Wind

2022/12/21 04:13

ありがとうございます。 DataPickerとTextBoxの行を逆にしたところ、Nullエラーは消えました。 XAMLは上から作成されるようです。 但し根本的な解決では無いので、データバインディングを使うようにします。
退会済みユーザー

退会済みユーザー

2022/12/21 04:24

TN8001 さんの回答を見て気が付いたのですが XAML で SelectedDate を指定していたんですね。それが設定される時点で SelectedDateChanged イベントが発生するので、 > WPFでアプリ起動時にテキストボックスがNullエラーになってしまいます となってしまうということですね。回避策を回答欄に書いておきます。
Wind

2022/12/21 05:01

はい、XAMLのDatePicker行で中に記述しているSelectedDateやSelectedDateChangedも動いて、次の行のTextBoxがまだ作られていないのでエラーになっていました。
guest

回答2

0

ベストアンサー

基本的にxamlは上から順に生成されていきます。

今回のようにイベントがすぐ飛ぶ状態(SelectedDateSelectedDateChangedともに指定)ですと、xamlで下にある要素がまだない状態でイベントが来てしまいます。
動作的にはイヤなのですが、これは今後も変わることはないと思います。

でどうするかですが、

案1

提示コードのようにnullチェックする。
ばかばかしいが安全ではある。

そのうちtxtBox?.Text = "test";こういう構文が、許されるようになるかもしれない(今はないしいつ来るかももわからない)
csharplang/null-conditional-assignment.md at main · dotnet/csharplang

案2

単純な解決法は、xaml上でTextBoxが先に来るようにする。
しかし順番次第でエラーになることがあるのはやや不安が残る。

案3

SelectedDateSelectedDateChangedどちらかを、InitializeComponent後に設定する。
全部できてからイベントが飛ぶようにすれば安心だが、少し不格好かもしれない。

案4

何をしたいかにもよるが、バインドで用が済むなら一番良い。

xml

1<Window 2 x:Class="Q9jmho7nu44o3nz.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 Width="800" 6 Height="450"> 7 <UniformGrid> 8 <GroupBox Header="nullチェック必要"> 9 <StackPanel> 10 <DatePicker SelectedDate="2023/01/01" SelectedDateChanged="DatePicker_SelectedDateChanged" /> 11 <TextBox Name="txtBox" /> 12 </StackPanel> 13 </GroupBox> 14 15 <GroupBox Header="TextBoxを先に書く"> 16 <Grid> 17 <Grid.RowDefinitions> 18 <RowDefinition Height="Auto" /> 19 <RowDefinition Height="Auto" /> 20 </Grid.RowDefinitions> 21 <TextBox Name="txtBox2" Grid.Row="1" /> 22 <DatePicker SelectedDate="2023/01/01" SelectedDateChanged="DatePicker2_SelectedDateChanged" /> 23 </Grid> 24 </GroupBox> 25 26 <GroupBox Header="Initialize後 設定"> 27 <StackPanel> 28 <DatePicker x:Name="datePicker3" SelectedDateChanged="DatePicker3_SelectedDateChanged" /> 29 <TextBox Name="txtBox3" /> 30 </StackPanel> 31 </GroupBox> 32 33 <GroupBox Header="バインド"> 34 <StackPanel> 35 <DatePicker x:Name="datePicker4" SelectedDate="2023/01/01" /> 36 <TextBox Text="{Binding SelectedDate, StringFormat=yyyy/MM/dd, ElementName=datePicker4, Mode=OneWay}" /> 37 </StackPanel> 38 </GroupBox> 39 </UniformGrid> 40</Window>

cs

1using System; 2using System.Windows; 3using System.Windows.Controls; 4 5namespace Q9jmho7nu44o3nz 6{ 7 public partial class MainWindow : Window 8 { 9 public MainWindow() 10 { 11 InitializeComponent(); 12 13 datePicker3.SelectedDate = DateTime.Parse("2023/01/01"); 14 } 15 16 private void DatePicker_SelectedDateChanged(object sender, SelectionChangedEventArgs e) 17 { 18 if (txtBox == null) return; // これが無いと、起動時にNullエラーとなる 19 if (sender is DatePicker picker) 20 { 21 txtBox.Text = picker.SelectedDate?.ToString("d"); 22 } 23 } 24 private void DatePicker2_SelectedDateChanged(object sender, SelectionChangedEventArgs e) 25 { 26 if (sender is DatePicker picker) 27 { 28 txtBox2.Text = picker.SelectedDate?.ToString("d"); 29 } 30 } 31 private void DatePicker3_SelectedDateChanged(object sender, SelectionChangedEventArgs e) 32 { 33 if (sender is DatePicker picker) 34 { 35 txtBox3.Text = picker.SelectedDate?.ToString("d"); 36 } 37 } 38 } 39}

やりたい事は選択した日付からn日後を計算して表示する事でしたが、WPFの基本的なところでハマっていました。

ViewModelで計算したプロパティを用意するパターンと、Converterで計算するパターン例。
実際はViewModelレスというわけにもいかないので、この中間くらい(ViewModelに必要ない値はConverterで計算)になることが多いと思います。

xml

1<Window 2 x:Class="Q9jmho7nu44o3nz.MainWindow" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:local="clr-namespace:Q9jmho7nu44o3nz" 6 xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" 7 Width="800" 8 Height="450"> 9 <Window.DataContext> 10 <local:ViewModel /> 11 </Window.DataContext> 12 <Window.Resources> 13 <local:DaysLaterConverter x:Key="DaysLaterConverter" /> 14 </Window.Resources> 15 <UniformGrid> 16 <GroupBox Header="ViewModel"> 17 <StackPanel> 18 <DatePicker SelectedDate="{Binding SelectedDate}" /> 19 <xctk:IntegerUpDown Minimum="0" Value="{Binding DaysLater}" /> 20 <TextBlock HorizontalAlignment="Right" Text="日後" /> 21 <TextBox Text="{Binding SelectedDateDaysLater, StringFormat=yyyy/MM/dd, Mode=OneWay}" /> 22 </StackPanel> 23 </GroupBox> 24 25 <GroupBox Header="Converter"> 26 <StackPanel> 27 <DatePicker x:Name="datePicker" SelectedDate="2023/01/01" /> 28 <xctk:IntegerUpDown 29 x:Name="integerUpDown" 30 Minimum="0" 31 Value="0" /> 32 <TextBlock HorizontalAlignment="Right" Text="日後" /> 33 <TextBox> 34 <TextBox.Text> 35 <MultiBinding 36 Converter="{StaticResource DaysLaterConverter}" 37 Mode="OneWay" 38 StringFormat="yyyy/MM/dd"> 39 <Binding ElementName="datePicker" Path="SelectedDate" /> 40 <Binding ElementName="integerUpDown" Path="Value" /> 41 </MultiBinding> 42 </TextBox.Text> 43 </TextBox> 44 </StackPanel> 45 </GroupBox> 46 </UniformGrid> 47</Window>

cs

1using System; 2using System.Globalization; 3using System.Windows; 4using System.Windows.Data; 5using CommunityToolkit.Mvvm.ComponentModel; 6 7namespace Q9jmho7nu44o3nz 8{ 9 public class ViewModel : ObservableObject 10 { 11 // ソースジェネレーター(LangVersion 8以上)を使えれば、もっとすっきり書けるのだが... 12 // [ObservableProperty 属性 - .NET Community Toolkit | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/communitytoolkit/mvvm/generators/observableproperty#notifying-dependent-properties) 13 public int DaysLater 14 { 15 get => _DaysLater; 16 set 17 { 18 if (SetProperty(ref _DaysLater, value)) 19 OnPropertyChanged(nameof(SelectedDateDaysLater)); 20 } 21 } 22 private int _DaysLater; 23 24 public DateTime? SelectedDate 25 { 26 get => _SelectedDate; 27 set 28 { 29 if (SetProperty(ref _SelectedDate, value)) 30 OnPropertyChanged(nameof(SelectedDateDaysLater)); 31 } 32 } 33 private DateTime? _SelectedDate = DateTime.Parse("2023/01/01"); 34 35 public DateTime? SelectedDateDaysLater => SelectedDate?.AddDays(DaysLater); 36 } 37 38 class DaysLaterConverter : IMultiValueConverter // 雑いw 39 { 40 public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 41 { 42 if (values[0] is DateTime d && values[1] is int i) 43 return d.AddDays(i); 44 return null; 45 } 46 public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) => throw new NotImplementedException(); 47 } 48 49 50 public partial class MainWindow : Window 51 { 52 public MainWindow() => InitializeComponent(); 53 } 54}

NuGet Gallery | CommunityToolkit.Mvvm 8.0.0
MVVM Toolkit の概要 - .NET Community Toolkit | Microsoft Learn

NuGet Gallery | Extended.Wpf.Toolkit 4.5.0
IntegerUpDown · xceedsoftware/wpftoolkit Wiki

投稿2022/12/21 03:20

編集2022/12/21 09:07
TN8001

総合スコア9315

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

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

Wind

2022/12/21 05:10

色んなパターンの回答をありがとうございます。 やりたい事は選択した日付からn日後を計算して表示する事でしたが、WPFの基本的なところでハマっていました。 WPFは出来るだけバインド(関係付け?)で処理した方が良さそうですね。 まだ理解出来ておりませんがMVVMを活かすには必要そうなので、勉強してみます。
TN8001

2022/12/21 09:07

> WPFは出来るだけバインド(関係付け?)で処理した方が良さそうですね。 > まだ理解出来ておりませんがMVVMを活かすには必要そうなので、勉強してみます。 例を追記しておきました。 WPFはMVVMでやることが前提のようなところがあります。 もちろんコードビハインドのみでもできないことはないんですが、バインドに慣れてくるとMVVMのほうが楽に感じてきます。 最初はとっつきにくいところはありますが、がんばってください^^
guest

0

今頃気づいて何ですが、XAML で DatePicker の SelectedDate を設定していたんですね。

それが設定される時点で SelectedDateChanged イベントが発生し、その時点では TextBox は初期化されてないので、

WPFでアプリ起動時にテキストボックスがNullエラーになってしまいます

というエラーとなってしまうということだったのですね。

回避策は TextBox が初期化されてから、即ち MainWindow のコンストラクタで InitializeComponent(); が実行されてから、datePicker.SelectedDate を設定するということでいかがですか?

イメージ説明

投稿2022/12/21 04:36

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

Wind

2022/12/21 05:05

XAMLではコントロール配置の記述だけ行い、イベントが発生する物はcs内の`InitializeComponent()`の後で記述するのですね。 ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問