C# 跟踪UWP中的表单是否脏
我试图跟踪UWP中表单的脏(修改)状态,该表单在视图和模型之间使用双向绑定 我目前跟踪各个已更改事件的方法(文本框的TextChange、组合框的SelectionChanged等)在页面加载数据时除外 似乎正在发生的事情是,在页面完全加载之后,仍然在对绑定进行评估,从而使表单认为它已被修改。通过逐步浏览我的代码,我在加载页面时构建了以下典型的时间线:C# 跟踪UWP中的表单是否脏,c#,uwp,C#,Uwp,我试图跟踪UWP中表单的脏(修改)状态,该表单在视图和模型之间使用双向绑定 我目前跟踪各个已更改事件的方法(文本框的TextChange、组合框的SelectionChanged等)在页面加载数据时除外 似乎正在发生的事情是,在页面完全加载之后,仍然在对绑定进行评估,从而使表单认为它已被修改。通过逐步浏览我的代码,我在加载页面时构建了以下典型的时间线: 模型已初始化(脏=假) 将检索数据并将其放置在模型中 绑定触发,填充表单(dirty=true) 页面的已加载事件被命中,此时我设置dirty
- 模型已初始化(脏=假)
- 将检索数据并将其放置在模型中
- 绑定触发,填充表单(dirty=true)
- 页面的已加载事件被命中,此时我设置dirty=false
- 继续设置绑定,从而将dirty重置为true
- (我需要一些东西将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"/>
最终的结果是,在用户对表单执行某种交互之前,不能将表单设置为Dirty
这在75%的时间内有效,并且不会产生误报(如果表单不干净,则表示表单脏了),但确实会产生一些误报,因为单击单选按钮、复选框或切换开关时,点击事件似乎不会触发。如果用户执行的唯一交互是在文本框中按一个键,那么它也会失败,因为在按下键之前会触发TextChanged事件,但是我们的用户只在文本框中输入一个字符的可能性微乎其微,因为他们的修改几乎没有,所以这一点不是主要问题。您的ViewModel是如何安装的 对于您的班级:
public class OrderModel : INotifyPropertyChanged
{
private OrderCase order;
public OrderCase Order
{
get
{
return order;
}
set
{
if (value != order) { IsDirty = true; }
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
var tempModel = new OrderModel();
tempModel = await WcfService.GetOrder(OrderId);
Model.Order = tempModel;
//Setting the ViewModel's property only when getting order is completed
//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;
}
否则,您可以尝试在ViewModel中添加每个属性,而不是仅添加OrderCase的一个副本。。。只是一个想法您不能在其他属性设置程序中设置IsDirty属性吗?只有当数据发生更改时,才会调用setter。问题是绑定到表单并存储在模型中的实际数据的类型来自WCF数据协定,因此,来自WCF的对象中属性的设置程序无法访问模型的IsDirty字段。您如何知道绑定的设置(最后一个要点)已完成?这个问题的答案基本上取决于绑定设置后触发的任何事件。如果没有事件,这将是一个猜谜游戏。您是否可以添加一个方法来设置私有属性而不是公共属性,从而不触发NotifyPropertyChangedEvent@Flater我的理解是,加载的事件应该是在用户拥有控制权之前触发的最后一个事件,但是,在加载事件之后,仍然会触发对_change事件的控制,这几乎就像竞争条件一样。如果设置了整个Order对象,这会起作用,但是OrderCase类型中有一组对象和属性,这些对象和属性绑定到视图。是顺序中的单个对象,如字符串CustomerName,在更改时需要将dirty属性设置为true。如何设置dirty属性?你能给我们看一个更完整的代码吗?谢谢这不起作用有两个原因:1。尽管OnNavigatedTo方法发生了更改,但竞争条件仍然存在。页面加载方法完成后,仍在评估绑定。2.在Order setter中设置Dirty不起作用,因为Order对象只是在最开始时设置的,当OrderCase中的属性被设置时,setter不会触发。如果您不能控制OrderModel,您可以修改ViewModel并公开OrderModel的每个属性,因此,您可以访问每个属性的设置程序。。。我知道这不是最好的解决办法
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
var tempModel = new OrderModel();
tempModel = await WcfService.GetOrder(OrderId);
Model.Order = tempModel;
//Setting the ViewModel's property only when getting order is completed
//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;
}