- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
感觉必须有一些半简单的解决方案,但我就是想不通。
编辑:前面的示例更清楚地显示了无限循环,但这提供了更多上下文。查看预编辑以快速了解问题。
以下 2 个类表示模型 View View 模型 (MVVM) 模式的 View 模型。
/// <summary>
/// A UI-friendly wrapper for a Recipe
/// </summary>
public class RecipeViewModel : ViewModelBase
{
/// <summary>
/// Gets the wrapped Recipe
/// </summary>
public Recipe RecipeModel { get; private set; }
private ObservableCollection<CategoryViewModel> categories = new ObservableCollection<CategoryViewModel>();
/// <summary>
/// Creates a new UI-friendly wrapper for a Recipe
/// </summary>
/// <param name="recipe">The Recipe to be wrapped</param>
public RecipeViewModel(Recipe recipe)
{
this.RecipeModel = recipe;
((INotifyCollectionChanged)RecipeModel.Categories).CollectionChanged += BaseRecipeCategoriesCollectionChanged;
foreach (var cat in RecipeModel.Categories)
{
var catVM = new CategoryViewModel(cat); //Causes infinite loop
categories.AddIfNewAndNotNull(catVM);
}
}
void BaseRecipeCategoriesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
categories.Add(new CategoryViewModel(e.NewItems[0] as Category));
break;
case NotifyCollectionChangedAction.Remove:
categories.Remove(new CategoryViewModel(e.OldItems[0] as Category));
break;
default:
throw new NotImplementedException();
}
}
//Some Properties and other non-related things
public ReadOnlyObservableCollection<CategoryViewModel> Categories
{
get { return new ReadOnlyObservableCollection<CategoryViewModel>(categories); }
}
public void AddCategory(CategoryViewModel category)
{
RecipeModel.AddCategory(category.CategoryModel);
}
public void RemoveCategory(CategoryViewModel category)
{
RecipeModel.RemoveCategory(category.CategoryModel);
}
public override bool Equals(object obj)
{
var comparedRecipe = obj as RecipeViewModel;
if (comparedRecipe == null)
{ return false; }
return RecipeModel == comparedRecipe.RecipeModel;
}
public override int GetHashCode()
{
return RecipeModel.GetHashCode();
}
}
.
/// <summary>
/// A UI-friendly wrapper for a Category
/// </summary>
public class CategoryViewModel : ViewModelBase
{
/// <summary>
/// Gets the wrapped Category
/// </summary>
public Category CategoryModel { get; private set; }
private CategoryViewModel parent;
private ObservableCollection<RecipeViewModel> recipes = new ObservableCollection<RecipeViewModel>();
/// <summary>
/// Creates a new UI-friendly wrapper for a Category
/// </summary>
/// <param name="category"></param>
public CategoryViewModel(Category category)
{
this.CategoryModel = category;
(category.DirectRecipes as INotifyCollectionChanged).CollectionChanged += baseCategoryDirectRecipesCollectionChanged;
foreach (var item in category.DirectRecipes)
{
var recipeVM = new RecipeViewModel(item); //Causes infinite loop
recipes.AddIfNewAndNotNull(recipeVM);
}
}
/// <summary>
/// Adds a recipe to this category
/// </summary>
/// <param name="recipe"></param>
public void AddRecipe(RecipeViewModel recipe)
{
CategoryModel.AddRecipe(recipe.RecipeModel);
}
/// <summary>
/// Removes a recipe from this category
/// </summary>
/// <param name="recipe"></param>
public void RemoveRecipe(RecipeViewModel recipe)
{
CategoryModel.RemoveRecipe(recipe.RecipeModel);
}
/// <summary>
/// A read-only collection of this category's recipes
/// </summary>
public ReadOnlyObservableCollection<RecipeViewModel> Recipes
{
get { return new ReadOnlyObservableCollection<RecipeViewModel>(recipes); }
}
private void baseCategoryDirectRecipesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
var recipeVM = new RecipeViewModel((Recipe)e.NewItems[0], this);
recipes.AddIfNewAndNotNull(recipeVM);
break;
case NotifyCollectionChangedAction.Remove:
recipes.Remove(new RecipeViewModel((Recipe)e.OldItems[0]));
break;
default:
throw new NotImplementedException();
}
}
/// <summary>
/// Compares whether this object wraps the same Category as the parameter
/// </summary>
/// <param name="obj">The object to compare equality with</param>
/// <returns>True if they wrap the same Category</returns>
public override bool Equals(object obj)
{
var comparedCat = obj as CategoryViewModel;
if(comparedCat == null)
{return false;}
return CategoryModel == comparedCat.CategoryModel;
}
/// <summary>
/// Gets the hashcode of the wrapped Categry
/// </summary>
/// <returns>The hashcode</returns>
public override int GetHashCode()
{
return CategoryModel.GetHashCode();
}
}
除非有要求,否则我不会费心展示模型(配方和类别),但它们基本上负责业务逻辑(例如,将配方添加到类别也会添加链接的另一端,即如果类别包含一个食谱,然后该食谱也包含在该类别中)并且基本上决定了事情的进展。 ViewModels 为 WPF 数据绑定(bind)提供了一个很好的接口(interface)。这就是包装类的原因
由于无限循环在构造函数中并且它正在尝试创建新对象,我不能只设置一个 bool 标志来防止这种情况发生,因为两个对象都没有完成构造。
我在想的是(作为单例或传递给构造函数或两者)一个 Dictionary<Recipe, RecipeViewModel>
和 Dictionary<Category, CategoryViewModel>
这将延迟加载 View 模型,但如果已经存在则不会创建新 View 模型,但我还没有抽出时间尝试看看它是否会起作用,因为它已经很晚了,我有点厌倦了处理这个过去 6 个小时左右。
不能保证这里的代码会编译,因为我去掉了一堆与手头问题无关的东西。
最佳答案
回到您最初的问题(和代码)。如果您想要的是自动同步的多对多关系,请继续阅读。寻找处理这些情况的复杂代码的最佳位置是任何 ORM 框架的源代码,这对于这个工具领域来说是非常常见的问题。我会查看 nHibernate (https://nhibernate.svn.sourceforge.net/svnroot/nhibernate/trunk/nhibernate/) 的源代码,了解它如何实现处理 1-N 和 M-N 关系的集合。
您可以尝试的简单方法是创建您自己的小集合类来处理它。下面我删除了您原来的包装类并添加了一个 BiList 集合,该集合使用对象(集合的所有者)和属性另一端的名称进行初始化以保持同步(仅适用于 M-N,但 1- N 很容易添加)。当然,你会想要润色代码:
using System.Collections.Generic;
public interface IBiList
{
// Need this interface only to have a 'generic' way to set the other side
void Add(object value, bool addOtherSide);
}
public class BiList<T> : List<T>, IBiList
{
private object owner;
private string otherSideFieldName;
public BiList(object owner, string otherSideFieldName) {
this.owner = owner;
this.otherSideFieldName = otherSideFieldName;
}
public new void Add(T value) {
// add and set the other side as well
this.Add(value, true);
}
void IBiList.Add(object value, bool addOtherSide) {
this.Add((T)value, addOtherSide);
}
public void Add(T value, bool addOtherSide) {
// note: may check if already in the list/collection
if (this.Contains(value))
return;
// actuall add the object to the list/collection
base.Add(value);
// set the other side
if (addOtherSide && value != null) {
System.Reflection.FieldInfo x = value.GetType().GetField(this.otherSideFieldName);
IBiList otherSide = (IBiList) x.GetValue(value);
// do not set the other side
otherSide.Add(this.owner, false);
}
}
}
class Foo
{
public BiList<Bar> MyBars;
public Foo() {
MyBars = new BiList<Bar>(this, "MyFoos");
}
}
class Bar
{
public BiList<Foo> MyFoos;
public Bar() {
MyFoos = new BiList<Foo>(this, "MyBars");
}
}
public class App
{
public static void Main()
{
System.Console.WriteLine("setting...");
Foo testFoo = new Foo();
Bar testBar = new Bar();
Bar testBar2 = new Bar();
testFoo.MyBars.Add(testBar);
testFoo.MyBars.Add(testBar2);
//testBar.MyFoos.Add(testFoo); // do not set this side, we expect it to be set automatically, but doing so will do no harm
System.Console.WriteLine("getting foos from Bar...");
foreach (object x in testBar.MyFoos)
{
System.Console.WriteLine(" foo:" + x);
}
System.Console.WriteLine("getting baars from Foo...");
foreach (object x in testFoo.MyBars)
{
System.Console.WriteLine(" bar:" + x);
}
}
}
关于mvvm - 我怎样才能避免这个无限循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/904999/
我是 PHP 新手。我一直在脚本中使用 for 循环、while 循环、foreach 循环。我想知道 哪个性能更好? 选择循环的标准是什么? 当我们在另一个循环中循环时应该使用哪个? 我一直想知道要
我在高中的编程课上,我的作业是制作一个基本的小计和顶级计算器,但我在一家餐馆工作,所以制作一个只能让你在一种食物中读到。因此,我尝试让它能够接收多种食品并将它们添加到一个价格变量中。抱歉,如果某些代码
这是我正在学习的一本教科书。 var ingredients = ["eggs", "milk", "flour", "sugar", "baking soda", "baking powder",
我正在从字符串中提取数字并将其传递给函数。我想给它加 1,然后返回字符串,同时保留前导零。我可以使用 while 循环来完成此操作,但不能使用 for 循环。 for 循环只是跳过零。 var add
编辑:我已经在程序的输出中进行了编辑。 该程序要求估计给定值 mu。用户给出一个值 mu,同时还提供了四个不等于 1 的不同数字(称为 w、x、y、z)。然后,程序尝试使用 de Jaeger 公式找
我正在编写一个算法,该算法对一个整数数组从末尾到开头执行一个大循环,其中包含一个 if 条件。第一次条件为假时,循环可以终止。 因此,对于 for 循环,如果条件为假,它会继续迭代并进行简单的变量更改
现在我已经习惯了在内存非常有限的情况下进行编程,但我没有答案的一个问题是:哪个内存效率更高;- for(;;) 或 while() ?还是它们可以平等互换?如果有的话,还要对效率问题发表评论! 最佳答
这个问题已经有答案了: How do I compare strings in Java? (23 个回答) 已关闭 8 年前。 我正在尝试创建一个小程序,我可以在其中读取该程序的单词。如果单词有 6
这个问题在这里已经有了答案: python : list index out of range error while iteratively popping elements (12 个答案) 关
我正在尝试向用户请求 4 到 10 之间的整数。如果他们回答超出该范围,它将进入循环。当用户第一次正确输入数字时,它不会中断并继续执行 else 语句。如果用户在 else 语句中正确输入数字,它将正
我尝试创建一个带有嵌套 foreach 循环的列表。第一个循环是循环一些数字,第二个循环是循环日期。我想给一个日期写一个数字。所以还有另一个功能来检查它。但结果是数字多次写入日期。 Out 是这样的:
我想要做的事情是使用循环创建一个数组,然后在另一个类中调用该数组,这不会做,也可能永远不会做。解决这个问题最好的方法是什么?我已经寻找了所有解决方案,但它们无法编译。感谢您的帮助。 import ja
我尝试创建一个带有嵌套 foreach 循环的列表。第一个循环是循环一些数字,第二个循环是循环日期。我想给一个日期写一个数字。所以还有另一个功能来检查它。但结果是数字多次写入日期。 Out 是这样的:
我正在模拟一家快餐店三个多小时。这三个小时分为 18 个间隔,每个间隔 600 秒。每个间隔都会输出有关这 600 秒内发生的情况的统计信息。 我原来的结构是这样的: int i; for (i=0;
这个问题已经有答案了: IE8 for...in enumerator (3 个回答) How do I check if an object has a specific property in J
哪个对性能更好?这可能与其他编程语言不一致,所以如果它们不同,或者如果你能用你对特定语言的知识回答我的问题,请解释。 我将使用 c++ 作为示例,但我想知道它在 java、c 或任何其他主流语言中的工
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我是 C 编程和编写代码的新手,以确定 M 测试用例的质因数分解。如果我一次只扫描一次,该功能本身就可以工作,但是当我尝试执行 M 次时却惨遭失败。 我不知道为什么 scanf() 循环有问题。 in
这个问题已经有答案了: JavaScript by reference vs. by value [duplicate] (4 个回答) 已关闭 3 年前。 我在使用 TSlint 时遇到问题,并且理
我尝试在下面的代码中添加 foreach 或 for 循环,以便为 Charts.js 创建多个数据集。这将允许我在此折线图上创建多条线。 我有一个 PHP 对象,我可以对其进行编码以稍后填充变量,但
我是一名优秀的程序员,十分优秀!