我有一个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!!
}
}
}
答案 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似乎想要默默地失败并让你感到疑惑。