问题,简而言之:
在MVC中,如何区分复选框点击(或选择框或列表框更改)与人类意义“控制器,修改模型”以及从控制器含义复选框(或选择框或列表框更改) “我正在更新视图,因为模型已更改”?
示例:
我有一个JS应用程序(所有一个大的HTML + JS页面;它背后有一个服务器,AJAX正在进行,但对于这个例子来说并不重要),其中“顶点”的概念由“边缘”连接。用户界面允许您在地图上添加和删除顶点,并启用或禁用顶点对之间的边线。
有两种方法可以禁用从顶点A到顶点B的边缘:
这是如何在MVC()下工作的,但请参阅本文末尾的更新,我在理解中纠正了问题:
这是具体的不雅:
因此,不必要的重新更新模型,并重新更新View。在一个更复杂的视图中,事件会触发触发事件的事件,这可能会导致数十个无关的更新!
<小时/> 更新:一个很好的答案。
我误解了MVC。我没有一个View,如上所述:我有几个模型的几个视图。特别是,我有一个特定节点的复选框列表边缘视图,以及一个单独的“详细窗口式”边缘视图。
此外,我不应该在模型更改时更新所有视图的一个控制器功能:每个视图应在模型更改时修改本身。
因此,如果每个View在Model上注册“状态更新”事件,并且每个View在收到这些事件后自行更新,那么我的循环事件问题的答案就是这样:
复选框列表视图会在模型状态更改后更新复选框时禁用复选框事件。
现在,如果用户通过“边缘详细信息”窗口禁用边缘,则控制器会更新边缘模型,复选框列表视图会收到更新通知,复选框列表视图足够智能,可以在更改时隐藏复选框事件相应复选框的状态。
这比我原来的解决方案更加可口,其中一个Controller更新所有视图 - 因此必须知道哪些视图需要特别小心和喂养以避免循环。相反,只有具有麻烦的UI元素的单个View必须处理该问题。
感谢那些回答我问题的人!
答案 0 :(得分:3)
回顾一下MVC模型。观点通常应该自我更新。以下是它的工作原理:控制器更改模型的状态,模型将更新发送到其视图,视图从模型中获取新状态并自行更新。虽然控制器和视图通常是捆绑在一起的(即以图形表示形式向下钻取数据),但它们不应仅通过模型直接交互。这当然是一般的。
因此更新视图的JS函数实际上不是控制器,这是一个重要的区别。它们应被视为您观点的一部分。这可能对手头的问题没有帮助,但我认为值得指出。
您也不能删除您的模型,我认为您的意思是您正在从模型中删除某些,因为如果没有任何视图或控制器可以存在(或处于功能状态)没有模特支持。
不是JS代码骑师并没有使用gmaps我真的没有看到问题出在哪里。更改复选框(已检查属性)的状态是否会触发onClick()事件?它真的不应该恕我直言,但也许他们这样实现它,否则你可以只是将你的控制器附加到onClick()并添加一些逻辑到复选框(或者,这是JS,在一个函数的某个地方)来改变复选框状态。如果那是不可能的,选项1和2肯定是你最好的选择。
那么当用户想要与视图交互时会发生什么?通常,窗口小部件将包括视图和控制器。复选框有一个视图(您可以查看是否已选中)以及控制器(您可以单击它)。当您单击复选框时,原则上应该发生以下情况:
第一步,控制器如何接收事件在某种程度上依赖于语言,但在OOP语言中,它可能是一个附加到此特定小部件上的用户界面事件的侦听器对象,该小部件是控制器或通知控制器用户交互。
答案 1 :(得分:0)
这是一个艰难的。如果我理解正确,则会导致问题,因为您在模型上公开了单击处理程序,并且控制器捕获了模型的单击事件。控制器更新视图,然后切换相同的事件。
从我的观点来看,我认为控制器将自己附加到Edge的Click事件是不合适的,因为它暴露了有关Edge如何实现和使用的过多细节。 Controller不关心Edge的使用方式或任何其他实现细节。
实际上,规范的MVC样式根本不需要Controller挂接到任何模型事件,通常是因为View的状态不会被View或任何其他控制器变异。模型无需通知控制器它已被更改。
要解决您的问题,您应该定义View的界面以使用单一方法,例如ToggleEdge:
public interface GraphView
{
event Action ToggleEdge;
}
很想要创建两个方法,EdgeClicked和CheckboxClicked,但坚持使用两个独立的方法,这违反了封装原则。它向Controller或任何想要挂钩这些事件的人暴露了太多的实现细节。请记住,Controller只关心View的状态发生变化,它不关心 它的变化。
在用户界面上实现View界面时,应注意确保从一个位置调用ToggleEdge事件。您可以通过挂钩View中的Edge.Clicked事件并使用它来切换复选框来完成此操作;这使得您的复选框负责将Toggle通风口提升到控制器:
public class UI : UserControl, GraphView
{
public event Action ToggleEdge;
void OnToggleEdge(Edge edge)
{
if (ToggleEdge != null)
ToggleEdge(edge);
}
protected void Edge_Clicked(object sender, EventArgs e)
{
CheckBox chkbox = FindCheckBoxThatCorrespondsToEdge((Edge)sender);
chkbox.Checked = !chkbox.Checked;
}
protected void chkEdge_CheckChanged(object sender, EventArgs e)
{
Edge edge = FindEdgeThatCorrespondsToCheckbox((CheckBox)sender);
OnToggleEdge(edge);
}
}
你可以提出一个观点,即View现在对它的实现了解得太多了:它知道边和复选框是基本连接的。也许这是另一个黑客,但它可能被解雇,因为“UI逻辑”需要保持View的显示同步。