Page State–Step by Step

本文详细介绍了Windows Phone应用程序的生命周期,包括启动、运行、休眠和墓碑化等阶段,并阐述了如何通过管理页面状态来保持用户体验的连贯性,尤其是在应用从休眠或墓碑状态恢复时。

Windows Phone Tutorial


The Windows Phone life cycle is not terribly complicated, but it can be the source of some LifeCycle  confusion, and managing the life-cycle can be intimidating to new Windows Phone programmers.  This posting will review the basic life-cycle of a Windows Phone application and will show you what you need to do to preserve state and give your users a rewarding phone experience.

Reviewing the Life Cycle

When your application is launched (e.g., from the start menu) the Application Launching event is fired. You can hook this event in App.xaml.cs in the Application_Launching event handler, as described in yesterday’s posting on Fast Application Switching.

Once the application is started, and every time the user navigates to your page, you  will receive the OnNavigatedTo method, after which your page will be in the Running state.

If the user starts a new application your application receives the Application Deactivated event and is put in the Dormant state.  If the phone runs low on memory, your application may be Tombstoned.

From either Tombstoned or Dormant your application may be terminated or it may be restored.  What we care about right now is what happens when your application is restored.

If your application is Dormant, you not only don’t have to take any action when you are restored, you don’t want to take any action; all your state was preserved when you were dormant, and you are ready to go.

If on the other hand, your application was tombstoned, then you do want to restore your page state when you return so that it appears to the user that your application was running (or at least dormant) while it was switched away.

Managing Page State

The best way to see how to manage Page State is to build a small application.  Open Visual Studio and create a new Windows Phone application and on the main page add a prompt and a TextBox for the user’s name, and a CheckBox for whether the user is a Geek, as shown in the following code,

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
< Grid
     x:Name = "ContentPanel"
     Grid.Row = "1"
     Margin = "12,0,12,0" >
     < Grid.RowDefinitions >
         < RowDefinition
             Height = "1*" />
         < RowDefinition
             Height = "1*" />
         < RowDefinition
             Height = "4*" />
     </ Grid.RowDefinitions >
     < StackPanel
         Grid.Row = "0"
         VerticalAlignment = "Stretch"
         HorizontalAlignment = "Stretch"
         Orientation = "Horizontal" >
         < TextBlock
             Text = "Full Name:"
             Margin = "5"
             HorizontalAlignment = "Right"
             VerticalAlignment = "Center" />
         < TextBox Name = "FullName" Text = "" Margin = "5"
                  Width = "300"
             HorizontalAlignment = "Right"
             VerticalAlignment = "Center" />
     </ StackPanel >
     < CheckBox
         Name = "Geek"
         Content = "Geek?"
         IsChecked = "True"
         Grid.Row = "1"
         VerticalAlignment = "Center" />
 
</ Grid >

Binding the Controls

Right now the CheckBox and TextBox have hardcoded values. We’d prefer to bind these values to an object.   Create MainPageViewModel.cs and have it implement INotifyPropertyChanged,

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public class MainPageViewModel : INotifyPropertyChanged
{
 
     private string _userName;
     public string UserName
     {
         get { return _userName; }
         set
         {
             _userName = value;
             NotifyPropertyChanged( "UserName" );
         }
     }
 
     private bool _isGeek;
     public bool IsGeek
     {
         get { return _isGeek; }
         set
         {
             _isGeek = value;
             NotifyPropertyChanged( "IsGeek" );
         }
 
     }
 
     public event PropertyChangedEventHandler PropertyChanged;
     private void NotifyPropertyChanged( string propName )
     {
         if (PropertyChanged != null)
         {
             PropertyChanged(
                 this,
                 new PropertyChangedEventArgs( propName ) );
         }
     }
}

Return to the Xaml and change the text property of the TextBox and the content property of the  CheckBox to databind to your new ViewModel,

01
02
03
04
05
06
07
08
09
10
11
12
13
14
< TextBox
     Name = "FullName"
     Text = "{Binding UserName, Mode=TwoWay}"
     Margin = "5"
     Width = "300"
     HorizontalAlignment = "Right"
     VerticalAlignment = "Center" />
 
   < CheckBox
      Name = "Geek"
      Content = "{Binding IsGeek, Mode=TwoWay}"
      IsChecked = "True"
      Grid.Row = "1"
      VerticalAlignment = "Center" />

Add attributes to make the class DataContract Serializable

So far this is straight data-binding, nothing special.  Because you’ll want to save an instance of the MainPageViewModel in Page State, however, you must make it DataContract serializable. You do that with attributes.

Add a reference to the System.Runtime.Serialization library.

Return to the MainPageViewModel.cs file and add the [DataContract] attribute to the class and add [DataMember] attributes to all the properties that you want serialized,

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
[DataContract]
public class MainPageViewModel : INotifyPropertyChanged
{
 
