我有一个WinForm应用程序(.Net 3.5),我们在内部用于数据输入......就像事情一样。会员计划,人口统计数据等应用程序有一个包含所有导航的Shell表单,然后根据导航选项嵌入UserControl。
我需要能够判断他们是否在任何控件中进行了任何更改,以便在他们尝试离开时我可以弹出“保存提醒”。最好的方法是什么?欢迎任何和所有建议。
我认为为每个用户控件上的每个控件挂钩事件来检查是否输入了任何数据是对的,这是不是很荒谬?
答案 0 :(得分:2)
如果您正在使用数据绑定,则可以在类中实现INotifyPropertyChanged(手动或通过生成运行时代理),订阅PropertyChanged事件并在那里进行所有跟踪。 / p>
如果没有,您可以递归迭代窗体/ usercontrol上的控件,为每个控件订阅适当的事件(例如TextChanged
为TextBox
,SelectedItemChanged
为{{1}控制等等)并将调用转发给您的跟踪程序。
答案 1 :(得分:1)
我不会说在这里使用活动会很荒谬,但您可能会对活动注册感到有创意。在实例化用户控件时,您可以循环遍历其中的所有UI控件,并根据UI元素的类型(文本框与标签等),您可以决定将该UI元素的已更改事件连接到处理程序。
你可能每个UI元素类型只有一个处理程序(一个用于文本框,一个用于复选框等),因为我相信这些事件的处理程序需要具有不同的参数。这些处理程序的逻辑也可以拉到自己的类中,这样就不必在每个用户控件中复制相同的处理逻辑。
答案 2 :(得分:1)
Anton编写的必然结果是除非控件绑定到提供更改通知的数据源,否则 挂钩每个控件的事件。不同的控件具有可以更改的不同属性集,有时其中不止一个可能很重要,具体取决于您设计UI的方式。
我维护了一些类似的应用程序,我喜欢使用的模式之一是“事件服务”。您可以使用IoC容器连接所有内容,主窗体/子任务永远不需要实际直接相互通信。
界面如下所示:
public interface IEventService
{
void RaiseChanged(object sender, EventArgs e);
event EventHandler Changed;
}
基本实现非常简单,但无论如何我都会包含它:
public class EventService : IEventService
{
public void RaiseChanged(object sender, EventArgs e)
{
EventHandler handler = Changed;
if (handler != null)
handler(sender, e);
}
public event EventHandler Changed;
}
在您选择的IoC容器中定义它并将其设置为Singleton,或者如果IoC工作太多则将其实现为Singleton;我假设你选择第一个选项。然后您的主表单代码如下所示:
public class MainForm : Form
{
private bool currentTaskChanged;
public MainForm()
{
InitializeComponent();
InitializeChangeEvents();
}
public void LoadTask(ITask task)
{
if (currentTaskChanged)
{
// Confirm whether or not to save changes
}
// Code to change the current task view here ...
currentTaskChanged = false;
}
private void InitializedChangedEvents()
{
IEventService service = IoC.Resolve<IEventService>();
service.Changed += TaskChanged;
}
private void TaskChanged(object sender, EventArgs e)
{
currentTaskChanged = true;
}
}
然后,获得新的子任务/控件变得非常简单:
public class CustomerSetupControl : UserControl
{
public CustomerSetupControl()
{
InitializeComponent();
InitializeChangeTriggers();
}
private void InitializeChangeTriggers()
{
IEventService service = IoC.Resolve<IEventService>();
txtAccountNumber.TextChanged += service.RaiseChanged;
txtName.TextChanged += service.RaiseChanged;
chkIsVip.CheckedChanged += service.RaiseChanged;
// etc.
}
}
你可以理论上通过迭代子任务的整个控制树来自动化其中一些,但这有点困难。例如,如果其中一个控件是CheckBox
,挂钩TextChanged
事件确实无法帮助您。因此,您需要逐个执行此操作,以确保您实际上检测到正确控制的正确更改事件 - 在某些情况下,您甚至可能希望忽略特定控件的更改(即可能存在只是在某处更改过滤器而不修改任何数据的组合框。)
这不是完全我使用的代码,但它非常相似。我建议尝试一下;因为我发现维护起来并不太难,所以你必须记住在添加它们时“注册”新控件。
这种方法特别好用的是任何控件都可以在事件服务中注册;您可以轻松地扩展服务以包括可以在应用程序中的任何位置使用的不同类型的“公共”事件(只需记住从任何不像主表单那样永远不会生存的控件中取消注册事件处理程序。)