none
binding sourceのListは更新できない RRS feed

  • 質問

  • はじめまして、binding の問題です、binding sourceのList<string>は更新できない

    ListBox の ItemsSource は x:Static local:MainWindow.slTmp

            public static List<string> slTmp;
            
            public MainWindow()
            {
                slTmp = new List<string>();
                slTmp.Add("1");
                slTmp.Add("2");
                slTmp.Add("3");
    


    .....

    listboxの中で、TextBox をいりたいですが、エラーが発生( Two-way binding requires Path or XPath)

    listboxのItemTemplateは:               

    <DataTemplate>

                 <TextBox Text="{Binding Mode=TwoWay,UpdateSourceTrigger=LostFocus}" />

    </DataTemplate>

    RelativeSource Selfを入れたら、エラーは発生しないが、TextBox.Textの更新はsourceのlistに届かないようです、どうすれば更新できるでしょうか

    <DataTemplate>

               <TextBox Text="{Binding Path=DataContext, RelativeSource={RelativeSource Self},Mode=TwoWay,UpdateSourceTrigger=LostFocus}"/>

    </DataTemplate>

    xaml:       

    <ListBox Height="287" HorizontalAlignment="Left" Margin="12,12,0,0" Name="listBox1" VerticalAlignment="Top" Width="145" ItemsSource="{x:Static local:MainWindow.slTmp}">            
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <TextBox Text="{Binding Path=DataContext, RelativeSource={RelativeSource Self},Mode=TwoWay,UpdateSourceTrigger=LostFocus}"></TextBox>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>




     

    • 編集済み nobuyaki 2011年9月4日 1:30
    2011年9月3日 9:23

回答

  • すみません。おかしなことを書いていました。m(_ _)m
    バインディングしてるオブジェクト自体を書き換えることができないのは値型参照型関係ありませんし、そもそも String は参照型です。

    リストにおけるオブジェクトを挿げ替えることはできませんが、参照型であればオブジェクトを書き換えることができます。Stringはおっしゃる通りごく普通の参照型です。値型のようにふるまうというのが脳内変換されて誤ったことを書いてしまいました。ご指摘ありがとうございます。

    #(追記)nobuyakiさんへ。stringについて誤ったことを書きました。ごめんなさい。stringについては最近以下に書いていますので、参考になればと思います。

    2つのList 内のオブジェクトをリンクさせる方法を教えてください
    http://social.msdn.microsoft.com/Forums/ja-JP/csharpgeneralja/thread/96df3709-fbef-41dd-94ab-0bed14476030/

     

    例えばリストの個々の String をテキストボックスにバインディングしたとして、テキストボックスからはその文字列が元のリストの何処に配置されているのか判らないので、勝手に新しい文字列インスタンスを作って自分のバインディング対象を置き換えても、リストの参照先を書き換えることができません(あるいはそのリストは読み取り専用かもしれない)。禁止されているのはそう言う理由でしょう。


    おっしゃる通りですね。
    改めて説明を以下のように修正させていただきます。

    今回の件は、メソッドの引数としてstringを渡した場合とクラスのインスタンスを渡した場合を考えればよくわかると思います。メソッドに渡されたstringを書き換えても渡す前の、つまりメソッド外のstringオブジェクトを書き換えることはできませんが、クラスのインスタンスであれば書き換えることができます。よって、私が提示したコードはクラスのプロパティとして、つまりクラスでstringをラップしてバインドしているのです。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/



    2011年9月4日 1:34
    モデレータ

すべての返信

  • おそらく、List<string>から返されるstringでバインドしているためでしょう。stringは値型であるため、Listが持っているstringのコピーが渡されるため、それを変更したところで元のListのstring型の値を変更することはできません。よって、以下のようにクラスでラップすれば良いでしょう。
    public partial class MainWindow : Window
    {
        //public static List<string> slTmp = new List<string>();
        public static List<MyNumber> slTmp = new List<MyNumber>();
     
        public MainWindow()
        {
            InitializeComponent();
    
            //slTmp.Add("1");
            //slTmp.Add("2");
            //slTmp.Add("3");
    
            //DataContext = slTmp;
    
            DataContext = slTmp = Enumerable.Range(1, 3).Select(i => new MyNumber { Number=i}).ToList(); 
     
        }
    }
    
    public class MyNumber
    {
        public int Number { get; set; }
    }
    
     
    <ListBox Height="287" HorizontalAlignment="Left" Margin="12,12,0,0" Name="listBox1"
                          VerticalAlignment="Top" Width="145" ItemsSource="{Binding }">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <TextBox Text="{Binding Path=Number,Mode=TwoWay,UpdateSourceTrigger=LostFocus}" />
             </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    

    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年9月3日 14:21
    モデレータ
  • おそらく、List<string>から返されるstringでバインドしているためでしょう。stringは値型であるため、Listが持っているstringのコピーが渡されるため、それを変更したところで元のListのstring型の値を変更することはできません。

    バインディングしてるオブジェクト自体を書き換えることができないのは値型参照型関係ありませんし、そもそも String は参照型です。

    例えばリストの個々の String をテキストボックスにバインディングしたとして、テキストボックスからはその文字列が元のリストの何処に配置されているのか判らないので、勝手に新しい文字列インスタンスを作って自分のバインディング対象を置き換えても、リストの参照先を書き換えることができません(あるいはそのリストは読み取り専用かもしれない)。禁止されているのはそう言う理由でしょう。

    2011年9月3日 16:32
  • すみません。おかしなことを書いていました。m(_ _)m
    バインディングしてるオブジェクト自体を書き換えることができないのは値型参照型関係ありませんし、そもそも String は参照型です。

    リストにおけるオブジェクトを挿げ替えることはできませんが、参照型であればオブジェクトを書き換えることができます。Stringはおっしゃる通りごく普通の参照型です。値型のようにふるまうというのが脳内変換されて誤ったことを書いてしまいました。ご指摘ありがとうございます。

    #(追記)nobuyakiさんへ。stringについて誤ったことを書きました。ごめんなさい。stringについては最近以下に書いていますので、参考になればと思います。

    2つのList 内のオブジェクトをリンクさせる方法を教えてください
    http://social.msdn.microsoft.com/Forums/ja-JP/csharpgeneralja/thread/96df3709-fbef-41dd-94ab-0bed14476030/

     

    例えばリストの個々の String をテキストボックスにバインディングしたとして、テキストボックスからはその文字列が元のリストの何処に配置されているのか判らないので、勝手に新しい文字列インスタンスを作って自分のバインディング対象を置き換えても、リストの参照先を書き換えることができません(あるいはそのリストは読み取り専用かもしれない)。禁止されているのはそう言う理由でしょう。


    おっしゃる通りですね。
    改めて説明を以下のように修正させていただきます。

    今回の件は、メソッドの引数としてstringを渡した場合とクラスのインスタンスを渡した場合を考えればよくわかると思います。メソッドに渡されたstringを書き換えても渡す前の、つまりメソッド外のstringオブジェクトを書き換えることはできませんが、クラスのインスタンスであれば書き換えることができます。よって、私が提示したコードはクラスのプロパティとして、つまりクラスでstringをラップしてバインドしているのです。

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/



    2011年9月4日 1:34
    モデレータ
  • 皆さん、返事してくれてありがと、trapemiyaさんの言うとおりに、stringをクラスのプロパティにしたら、更新ができました

    2011年9月4日 4:06