     private string _userName;
 
     [DataMember]
     public string UserName
     {
        //...
     }
 
     private bool _isGeek;
 
     [DataMember]
     public bool IsGeek
     {
        //...
     }

Track the state

The final step is to add a flag to the MainPage class to track whether you are seeing a new instance of the page or a restored instance. It is this flag (_isNewPageInstance) that will ensure that your page is efficient. If you return to the page after being tombstoned you want this flag to be true, but if you return after being dormant you want it to be false.

1
2
MainPageViewModel _vm;
bool _isNewPageInstance = false ;

[ Note that we also added a member variable to hold the MainPageViewModel instance. ]

The Page Logic

Begin by initializing the flag to false (as shown) but setting the flag to true in your constructor.

1
2
3
4
5
public MainPage()
{
     InitializeComponent();
     _isNewPageInstance = true ;
}

Override the OnNavigatedFrom method and save the page state unless the navigation mode is Back, in which case the page is begin discarded and there is no reason to save state,

1
2
3
4
5
6
7
8
9
protected override void OnNavigatedFrom(
     System.Windows.Navigation.NavigationEventArgs e )
{
     if (e.NavigationMode !=
           System.Windows.Navigation.NavigationMode.Back)
     {
         State[ "MainPageViewModel" ] = _vm;
     }
}

Next, override the OnNavigatedTo method. Here is where that flag comes into play.  You might be coming to this page under a number of different conditions. Let’s consider three primary cases:

