WPF:NodeChanged事件未触发

时间:2010-11-02 21:56:53

标签: .net wpf c#-4.0

我有一个WPF应用程序,它使用XmlDataProvider将DataGrid绑定到XML文档。一切正常,除了我试图在NodeChanged事件上“保存”/写入XML文件,而不是使用按钮或其他用户触发的机制。不幸的是,我创建的NodeChanged处理程序没有被选中。非常感谢任何帮助,以弄清楚它为什么不被解雇。

XAML:

  <Grid Name="Grid" Loaded="Grid_Loaded">
    <Grid.DataContext>
      <XmlDataProvider x:Name="MyData" Source="Data.xml" XPath="Nodes/Node" />
    </Grid.DataContext>
    <DataGrid AutoGenerateColumns="False" Name="dataGrid1" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" SelectionUnit="FullRow" SelectionMode="Single" Margin="0,0,0,50">
      <DataGrid.Columns>
        <DataGridTextColumn Header="Header" Binding="{Binding XPath=@Value, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
      </DataGrid.Columns>
    </DataGrid>
    <Button Content="Save" Height="23" HorizontalAlignment="Left" Margin="416,276,0,0" Name="SaveButton" VerticalAlignment="Top" Width="75" Click="SaveButton_Click" />
  </Grid>

代码隐藏:


namespace WpfApplication1
{
  public partial class MainWindow : Window
  {
    public MainWindow()
    {
      InitializeComponent();

      string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
      MyData.Source = new Uri(appPath + "/Data.xml");
    }

    private void SaveButton_Click(object sender, RoutedEventArgs e)
    {
      string source = MyData.Source.LocalPath;
      MyData.Document.Save(source); 
    }

    private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
      MyData.Document.NodeChanged += new XmlNodeChangedEventHandler(Document_NodeChanged);
    }

    void Document_NodeChanged(object sender, XmlNodeChangedEventArgs e)
    {
      MessageBox.Show("Node changed");
    }
  }
}

XML数据文件:

<Nodes>
  <Node Value="test1" />
  <Node Value="test3" />
  <Node Value="ttt" />
</Nodes>

要重现,您只需将上述内容粘贴到新的WPF应用程序中,将XML数据文件命名为Data.xml,将其放入项目的bin / Debug中,然后将其作为“现有项目”添加到项目中。

更新

感谢罗伯特指出这个问题!

这是一个更有趣的情况。如果你只是将一个LayoutUpdated事件处理程序添加到我的示例代码中的MainWindow,你会得到非常奇怪的行为,如果显示一个完全不相关的MessageBox,实际上将触发NodeChanged事件:

public partial class MainWindow : Window
{
    private bool event_activated = false;

    public MainWindow()
    {
        InitializeComponent();
        string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
        MyData.Source = new Uri(appPath + "/Data.xml");
    }

    private void SaveButton_Click(object sender, RoutedEventArgs e)
    {
        string source = MyData.Source.LocalPath;
        MyData.Document.Save(source);  
    }

    private void Grid_Loaded(object sender, RoutedEventArgs e)
    {
        MyData.Document.NodeChanged += new XmlNodeChangedEventHandler(Document_NodeChanged);
    }

    private void Document_NodeChanged(object sender, XmlNodeChangedEventArgs e)
    {
        MessageBox.Show("Node changed");
    }

    private void Window_LayoutUpdated(object sender, EventArgs e)
    {       
        if (!event_activated)
        {
            event_activated = true;
            MessageBox.Show("LayoutUpdated"); // <-- NodeChanged is fired with this one line of code, and not fired if you comment this line out!!
        }
    }
}

1 个答案:

答案 0 :(得分:0)

它不会触发,因为节点的值不会改变,只会碰巧命名为Value的属性。它在documentation

中说明
  

在更改属于此文档的节点的值时发生。   ...   此事件仅适用于具有值的节点。

如何使用DataGrid.CellEditEnding或DataGrid.RowEditEnding呢?

更新:

你是对的,NodeChanged也会触发属性。我确实在你漂亮的repro应用程序中找到了问题。如果我注释掉你的构造函数代码,那一切都有效。您已经在Xaml中设置了源代码。似乎此代码触发了一个内部处理的异常,该异常将XmlDataProvider置于损坏状态。

  public MainWindow()
  {
     InitializeComponent();
     //string appPath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
     //MyData.Source = new Uri(appPath + "/Data.xml");
  }

您可以在调试输出中看到异常。 WPF似乎想要默默地失败并让你感到疑惑。