2011-04-03 34 views
0

我有一個簡單的應用程序,它從DataBase中讀取專輯列表並填充ListBox(AlbumShowCase)。 每當一個ListBoxItem被選中,我更新一個DataGrid(trackDataGrid)與該專輯中的軌道列表(也來自DataBase)。在WPF中編輯DataGrid會導致System.NullReferenceException異常

問題是,我可以編輯DataGrid中的項目,並且對於所有現有的軌道,更改是持久的。但是,如果我嘗試添加一個新的軌道,一旦我完成編輯行,我得到System.NullReferenceException。

private TunesDBDataContext db; 

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    db = new TunesDBDataContext("TunesDB.sdf"); 
    var query = from a in db.Albums select new AlbumCase(a); 
    AlbumShowCase.ItemsSource = query; 
} 

private void trackDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    db.SubmitChanges(); 
} 

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    var query = from a in db.Albums 
       where a.AlbumID == ((AlbumCase)e.AddedItems[0]).Album.AlbumID 
       select a.Tracks; 

    trackDataGrid.ItemsSource = query; 
} 

例外我ValueConverter後立即發生:

[ValueConversion(typeof(String), typeof(int))] 
public class TimeConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     int time = (int)value; 
     TimeSpan ts = TimeSpan.FromSeconds(time); 
     return ts.ToString(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     // The validation runs before this, so we know that if we got here 
     // the data must be valid and won't throw an exception. 
     return (int)TimeSpan.Parse((string)value).TotalSeconds; 
     // THE EXCEPTION OCCURS AFTER THIS LINE FOR NEW ROWS 
    } 

的TimeConverter與TimeConverterRule是確保進入軌道長度是有效的配對,併爲所有我知道它的正常工作。 就在用戶編輯發生崩潰的DataGrid的最後一行(空白行)時。而這裏的堆棧跟蹤:

System.NullReferenceException was unhandled 
Message=Object reference not set to an instance of an object. 
Source=PresentationFramework 
StackTrace: 
    at System.Windows.Data.BindingExpression.IsValidValueForUpdate(Object value, Type sourceType) 
    at System.Windows.Data.BindingExpression.ConvertProposedValue(Object value) 
    at System.Windows.Data.BindingExpression.ValidateAndConvertProposedValue(Collection1& values) 
    at System.Windows.Controls.DataGridHelper.ValidateWithoutUpdate(FrameworkElement element) 
    at System.Windows.Controls.DataGridColumn.CommitCellEdit(FrameworkElement editingElement) 
    at System.Windows.Controls.DataGridColumn.CommitEdit(FrameworkElement editingElement) 
    at System.Windows.Controls.DataGridCell.CommitEdit() 
    at System.Windows.Controls.DataGrid.OnExecutedCommitEdit(ExecutedRoutedEventArgs e) 
    at System.Windows.Controls.DataGrid.OnExecutedCommitEdit(Object sender, ExecutedRoutedEventArgs e) 
    at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e) 
    at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding) 
    at System.Windows.Input.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute) 
    at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute) 
    at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e) 
    at System.Windows.UIElement.OnExecutedThunk(Object sender, ExecutedRoutedEventArgs e) 
    at System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target) 
    at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target) 
    at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs) 
    at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised) 
    at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args) 
    at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted) 
    at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated) 
    at System.Windows.Input.RoutedCommand.Execute(Object parameter, IInputElement target) 
    at System.Windows.Controls.DataGrid.EndEdit(RoutedCommand command, DataGridCell cellContainer, DataGridEditingUnit editingUnit, Boolean exitEditMode) 
    at System.Windows.Controls.DataGrid.CommitAnyEdit() 
    at System.Windows.Controls.DataGrid.OnEnterKeyDown(KeyEventArgs e) 
    at System.Windows.Controls.DataGrid.OnKeyDown(KeyEventArgs e) 
    etc...etc... 
    } 
+0

我想看看XAML聲明 – ebattulga 2011-04-03 10:06:00

回答

1

我懷疑的是,這是因爲你被綁定到LINQ的結果SQL查詢。當您編輯該行時,WPF會嘗試將新項目「添加」到您的查詢中 - 但它不支持添加。

嘗試是這樣的:

var query = from a in db.Albums 
      where a.AlbumID == ((AlbumCase)e.AddedItems[0]).Album.AlbumID 
      select a.Tracks; 

var dataSource = new ObservableCollection<Track>(); 
foreach (var item in query) 
    dataSource.Add(item); 

trackDataGrid.ItemsSource = dataSource; 

則可能需要訂閱對電網事件,以便當添加一個項目,你將它添加到的DbContext。

此外,確保AlbumCase是一個公共類,具有公共的,無參數的構造函數。這是因爲WPF會嘗試「新」一個來設置屬性。

+0

這看起來像是一個正確的方向,使用我想出的代碼: \t \t \t var dataSource = new ObservableCollection (); \t \t \t的foreach(在查詢VAR實體) \t \t \t \t的foreach(在實體軌道T) \t \t \t \t { \t \t \t \t \t dataSource.Add(T); \t \t \t \t} \t \t \t trackDataGrid.ItemsSource =數據源;' 而沒有更多的崩潰! 我將不得不使現在的更改持久化,但使用ObservableCollection這很容易:)再次感謝! – 2011-04-03 10:22:15

0
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
//check value null 
if(value==null) return 0; 
     return (int)TimeSpan.Parse((string)value).TotalSeconds; 

    } 
+0

可惜的是並沒有這樣的伎倆。該值實際上是有效的(目前在調試器中我可以閱讀「00:04:25」)。 – 2011-04-03 09:11:08

1

與.net反射戳,這是你正在運行到(在System.Windows.Data.BindingExpression)代碼:

internal override object ConvertProposedValue(object value) 
{ 
    ... 
    Type sourcePropertyType = this.Worker.SourcePropertyType; 
    IValueConverter dynamicConverter = null; 
    CultureInfo culture = base.GetCulture(); 
    if (this.Converter != null) 
    { 
     if (!base.UseDefaultValueConverter) 
     { 
      value = this.Converter.ConvertBack(value, sourcePropertyType, this.ParentBinding.ConverterParameter, culture); 
      if (((value != Binding.DoNothing) && (value != DependencyProperty.UnsetValue)) && !this.IsValidValueForUpdate(value, sourcePropertyType)) 
      { 
       dynamicConverter = this.DynamicConverter; 
      } 
     } 

從我可以理解「SourcePropertyType」是一個空值(然後它會拋出呼叫IsValidValueForUpdate)。

所以,這顯然是一個PresentationFramework中的錯誤(它可以報告一個很好的錯誤並且優雅地失敗),但是它發生的原因是,您傳遞給WPF一個爲null的源屬性類型。也許是因爲通用的開放類型或anonymouse類型。

希望這會有所幫助。

爲了幫助你診斷,我建議你把WPF追溯一個,見SO關於這個問題的主題:How to detect broken WPF Data binding?

+0

感謝您的幫助,我查找了我的DataBinding,並找不到任何錯誤:(:(從您給我的鏈接我設置我的app.config創建GraveOfBindErrors.txt並且只有Microsoft的功能區似乎有問題,沒有任何從我的代碼) – 2011-04-03 10:20:45

+0

但他的查詢的結果似乎並不是一個匿名類型(沒有'新{...}'),你不能有一個開放的泛型類型的對象。 – svick 2011-04-03 11:36:01

+0

@svick - 是的,這是可能是不同的東西WPF堆棧得到一個空類型,並保持它,而不是拋出和錯誤,也許動態程序集? – 2011-04-03 14:09:05