none
バインディング先のソースを更新しても反映されない RRS feed

  • 質問

  • http://social.msdn.microsoft.com/Forums/ja-JP/wpfja/thread/da684e9d-5135-47a2-8e9c-ce4461b0554a

    で、存在しないPathが設定されているときの挙動について質問していましたが、質問時と大分状況が変わってきましたので改めて別のスレッドを立てさせていただきました。

    そのときの回答として、XElementを直接使うのではなく、クラス定義した方がよいとのアドバイスをいただきましたので、そちらの方も試そうとは思っているのですが、なぜこのような現象が発生するのか分からないままでは、根本的に使用方法を誤っている可能性もあるかと思い、検証を続けています。

    ご協力よろしくお願いいたします。

    状況としましては、ComboBoxのItemsSourceでBindingのPathを起動時には存在しないものに設定しています。
    ボタンをClickしたときのイベントで、指定しているPathの要素を作成しています。

    ソース自体は想定通り更新できていると思うのですが、なぜか反映されません。

    色々試してみたところ、別の階層で指定しているDataContextが影響していることがわかりました。

    下記に検証用のコードを記載していますのでご参照ください。

    ListBoxのDataContextを定義しているか否かで状況が変わります。
    定義していない場合は期待する通りに反映されます。

    また、DataContextを定義したままでも、もともとXMLファイルにバインディング先の要素が存在していれば正常に表示されます。

    ---XMLファイル-----------------------------
    <tests>
      <test/>
      <!--<items><item name="aaa"/></items>--> <!--これを復活させると、DataContextを指定していても正常に表示される-->
    </tests>

    ---MainWindow.xaml-------------------------
    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:local="clr-namespace:WpfApplication1"
            xmlns:my="clr-namespace:WpfApplication1"
            Title="MainWindow" Height="350" Width="525">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>
            <Grid Grid.Row="0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid Grid.Column="0">
                    <ListBox DataContext="{Binding Element[test]}"/>    <!--このDataContextのあるなしで状況が変わる-->          
                </Grid>
                <ComboBox Grid.Column="1"             
                        IsEditable="True"
                        IsTextSearchEnabled="True"
                        TextSearch.TextPath="Attribute[name].Value"
                        ItemsSource="{Binding Path=Element[items].Elements[item]}"  >
                    <ComboBox.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Attribute[name].Value}"/>
                        </DataTemplate>
                    </ComboBox.ItemTemplate>
                </ComboBox>
            </Grid>
            <Button x:Name="myButton" Grid.Row="1" Content="Click" Click="myButton_Click"/>
        </Grid>
    </Window>

    ---MainWindow.xaml.cs---------------------------
    namespace WpfApplication1
    {
        /// <summary>
        /// MainWindow.xaml の相互作用ロジック
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();

                XDocument xdoc = XDocument.Load("xmlファイルのパス");
                var test = xdoc.Root;
                this.DataContext = test;
            }
            private void myButton_Click(object sender, RoutedEventArgs e)
            {
                XElement item = new XElement("item");
                item.SetAttributeValue("name", "aaa");
                XElement items = new XElement("items");
                items.Add(item);

                ((XElement)this.DataContext).Add(items);

            }
        }
    }

    この現象に対して何かよいお知恵がありましたら、アドバイスよろしくお願いいたします。

    2011年1月14日 7:06

すべての返信

  • myButton_Click()によって更新されるXMLは

    <tests>
      <test />
      <items>
        <item name="aaa" /> <!-- ListBoxは先頭のここを参照 -->
      </items>
      <items>
        <item name="aaa" />
      </items>
    </tests>

    となり、items要素が毎回追加されていますよ。

    余談ですが、ListBoxもComboBoxと同じようにItemsSource / ItemTempleteプロパティを使いましょう。

    2011年1月15日 0:49
  • 佐祐理様

    ご返信いただきありがとうございます。

    現象を再現させるためだけの適当なサンプルコードでしたので、おかしなことになってしまっていてすみません。

    サンプルコードで期待する結果は

    「1回myButtonをクリックすると、コンボボックスに"aaa"が登録される。」点のみです。

    ご指摘のように複数回クリックすると、どんどんitems要素が追加されることになります。

    また、実際にListBoxを作成する必要性がなかったので、ItemsSourceやItemTemplateなどの指定は省略させていただきました。

     

    さて、tests/items/itemのところに「ListBoxは先頭のここを参照」と記載いただきましたが、Element[test]としているのになぜここが参照されてしまうのでしょうか。

    また、上記のサンプルコードではDataContextを指定する必要性があまりないのですが、実際に作成するコードでは、GridなどにDataContextを設定して下層のコントロールでそれが継承されるようにしたいと考えているのです。

    そもそも、DataContextの指定は、その子孫の要素にしか影響しないものと理解していたのですが、それが間違った認識なのでしょうか。

    上記サンプルコードの場合、ListBoxとComboboxは親子関係がないため、いくらListBoxでDataContextを指定しようが、なんの影響もないはずと思っていたのですが。

    引き続きアドバイスいただけましたら幸いです。

    よろしくお願いいたします。

    2011年1月17日 8:41