错误消息:
HResult= 0x 80004003消息=对象引用未设置为对象示例。源=System.Windows.Forms堆栈跟踪:在系统.Windows.窗体.绑定.SetPropValue(对象值)在系统.Windows.窗体.绑定.PushData(布尔值强制)在系统.Windows.窗体.绑定管理器库.PushData(布尔值成功)(& S)
在系统.组件模型.属性描述符. OnValueChanged(对象组件,事件参数e)在系统.组件模型.反射属性描述符.OnValueChanged(对象组件,事件参数e)
第132行:在项目XYZ.MVVM.视图模型. RecipeViewModel.通知属性已更改(字符串属性名称)
此异常最初在此调用堆栈中引发:[外部代码]项目XYZ.MVVM.视图模型. RecipeViewModel. cs中的通知属性已更改(字符串)
编辑:第132行:PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
目的:
在WinForm中显示一个配方编辑器,您可以在其中选择一个类别,然后选择要更改的配方,并使用一些嵌套属性对象(烘箱温度和时间斜坡等)层/步骤更改配方。
用途:
1.在显示的ComboBox 1中选择类别
1.在显示的组合框中选择配方2
所选的配方应显示在一些文本框、组合框中,一些特定步骤显示在数据网格视图中。此外,如果您在组合框2中选择另一个配方,它应可以更改且不会丢失其信息。
问题:参见上述异常。
下面是代码的一部分(我希望我没有忘记C&P和翻译中的一些内容):
我有一个CollectionViewSource RecipesOnWork,我用CategoryFilter过滤它,效果很好。我把这个过滤后的视图给了一个组合框RecipesOnWork.Cast<RecipeViewModel>().ToList()
,在那里我可以按名称选择一个食谱。我找不到更好的方法...(如果有一个,我想读一下,😉但不是针对这个问题)
我还在事件CollectionViewSource.CurrentChanged上挂接了我自己:RecipesOnWork.View.CurrentChanged += CurrentRecipeChanged;
使用从ComboBox2.SelectedIndexChanged事件中选择的配方,我检查配方是否在RecipesOnWork中,在RecipesOnWork中查找配方,在CurrentItem上设置以下内容:
if(sender is ComboBox combobox)
{
combobox.SelectedItem is RecipeViewModel Recipe
if (RecipesOnWork.View.Contains(Recipe))
{ RecipesOnWork.View.MoveCurrentTo(Recipe); }
}
由于CurrentRecipeChanged,我设置了我的私有CurrentSelectedRecipe,因为我的
private RecipeViewModel curentSelectedRecipe = new RecipeViewModel();
public RecipeViewModel CurentSelectedRecipe
{
get { return CurentSelectedRecipe; }
set
{
// Edit:
if (curentSelectedRecipe == value || value == null)
{ return; }
//Even if I deactivate this part of unsubcribe I get the exception.
if (curentSelectedRecipe != null)
{ curentSelectedRecipe.PropertyChanged -= InformRecipeChanged; }
curentSelectedRecipe = value;
//Even if I deactivate this part of subcribe I get the exception.
curentSelectedRecipe.PropertyChanged += InformRecipeChanged;
}
}
并将更改通知给所有可能的视图。(Views是视图的列表)
Views.ForEach(view => view.OnNext(Recipe));}
public override void OnNext(RecipeViewModel value)
{
ViewModel = value;
// Work fine in the test:
ClearSubscribe(FRM.TBNestedOBJ1Time, "Text", ViewModel.nestedOBJ1, nameof(NestedClassViewModel1.Time), true, OnPropertyChanged);
// If I'm changing the text here I get a System.NullReferenceException:
ClearSubscribe(FRM.TBRecipeName, "Text", ViewModel, nameof(RecipeViewModel.Name), true, OnPropertyChanged);
}
private void ClearSubscribe(Control control, string binderPropertie, object obj, string objPropertie, bool formatEnabling, DataSourceUpdateMode updateMode)
{
control.DataBindings.Clear();
control.DataBindings.Add(binderPropertie, obj, objPropertie, formatEnabling, updateMode);
}
嵌套OBJ 1也具有INotify属性更改
public class RecipeViewModel : INotifyPropertyChanged
{
//Example for one nested class NestedOBJ1:
private NestedClassViewModel1 nestedOBJ1 = new NestedClassViewModel1();
public NestedClassViewModel1 NestedOBJ1
{
get => nestedOBJ1;
set
{
if (nestedOBJ1 == value)
{ return; }
nestedOBJ1 = value;
NotifyPropertyChanged();
}
}
private string name = "Undefined";
public string Name
{
get => name;
set
{
if (name == value)
{ return; }
name = value;
NotifyPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
**我必须使用.Net Framework 4.8和WinForm。**我正尝试通过一点调整来实现MVVM模式,所以我决定使用MVC和MVVM的混合模式...=〉我有控制器、视图模型、视图和模型,其中包含一些业务逻辑,我在这些逻辑之间给予对象。因此,也许我还丢失了PropertyChanged?
如果我一步一步地改变Recipe.Name,我可以看到,该Recipe.Name已经有了新的值,此时它也不是空的。
- 只有EventHandler PropertyChanged可以为空?我不明白为什么在检查它是否为空时会出现NullReferenceException?(
PropertyChanged?.Invoke()
) - 这是因为在第一次检查中它不是null,并且因为我的ClearSubscribe()我得到了null异常吗?
- 如果我想进行双向交流,我如何才能避免这种情况?
- 为什么它在嵌套对象上没有崩溃?
我肯定我错过了什么,我不明白。也许有人可以帮助我?
我试图解决这个问题,因为5或6天,所以我不知道如何才能做到这一点,也许做得更好了。
谢谢你的帮助。
到目前为止,我尝试的还有:若要手动将它系结至OnNext方法中的文字方块,请透过
FRM.CategoryName.TextChanged -= ManualBound;
FRM.CategoryName.Text = ViewModel.Rubrik;
FRM.CategoryName.TextChanged += ManualBound;
若为手动绑定:
private void ManualBound(object sender, EventArgs e)
{
if (sender is TextBox box)
{
ViewModel.Category = box.Text;
}
}
这是可行的,但我必须做很多工作,这就是为什么我使用ClearSubscribe(Control control, string binderPropertie, object obj, string objPropertie, bool formatEnabling, DataSourceUpdateMode updateMode)
,这对我来说是一个“更聪明”的方式后,一些研究绑定一些属性的TextBox
。
要查找问题:
关于public RecipeViewModel CurentSelectedRecipe
中@Selvin编辑的建议
set
{
if (curentSelectedRecipe == value || value == null)
{ return; }
//Even if I deactivate this part of unsubcribe I get the exception.
if (curentSelectedRecipe != null)
{ curentSelectedRecipe.PropertyChanged -= InformRecipeChanged; }
curentSelectedRecipe = value;
//Even if I deactivate this part of subcribe I get the exception.
curentSelectedRecipe.PropertyChanged += InformRecipeChanged;
}
if (curentSelectedRecipe == value )
{ return; }
我添加了这个,但仍然得到了这个System.NullReferenceException
在NotifyPropertyChanged方法中://没有帮助:如果(属性更改== null){ return;}
if (PropertyChanged!= null)
{
foreach (PropertyChangedEventHandler subscriber in PropertyChanged?.GetInvocationList())
{
if (subscriber != null)
{
Debug.WriteLine(subscriber.Target.ToString());
/*
Output:
System.ComponentModel.ReflectPropertyDescriptor
System.ComponentModel.ReflectPropertyDescriptor
System.ComponentModel.ReflectPropertyDescriptor
*/
}
}
}
var myEvent = new PropertyChangedEventArgs(propertyName); // was not null
var this2 = this;// was not null
// still throw Exception.
PropertyChanged?.Invoke(this2, myEvent);
1条答案
按热度按时间jqjz2hbq1#
在@Selvin的评论之后,我的思想走上了正确的思考道路,所以我想我发现了自己的错误:
|| ViewModel ==值是重要的部分。
因为所有的东西都连接好了,所以不需要重新连接任何东西--〉所以不要在那里中断。
我的错误是我问:
我不知道要避免这种情况,所以我尝试了上面的代码,它成功了。所以问题是改变了
PropertyChanged
,而它在自己的调用中改变了它,在那里它变成了null,这就是我通过NullCheck的原因。((this, new PropertyChangedEventArgs(propertyName));
)