2011-06-15 49 views
4

我需要存儲我的應用程序窗口的大小/位置和狀態,當用戶關閉應用程序並在用戶打開應用程序時將其設置回。什麼WPF方法可以用來在控件的第一個顯示上設置一些屬性?

我很容易使用註冊表鍵(這是甚至是最好的辦法?),但我想知道我應該把代碼設置爲這些屬性。

我想在窗口第一個「出現」時設置它們。但是,我有可能在這種情況下,可以使用幾種方法,即:

  • Window.Show()
  • Window.Activate()
  • Window.ApplyTemplate()
  • Window.Arrange()
  • Window.ArrangeCore()
  • Window.ArrangeOverride()
  • Window.BeginInit()
  • Window.EndInit()
  • Window.Measure()
  • Window.MeasureCore()
  • Window.MeasureOverride()
  • Window.OnApplyTemplate()
  • Window.OnInitialized()
  • Window.OnRender()
  • Window.UpdateLayout()

我知道,他們中的大多數只是一個壞主意(UpdateLayout()將被稱爲waaaaaaay t例如經常)。意想不到的是,我正在尋找一種方法,只能在窗口中調用一次,這樣我就不必添加一個標誌來檢查這是否是方法的第一個調用。

那麼哪一個在這種情況下是最好的?爲什麼?我把代碼保存在Window.Close()(我重寫我的MyWindow類中的方法)的值,但我也可以把它放在Window.OnClosing()或Window中.OnClosed()。這對我的情況有什麼影響嗎?我還必須保存一個datagrid的列順序,在這種情況下,我應該在哪裏放置「保存」和「加載」代碼?

+0

在我下面的答案中提出的體系結構中,解決你的問題是否值得我去處理?我只問問,因爲對於你當前的架構和我所提出的問題,問題的答案會有所不同 - 希望這是有道理的? =/ – Smudge202 2011-06-15 10:01:34

回答

0

我的選擇:我終於把代碼從窗口中加載註冊表中的值。顯示()。

我這樣做的原因是因爲兩兩件事:

  1. 我保存窗口的狀態,(最小/最大)和WPF做的方式,我需要首先設置寬度/高度,然後是最大化狀態(如果需要),否則它會弄亂佈局。如果我不先設置寬度/高度,那麼當我最大化窗口之後,我會鬆開它們。所以我不得不按照這個順序來做事情:寬度+高度和狀態。 (此外,在使用多個屏幕時,這是必要的,否則會丟失您正在處理的屏幕)。這意味着上面的一些方法是不切實際的(例如「度量」方法)

  2. 如果我把代碼放在上面提到的大多數方法中,我會看到一個不好看的效果在第一次顯示時:窗口將首先以其高度和寬度設置出現在屏幕的中間,然後在一小段延遲之後窗口最大化。

將代碼放在window.Show()中,設法解決這兩個問題。我可能與其他一種或多種方法有相同的結果,但我只是因嘗試不同的配置而感到厭倦,最後使用了第一個讓我完全滿意的方法。

3

好的,在我看來,你像對待一個老派的WinForms應用程序一樣對待WPF。您不再需要監視表單事件以從表單屬性中檢索信息。大多數WPF控件屬性都被稱爲Dependency Property

演示一些聰明的東西依賴屬性介紹的是Data Binding

如果再考慮寫有MVVM Architecture應用程序,你將很快能夠工作下列出自己... =)

在查看* 1,您可以創建依賴屬性,或標準屬性和實施INotifyPropertyChanged,其中包含大小/佈局/位置/等。然後將表單的屬性(xaml或代碼)綁定到視圖的屬性。然後,您可以實現任何您喜歡的功能來存儲/檢索默認設置,並且只需調整視圖中屬性的獲取/設置即可更改表單時自動更新。

由於在Windows的標題一個簡單的例子:

<Window x:Class="MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="{Binding Path=DisplayName}" 
     WindowStartupLocation="CenterScreen" > 
    <Grid>...</Grid> 
</Window> 

示例實現視圖:

public class SampleView : System.ComponentModel.INotifyPropertyChanged 
{ 

    public event PropertyChangedEventHandler System.ComponentModel.INotifyPropertyChanged.PropertyChanged; 
    public delegate void PropertyChangedEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e); 

    private string _Title; 
    public string Title { 
     get { 
      if (_Title == null) { 
       _Title = My.Settings.MainWindowTitle; 
      } 
      return _Title; 
     } 
     set { 
      _Title = value; 
      if (!(_Title == My.Settings.MainWindowTitle)) { 
       if (PropertyChanged != null) { 
        PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("Title")); 
       } 
       My.Settings.MainWindowTitle = Title; 
       My.Settings.Save(); 
      } 
     } 
    } 
} 

編輯:關於如何更好地存儲用戶的喜好,我不會推薦儘管如此,這還遠遠沒有聞所未聞。現在的註冊表已經打包好了,在我看來的設置中,,註冊表並不是真正爲此設計的。考慮將application settings設置爲用戶範圍。這將處理大部分數據存儲/檢索的地方和方式的轉儲,併爲您提供一個很好的類型安全接口。