  • This is your first time on the page – in that case the constructor will be called, and the flag will be true, but there will be nothing in the State dictionary
  • You are returning to this page from being tombstoned – in this case the flag will be true.  When you return from tombstoning the constructor is called and the flag is set to true.
  • You are returning from the application being Dormant – in this case state was preserved and so the flag will be false.

The reason the flag is false when you return from the Dormant state is that we set it to false at the end of OnNavigatedTo (as you’ll see in a moment) and that state is preserved when the page is Dormant. Returning from Dormant does not call the constructor.

The critical difference is that after tombstoning the flag is true (indicating you should go get the state you saved in the Page State dictionary) and after being dormant the flag is false (indicating that you do not need to restore state).

Here’s the override of OnNavigatedTo,

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
protected override void OnNavigatedTo(
     System.Windows.Navigation.NavigationEventArgs e )
{
     if (_isNewPageInstance)
     {
         if (_vm == null )
         {
             if (State.ContainsKey( "MainPageViewModel" ))
             {
                 MessageBox.Show( "Retrieving state..." );
                 _vm = State[ "MainPageViewModel" ]
                                    as MainPageViewModel;
             }
             else
             {
                 _vm = new MainPageViewModel();
             }
         }
         DataContext = _vm;
     }
     _isNewPageInstance = false ;
}

The State Machine

The first time you get here (e.g., when the application is launched) the first if statement evaluates to true (_isNewPageInstance was set to true in the constructor).  The instance of MainPageViewModel will be null but the State object will not contain anything and so you’ll create a new instance of MainPageViewModel.

If you get here from a dormant state then the first if statement will fail ( _isNewPageInstance == false) and you’ll fall through changing nothing and not taking any time to restore state, as state is already intact.  This is a very good thing; no time is wasted restoring state.

Finally, if you get here from being tombstoned the first if statement will evaluate true (remember that you go through the constructor) and the vm will be null, but this time the Page State object will have the MainPageViewModel object and so you can retrieve it.

Run the program and note that the message box does not come up.  Next, stop the application and right click on the project, and choose Properties.  Select the Debug tab and check the checkbox that says Tombstone upon deactivation while debugging.  Run the application and note that the message box does indicate that this time state is being restored.


转载于:https://www.cnblogs.com/ConfuciusPei/archive/2013/03/07/5118419.html

在 Playwright 中,**`state`** 通常指页面、元素或测试环境的当前状态(如加载状态、交互状态、可见性等)。它可以是显式的(如通过 API 获取)或隐式的(如通过等待条件推断)。以下是不同场景下 `state` 的含义和用法: --- ### **1. 页面状态(Page State)** 指整个页面的加载或交互状态,常见于以下场景: #### **(1) 页面加载状态** - **`page.is_visible()`**:检查页面是否可见(如弹出窗口遮挡时返回 `False`)。 - **`page.is_loaded()`**(非直接 API):通过等待导航事件(如 `page.goto()` 的 `wait_until` 参数)间接判断。 ```python # 显式等待页面加载完成(包括网络请求) page.goto("https://example.com", wait_until="domcontentloaded") # 或 "networkidle" ``` #### **(2) 路由拦截状态** - 通过 `page.route()` 拦截请求时,可修改请求/响应的 `state`: ```python async def handle_route(route): # 修改请求状态(如模拟慢网络) await route.continue_(**{"headers": {"x-custom-header": "test"}}) page.route("**/*", handle_route) ``` --- ### **2. 元素状态(Element State)** 指 DOM 元素的可见性、可交互性等状态,Playwright 提供了多种方法检查: #### **(1) 可见性状态** - **`is_visible()`**:元素是否可见(非 `display: none` 或 `visibility: hidden`)。 ```python button = page.locator("button#submit") if button.is_visible(): button.click() ``` #### **(2) 启用状态** - **`is_enabled()`**:元素是否可交互(如未禁用的输入框)。 ```python input_field = page.locator("input[type='text']") if input_field.is_enabled(): input_field.fill("test") ``` #### **(3) 选中状态** - **`is_checked()`**:复选框或单选按钮是否被选中。 ```python checkbox = page.locator("input[type='checkbox']") if not checkbox.is_checked(): checkbox.check() ``` #### **(4) 编辑状态** - **`is_editable()`**:元素是否可编辑(如内容可编辑的 `div`)。 ```python editable_div = page.locator("[contenteditable=true]") if editable_div.is_editable(): editable_div.fill("New text") ``` --- ### **3. 测试状态(Test State)** 指测试运行时的上下文状态,可通过以下方式管理: #### **(1) 自定义状态变量** - 在测试函数中定义变量跟踪状态: ```python def test_login(page): login_success = False page.locator("#username").fill("user") page.locator("#password").fill("pass") page.locator("#submit").click() # 根据元素状态更新测试状态 if page.locator(".success-message").is_visible(): login_success = True assert login_success ``` #### **(2) Playwright Test 的 `test.info()`** - 在 Playwright Test 框架中,可通过 `test.info()` 访问测试状态(如测试名称、附件等): ```python from playwright.sync_api import Page, test @test.describe("Login Flow") def test_login(): @test.step("Step 1: Open page") def step_1(page: Page): page.goto("https://example.com") test.info().attachments.append({"name": "screenshot.png", "path": "screenshot.png"}) ``` --- ### **4. 浏览器上下文状态(Browser Context State)** 指整个浏览器上下文(如 Cookie、存储)的状态: #### **(1) Cookie 状态** - 通过 `context.cookies()` 获取当前 Cookie 状态: ```python context = browser.new_context() page = context.new_page() page.goto("https://example.com") cookies = context.cookies() # 获取当前 Cookie 状态 ``` #### **(2) 存储状态** - 通过 `context.storage_state()` 获取或设置本地存储(LocalStorage/SessionStorage): ```python # 保存当前存储状态 state = context.storage_state(path="state.json") # 后续测试中恢复状态 new_context = browser.new_context(storage_state="state.json") ``` --- ### **5. 动态状态处理(推荐模式)** Playwright 鼓励通过 **显式等待** 而不是轮询来处理状态变化: #### **(1) 等待元素状态变化** ```python # 等待按钮变为可点击 page.locator("button#submit").wait_for(state="visible") # 或 "enabled" # 等待元素消失 page.locator(".loading-spinner").wait_for(state="hidden") ``` #### **(2) 自定义等待条件** ```python from playwright.sync_api import ExpectTimeout def is_logged_in(page): try: return page.locator(".welcome-message").is_visible() except ExpectTimeout: return False # 轮询检查登录状态(不推荐,优先用 wait_for) import time while not is_logged_in(page): time.sleep(1) ``` --- ### **6. 常见问题** #### **Q1: 如何检查元素是否在视口中(Viewport)?** - 使用 `locator.is_in_viewport()`: ```python if page.locator("#floating-button").is_in_viewport(): print("元素在视口中") ``` #### **Q2: 如何模拟网络状态(如离线模式)?** - 通过 `browser.new_context()` 的 `offline` 参数: ```python context = browser.new_context(offline=True) # 模拟离线 ``` #### **Q3: 如何重置页面状态?** - 重新加载页面或创建新上下文: ```python page.reload() # 重置页面状态 # 或 new_context = browser.new_context() # 完全新建上下文 ``` --- ### **总结** | **场景** | **关键方法/属性** | **用途** | |------------------|-------------------------------------------|-------------------------------------------| | 页面状态 | `page.is_visible()`, `wait_until` | 检查加载完成或导航事件 | | 元素状态 | `is_visible()`, `is_enabled()`, `is_checked()` | 验证元素可交互性 | | 测试状态 | 自定义变量、`test.info()` | 跟踪测试执行进度 | | 浏览器上下文 | `cookies()`, `storage_state()` | 管理会话数据 | | 动态状态 | `wait_for(state=...)` | 显式等待状态变化,避免 flaky 测试 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值