【发布时间】:2018-04-23 20:56:33
【问题描述】:
我正在尝试跟踪 UWP 中表单的脏(修改)状态,该表单在视图和模型之间使用两种方式绑定。
我当前跟踪相应更改事件的方法(文本框的 TextChange、组合框的 SelectionChanged 等)在页面加载数据时有效。
似乎正在发生的是,在页面完全加载后仍在评估绑定,从而使表单认为它已被修改。从单步执行我的代码开始,我在加载页面时构建了以下典型时间线:
- 模型已初始化(dirty = false)
- 数据被检索并放置在模型中
- 绑定触发器,填写表单(dirty = true)
- 页面的Loaded事件被命中,此时我设置dirty = false
- 绑定继续设置,因此将脏设置为真
- (我需要在这里设置一些东西来将dirty设置为false)
是否有在所有绑定第一次评估后触发的事件,或以某种方式跟踪绑定是否已全部评估?
编辑:一些粗略的示例代码可以更好地了解我是如何设置的
型号:
public class OrderModel : INotifyPropertyChanged
{
private OrderCase order;
public OrderCase Order
{
get
{
return order;
}
set
{
order = value;
this.RaisePropertyChanged("Order");
}
}
private bool dirty;
public bool Dirty
{
get
{
return dirty;
}
set
{
dirty = value;
}
}
}
查看 - 代码隐藏
OrderModel Model;
int OrderId;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
//Call a method in the View Model which calls a WCF service
//to get the OrderCase object out of our database and into the
//Order object in the model
Model = new OrderModel();
Model.Order = await WcfService.GetOrder(OrderId);
//Once this returns all the bindings start evaluating
}
private void Page_Loaded(object sender, RoutedEventArgs e)
{
SetUndirty();
}
public override void TextBoxSetDirty(object sender, TextChangedEventArgs e)
{
//one of these exists for each type of control I use
//this gets triggered when the text changes due to the model changing
SetDirty();
}
public void SetDirty()
{
Model.Dirty = true;
}
查看 - XAML
<TextBox
Text = "{x:Bind Path=Order.CustomerName, mode=TwoWay}"
TextChanged="TextBoxSetDirty"/>
视图大体相同,包括 ComboBoxes、RadioButtons、ToggleSwitches 和 SyncFusion Datagrid
编辑 2: 我目前有一个解决方法,另一个名为“UserHasInteracted”的属性最初为 False,但在页面的 KeyDown 或 Tapped 事件触发时,它被设置为 true,并且 SetDirty 方法被修改为:
public void SetDirty()
{
if (UserHasInteracted)
Model.Dirty = true;
}
最终结果是,在用户对其进行某种交互之前,该表单无法设置为“脏”。
这大约有 75% 的时间有效,并且不会产生误报(说表单不是脏的时候),但确实会产生一些误报,因为当 RadioButton 时,Tapped 事件似乎不会触发、 CheckBox 或 ToggleSwitch 被单击。如果用户执行的唯一交互是文本框中的单个按键,它也会失败,因为 TextChanged 事件在 KeyDown 之前触发,但是我们的用户只会在文本框中输入单个字符的可能性很小,因为他们的修改很小没有,所以这不是一个主要问题。
【问题讨论】:
-
你不能在你的其他属性设置器中设置一个 IsDirty-Propertie 吗?只有当你的数据发生变化时,setter 才会被调用
-
问题在于绑定到表单并存储在模型中的实际数据属于来自 WCF 数据协定的类型,因此对象中属性的设置器来自 WCF 无法访问模型的 IsDirty 字段。
-
你怎么知道绑定的设置(最后一个要点)已经完成?这个问题的答案基本上取决于绑定设置后触发的任何事件。如果没有事件,这将是一场猜谜游戏。
-
您可以添加一个方法来设置私有属性而不是公共属性,因此不会触发 NotifyPropertyChangedEvent
-
@Flater 我的理解是 Loaded 事件应该是在用户拥有控制权之前触发的最后一个事件,但是在 Loaded 事件之后仍然触发控件 on_change 事件,几乎就像一个竞争条件.