問題描述
WPF說數據項不為空時為空 (WPF says that data item is null when it is not null)
I have a ViewModel class that I use with WPF and MVVM:
public class ViewModel {
/* Other members here... */
public ReadOnlyObservableCollection<BackplaneViewModel> Backplanes {
get { return _Backplanes; }
}
public BackplaneViewModel CurrentBackplane {
get {
var cb = _CurrentBackplane ?? (_CurrentBackplane = Backplanes.First());
return cb;
}
set {
if (_CurrentBackplane == value) return;
_CurrentBackplane = value;
RaisePropertyChanged("CurrentBackplane");
}
}
}
The _Backplanes
collection is created and populated in the constructor and never changes.
I have a control that uses an instance of this ViewModel
as its DataContext
. The user can choose the CurrentBackplane
with a ComboBox
:
<ComboBox ItemsSource="{Binding Backplanes}"
SelectedItem="{Binding CurrentBackplane}"
DisplayMemberPath="BackplaneIndex" />
The CurrentBackplane
may also be changed in code.
I put a break point on the get
of CurrentBackplane
. The cb
variable is not null. But, immediately after WPF
requests its value, I get the following in the Output window:
System.Windows.Data Information: 40 : BindingExpression path error: 'BackplaneIndex' property not found for 'object' because data item is null. This could happen because the data provider has not produced any data yet. BindingExpression:Path=BackplaneIndex; DataItem=null; target element is 'ComboBox' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 19 : BindingExpression cannot retrieve value due to missing information. BindingExpression:Path=BackplaneIndex; DataItem=null; target element is 'ComboBox' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 20 : BindingExpression cannot retrieve value from null data item. This could happen when binding is detached or when binding to a Nullable type that has no value. BindingExpression:Path=BackplaneIndex; DataItem=null; target element is 'ComboBox' (Name=''); target property is 'NoTarget' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=BackplaneIndex; DataItem=null; target element is 'ComboBox' (Name=''); target property is 'NoTarget' (type 'Object')
Why is WPF
telling me the data item is null?
I'm not sure what I'm doing wrong. The program actually runs fine, but I'm trying to track down a memory leak that I think may be related to this issue.
參考解法
方法 1:
Have you tried setting _CurrentBackplane after you set the collection's value in the constructor to immediately be the first value and change the getter code to just return _CurrentBackplane?
_CurrentBackplane = Backplanes.First();
and
public BackplaneViewModel CurrentBackplane {
get {
return _CurrentBackplane;
}
set { _CurrentBackplane = value; }
}
方法 2:
in addition to Joshs answer you should raise propertychanged in your setter
set { _CurrentBackplane = value; OnPropertyChanged("CurrentBackplane "); }
and you should set the Mode to TwoWay for your SelectedItem
SelectedItem="{Binding CurrentBackplane, Mode=TwoWay}"
and btw you just get a binding information not a binding error
方法 3:
Can you check if the DataContext has actually been set to your ViewModel instance before the logging is written to the output window? You can do this by hooking up an event handler to the DataContextChanged event.
I am seeing a similar problem with my code, unfortunately I haven't worked out how to prevent it but I shall keep you posted if I do.
方法 4:
I 'm not sure if this is the answer, but give it a try. In your application set:
System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Critical;
This might solve the problem.
方法 5:
To me the solution was to recheck it after DataContext
property has been reset, then resetting the binding:
<pre class="lang-cs prettyprint-override">var resolvedSource = bindingExpression.ResolvedSource;
if (resolvedSource == null)
{
textBox.DataContextChanged += dataContextChanged;
static void dataContextChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var frameworkElement = (FrameworkElement)sender;
var be = frameworkElement.GetBindingExpression(TextBox.TextProperty);
var newBe = BindingOperations.SetBinding(
(DependencyObject)sender, TextBox.TextProperty, be.ParentBinding);
Debug.Assert(newBe is BindingExpression);
Debug.Assert(newBe.DataItem != null);
//here newBe.DataItem should not be null
addValidationRules((BindingExpression)newBe);
frameworkElement.DataContextChanged -= dataContextChanged;
}
return;
}
addValidationRules(bindingExpression);
</code></pre>
(by ken、Josh、blindmeis、Bijington、user3083911、Shimmy Weitzhandler)
參考文件