今回はC# WPF でxaml ファイルで定義したコントロールを初期化子で参照する方法について書きます。
結論を先に言うと、初期化子で直接参照することはできません。
代替案として、FindNameメソッドでコントロール名からコントロールを検索するようにしました。
やりたいこと

上記ウィンドウにコンボボックスが2つあります。
<Window x:Class="Test_Static.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:Test_Static" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" DataContext="x:Static"> <Grid> <ComboBox x:Name="Combo1" HorizontalAlignment="Left" Margin="45,25,0,0" VerticalAlignment="Top" Width="140" Height="30"/> <ComboBox x:Name="Combo2" HorizontalAlignment="Left" Margin="45,70,0,0" VerticalAlignment="Top" Width="140" Height="30"/> </Grid> </Window>
xamlファイルは上記のとおりです。
ここで、ComboBoxのx:Name 属性にそれぞれCombo1、Combo2と設定しました。
そのx;Name属性を設定したコントロールを、csファイルの初期化子で参照できるようにしたいです。
using System; using System.Windows; using System.Windows.Controls; namespace Test_Static { // MainWindow.xaml の相互作用ロジック public partial class MainWindow : Window { // コンボボックス設定リストのクラス private class TestComboSet { public String[] list; public int id; public ComboBox combo; } // コンボボックス設定リストのオブジェクト private TestComboSet[] testComboSet = new TestComboSet[] { new TestComboSet() { list = new String[]{"A","B","C"}, id = 1, /*** ここでXamlで定義したコンボボックスを参照したい ***/ }, new TestComboSet() { list = new String[]{"D","E","F"}, id = 2, /*** ここでXamlで定義したコンボボックスを参照したい ***/ } }; public MainWindow() { InitializeComponent(); foreach( TestComboSet testComboSet in testComboSet ) { /*** ここでコンボボックスにリストを設定する ***/ } } } }
- MainWindowのフィールドに、TestComboSet型の配列testComboSetを定義します。
- testComboSetの初期化子でXaml で定義したコンボボックスを参照します。
- コンストラクタで、コンボボックスにリストを設定をしたいです。
- Windows10
- Microsoft Visual Studio Community2019
- .NET Framework 4.7.2
- WPF アプリ( .NET Framework )
初期化子でコントロールの参照はできない
単純に初期化子でコントロールの参照をする場合は下記のようになります。しかし、この方法だとエラーになります。
// コンボボックス設定リストのオブジェクト private TestComboSet[] testComboSet = new TestComboSet[] { new TestComboSet() { list = new String[]{"A","B","C"}, id = 1, combo = Combo1 // ★★★ エラー }, new TestComboSet() { list = new String[]{"D","E","F"}, id = 2, combo = Combo2 // ★★★ エラー } };
エラー内容は、
エラー CS0236 フィールド初期化子は、静的でないフィールド、メソッド、またはプロパティ ‘MainWindow.Combo1’ を参照できません
プログラミングガイドには以下の記述があります。
フィールドの初期化子は、他のインスタンス フィールドを参照できません。
どうやら初期化子では、参照できないようです。
コンストラクタで初期化することは可能です。
// コンボボックス設定リストのオブジェクト private TestComboSet[] testComboSet = new TestComboSet[] { new TestComboSet() { list = new String[]{"A","B","C"}, id = 1, }, new TestComboSet() { list = new String[]{"D","E","F"}, id = 2, } }; public MainWindow() { InitializeComponent(); // ★★★ 初期化の設定が2か所になる testComboSet[0].combo = Combo1; // OK testComboSet[1].combo = Combo2; // OK foreach ( TestComboSet testComboSet in testComboSet ) { } }
でも、初期化子とコンストラクタで2か所で初期化することになります。保守性の観点で、初期化は1か所に固めておきたいところです。
FindName メソッドで参照する
そこで、初期化子ではコントロール名を記載して、コンストラクタでコントロールを参照する方針に変更します。
FindName メソッドを使うとコントロール名からコントロールを検索することができます。
なので、初期化子ではコントロール名を定義して、コンストラクタでコントロールを検索と設定をします。
具体的に↓のコードのようになります。
using System; using System.Windows; using System.Windows.Controls; namespace Test_Static { // MainWindow.xaml の相互作用ロジック public partial class MainWindow : Window { // コンボボックス設定リストのクラス private class TestComboSet { public String[] list; public int id; public String combo_name; // ★★★ 追加 public ComboBox combo; } // コンボボックス設定リストのオブジェクト private TestComboSet[] testComboSet = new TestComboSet[] { new TestComboSet() { list = new String[]{"A","B","C"}, id = 1, combo_name = "Combo1" // コントロール名 }, new TestComboSet() { list = new String[]{"D","E","F"}, id = 2, combo_name = "Combo2" // コントロール名 } }; public MainWindow() { InitializeComponent(); foreach ( TestComboSet testComboSet in testComboSet ) { // ★★★ コントロール名からコントロールを取得 testComboSet.combo = FindName(testComboSet.combo_name) as ComboBox; // コントロールにリストを設定 foreach( String s in testComboSet.list) { testComboSet.combo.Items.Add(s); } } } } }
- TestComboBoxクラスにコントロール名のフィールドを追加します。
- testComboSetの初期化子でコントロール名を設定します。
- コンストラクタでFindNameメソッドで、コントロール名からコントロールを検索し設定します。
この方法だと、初期化が初期化子のみでできます。1か所でできたので、すっきり書けます。
コードの実行結果

コンボボックスの参照ができて、リストの設定もできました。
まとめ
今回はC# WPF でxaml ファイルで定義したコントロールを初期化子で参照する方法について書きました。
初期化子で直接参照することはできません。
FindNameメソッドでコントロール名からコントロールを検索しました。
コメントを残す