* 1我個人比較喜歡嘗試將所有東西都綁定到ViewModel上,並且幾乎完全是啞視圖;儘管我知道有很多有效的情況下有代碼的視圖。我不會說Size/Layout /等是真正的業務邏輯關注點,也不是我一直關心的事情,所以這可能應該在View中處理。

EDIT 2 - 的用戶/應用範圍設置一個簡單的例子:

下面是我添加到項目的設置一個快速圖片:

Settings screenshot

下面的代碼試圖使用應用程序和用戶範圍設置。 注:應用範圍設置爲只讀在運行時

public class SettingsExample 
{ 
    private Form1 frmMain = new Form1(); 

    public void Main() 
    { 
     frmMain.BackColor = My.Settings.DefaultBackColour; 
    } 

    public void UserLoggedIn() 
    { 
     frmMain.BackColor = My.Settings.UserBackcolour; 
    } 

    public void UpdateUserBackcolour(System.Drawing.Color newColour) 
    { 
     My.Settings.UserBackcolour = newColour; 
     My.Settings.Save(); 
    } 

    public void UpdateDefaultBackcolour(System.Drawing.Color newColour) 
    { 
     My.Settings.DefaultBackColour = newColour; 
     // Compiler Error 
     // This property is read only because it is an application setting 
     // Only user settings can be changed at runtime 
    } 

} 
+0

oy,我必須說我傾向於與lukas會聚,並發現在這種情況下使用MVVM矯枉過正。在MyWindow類的代碼中保存/加載更簡單輕鬆。 DataBindings不是沒有代價的,只要在應用程序的一生中使用它們來更新屬性及其源代碼,對我來說就顯得太過份了。另外,在這種情況下,請考慮當用戶調整窗口大小(我想保存窗口的大小)時在代碼隱藏中發生的情況:數以千計的讀/寫在註冊表中......我認爲不是最好的方法。 +1的應用程序設置,但我會看看它:) – David 2011-06-15 12:23:34

+0

公平的@大衛,很高興我可以幫助應用程序設置。我認爲可能有很多優點和缺點與綁定。有人可能會在綁定的辯護方面爭辯說,如果應用程序足夠輕以至於無法證明綁定的性能受到任何影響,那麼應用程序可能不夠大,無法關注其中的性能影響。 ^^另外,它引入的模式較少。但是,所有的主觀,最終都會落在你身上。 =) – Smudge202 2011-06-15 12:46:25

+0

我還必須補充說,由於遺留代碼,我必須在後面的代碼中執行大部分實例化/屬性值作用。所以在我的情況下,Bindings實際上會讓事情變得非常混亂,我一定會在我的代碼中避免它們(儘管我用它們來做其他目的,我可以自由地做我想做的事)。但是我在尋找更一般的答案,因此我的問題缺乏細節。我看了一下應用程序設置,但並不真正瞭解它的工作方式。它看起來只限於在Visual Studio中執行。你可能有代碼示例嗎? – David 2011-06-15 13:57:38

0

首先,你忘了

Loaded事件 - 當元素 的佈局,已呈現,並準備 發生相互作用。 (繼承自 FrameworkElement。)

沒有一個簡單的答案。場景可能會有所不同,不管它是一個「兒童」類似於對話框的窗口(那麼我只需在Show())前設置一行大小,同一窗口的新實例或應用程序的新實例即可。

我會爭辯說,UpdateLayout()是一個壞主意。其實,這是一個非常好的主意。例如:

private bool m_onStart = true; 

public MainWindow() 
{ 
     InitializeComponent(); 
     this.LayoutUpdated += new EventHandler(MainWindow_LayoutUpdated); 
} 

void MainWindow_LayoutUpdated(object sender, EventArgs e) 
{ 
    if (m_onStart) 
    { 
     m_onStart = false; 
     Dispatcher.BeginInvoke(() => 
     { 
       //Start App 
     } 
     ); 
    } 
} 

即使它被稱爲每秒一千時間(這是非常不可能的),你甚至不會注意到它並不會傷害性能。

總而言之,您可以創建一個輔助方法來保存用戶偏好,然後再讀取它。由於該任務與視圖相關,並且使用MVVM和綁定對此是一種矯枉過正,因此在Loaded事件中設置大小(在完成所有ctors,初始化和可視化樹時執行此操作)。

+0

「bi [n] ding是這個矯枉過正」。我不是在爭論這個問題,只是想知道爲什麼? – Smudge202 2011-06-15 10:11:26

+1

,因爲你需要設置一大堆東西來完成簡單的任務。這就是爲什麼MVVM燈做得很好。 「第二個來自MVVM的創建者John Gossman自己[8],他指出實現MVVM的開銷對於簡單的UI操作是」過度的「,他還指出,對於更大的應用程序來說,推廣View層變得更加困難,他表明數據綁定如果管理不好,可能會在應用程序中導致大量內存消耗。「 – 2011-06-15 10:41:19

+0

我還沒有機會通過MVVM光,所以謝謝你提到它。不確定你的意思是「你需要設置很多東西」,因爲比較我們的兩個代碼示例,代碼量似乎沒有太大差異,並且我發佈的代碼不需要維護(本身)一個狀態 - m_onStart標誌。但是,我會瀏覽我能找到的MVVM light文章並全力以赴。謝謝回覆! – Smudge202 2011-06-15 10:48:01

相關問題