アプリケーション設定 その3
id:siokoshou:20060122 でアプリケーション設定を VisualStudio と手書きで混在させる方法が分からないって書いてた件、解決できたのでメモしときます。以下は前回に引き続きユーザー設定の話題を扱ってます。
プロジェクトのプロパティを開くと出てくる画面(プロジェクトデザイナっていうみたい)の「設定」ページ(以下、設定ページ)で、アプリケーション設定とユーザー設定(各ユーザーごとの設定)が簡単に設定できるってとこは前回書いたとおり。設定ページで追加した設定は app.config に反映されて、コンパイルすると最終的には「ほげほげ.exe.config」になります。
設定ページは楽なんだけどできることがかなり限定されてて、アプリケーション設定で用意されてる機能のごく一部しか使えません。かといってせっかく用意されてるツールを捨てて、app.config と ApplicationSettingsBase を継承したクラスを全部手書きするのはもったいない。そこで設定ページでできることは設定ページを使いつつ、できない部分だけ手書きするという共存の道を探ってみました(どこかに情報が載ってそうだけどまだ見つけてない…)。
どうやら app.config に VisualStudio が書き込んだのとは別の section を用意してやれば、共存可能なようです。そうするとユーザー設定セクションが複数あることになりますが、別セクションには何を書いても VisualStudio は干渉してきません。設定値を読み書きする処理は Settings.cs に追加でOKでした。
app.config の VisualStudio が書き込んだ section に手書きで追加してしまうと、VisualStudio が設定ページに自動的に取り込み、さらに Settings.Designer.cs に読み書きするコードも自動で生成してしまいます。こうなると設定ページで app.config が壊れているって警告がでたり、Settings.cs に手書きしたコードと同じプロパティを読み書きするコードが Settings.Designer.cs に重複してできてしまいコンパイルが通らなくなります。
ちょっと整理。
ファイル | 書き換えOK? |
---|---|
app.config | 書き換えOKだけど、VisualStudioも読み書きするので、書き換えてもよいところとマズイところがある。 |
Settings.cs | 設定ページの「コードの表示ボタン」を押すと生成される。書き換えOK。 |
Settings.Designer.cs | VisualStudioが自動生成する。書き換えちゃダメ! |
例がないとややっこしくて何言ってんだかわかんねー、ってわけで以下サンプルで順を追って説明します。
id:siokoshou:20060122#p1 に、Form の Size を手書きで追加します。このくらいのことは設定ページでもできるけど、サンプルってことで。
前回までの時点の app.config は以下のとおり。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSettings" (中略) > <section name="WindowsApplication1.Properties.Settings" (中略) /> </sectionGroup> </configSections> <userSettings> <WindowsApplication1.Properties.Settings> <setting name="FormLocation" serializeAs="String"> <value>0, 0</value> </setting> </WindowsApplication1.Properties.Settings> </userSettings> </configuration>
sectionGroup として userSettings が定義されていて、今ここに一つだけある section の WindowsApplication1.Properties.Settings が VisualStudio が自動生成したセクションです。これとは別のセクションを追加すると、追加した section には VisualStudio が干渉してきません。そこに Size を追加してやります。
先に進む前に、問題点が何のことだか分からないって方は「」の後ろに「
で、話を戻して、まずは sectionGroup 内に section の定義を追加します。WindowsApplication1.Properties.Settings の定義をコピペして、ManualSettings とでも名付けてしまえばOK。name 以外の type やら何やらはそのまま。
次に後ろのほうの userSettings にこのセクションを追加し、FormSize の名前(何でもいいけど)で Size の定義を追加します。
追加後の app.config はこうなります。
<?xml version="1.0" encoding="utf-8" ?> <configuration> <configSections> <sectionGroup name="userSettings" (中略) > <section name="WindowsApplication1.Properties.Settings" (中略) /> <section name="ManualSettings" (中略) /> </sectionGroup> </configSections> <userSettings> <WindowsApplication1.Properties.Settings> <setting name="FormLocation" serializeAs="String"> <value>0, 0</value> </setting> </WindowsApplication1.Properties.Settings> <ManualSettings> <setting name="FormSize" serializeAs="String"> <value>300, 300</value> </setting> </ManualSettings> </userSettings> </configuration>
app.config の詳しいことは「.NET Framework の構成ファイル スキーマ」のあたり。
Settings.cs に読み書きする処理を追加します。この例は設定ページでも設定できる程度のことなので Settings.Designer.cs からコピペしてちょっと直しただけ。検証コードはサンプルなので省略。
[global::System.Configuration.UserScopedSettingAttribute()] [global::System.Configuration.DefaultSettingValueAttribute( "300, 300" )] public global::System.Drawing.Size FormSize { get { return ( ( global::System.Drawing.Size ) ( this[ "FormSize" ] ) ); } set { this[ "FormSize" ] = value; } }
Form1.cs に読み書き処理を追加。
using System; using System.ComponentModel; using System.Windows.Forms; using System.Configuration; namespace WindowsApplication1 { public partial class Form1 : Form { public Form1() { InitializeComponent(); this.Size = Properties.Settings.Default.FormSize; } protected override void OnClosing( CancelEventArgs e ) { try { Properties.Settings.Default.FormSize = this.Size; Properties.Settings.Default.Save(); } catch ( ConfigurationErrorsException ce ) { MessageBox.Show( ce.BareMessage, "Error!" ); } finally { base.OnClosing( e ); } } } }
ついでに AssemblyInfo.cs の Company に test とでも書いて、保存された user.config を見てみてネ。ちょっと驚きます。
コンパイル実行すると、Form の Size を保存/読み取りするようになります。サイズを変更して終了、もう一度実行するとサイズが終了前と同じになってるハズ。
このように VisualStudio が作ったセクションとは別のセクションであれば設定ページは無視してくれるようです。これで設定ページを使いつつも、serializeAs="Binary" なんてのは手書きするってことができます。
正しい方法なのかどうかよく分かってないけど、まぁ多分OK。違うこうやるんだって情報や、ここ見ると書いてあるヨって情報があったら教えてくださいませ。