WPF: событие NodeChanged не запускается - PullRequest
0 голосов
/ 03 ноября 2010

У меня есть приложение WPF, которое связывает DataGrid с документом XML с помощью XmlDataProvider. Все работает отлично, за исключением того, что я пытаюсь «сохранить» / записать в файл XML по событию NodeChanged вместо кнопки или другого механизма, запускаемого пользователем. К сожалению, обработчик 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 XML.xml, поместить его в bin / Debug проекта и добавить в проект как «существующий элемент».

UPDATE

Спасибо, Роберт, за указание на проблему!

Вот еще более интересная ситуация. Если вы просто добавите обработчик события LayoutUpdated в MainWindow в мой пример кода, как показано ниже, вы получите очень странное поведение в том, что событие NodeChanged действительно будет запущено, если отобразится совершенно не связанный MessageBox:

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 голосов
/ 03 ноября 2010

Не срабатывает, потому что значение узла не меняется, только атрибут с именем Value. Это указано в документации :

Происходит, когда значение узла, принадлежащего этому документу, было изменено. ... Это событие применяется только к узлам, которые имеют значение.

Как насчет использования DataGrid.CellEditEnding или DataGrid.RowEditEnding вместо этого?

Обновление:

Вы правы, NodeChanged будет срабатывать и для атрибутов. Я нашел проблему в вашем хорошем приложении для воспроизведения. Если я закомментирую ваш код конструктора, все будет работать. Вы уже установили источник в Xaml. Кажется, что этот код запускает исключение с внутренней обработкой, которое переводит XmlDataProvider в поврежденное состояние.

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

Вы можете увидеть исключение в выходных данных отладки. WPF, похоже, любит молчаливо проваливаться и заставляет задуматься.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...