ToggleSwitchを分離ストレージに関連付ける

WPFのトグルスイッチは、主に設定に使用する。
これが沢山あると、

ToggleSwitch

XAMLもそうだが、トグルイベントのハンドラもそれに合わせて書かなければならない。設定項目が増えるほど、このハンドラコードをチマチマと追加しなければならず、単純ミスも多くなる。
そこで、これをビヘイビアで何とかしようという話。

アプリケーションが複雑ではない場合、設定情報を単純に分離ストレージに格納すると思う。IsolatedStorageSettings.ApplicationSettingsコレクションを使用すると、出し入れは簡単になる。
ToggleSwitchの状態は、「オン」と「オフ」だけなので、ApplicationSettingsには単純にブール値で格納すれば良い。
そこで:

public sealed class AppSettingsBehavior : Behavior<ToggleSwitch>
{
    public static DependencyProperty SettingNameProperty =
        DependencyProperty.Register(
            "SettingName",
            typeof(string),
            typeof(AppSettingsBehavior),
            new PropertyMetadata(null));

    public static DependencyProperty OnTextProperty =
        DependencyProperty.Register(
            "OnText",
            typeof(string),
            typeof(AppSettingsBehavior),
            new PropertyMetadata("On"));

    public static DependencyProperty OffTextProperty =
        DependencyProperty.Register(
            "OffText",
            typeof(string),
            typeof(AppSettingsBehavior),
            new PropertyMetadata("Off"));

    public AppSettingsBehavior()
    {
    }

    public string SettingName
    {
        get
        {
            return (string)this.GetValue(SettingNameProperty);
        }
        set
        {
            this.SetValue(SettingNameProperty, value);
        }
    }

    public string OnText
    {
        get
        {
            return (string)this.GetValue(OnTextProperty);
        }
        set
        {
            this.SetValue(OnTextProperty, value);
        }
    }

    public string OffText
    {
        get
        {
            return (string)this.GetValue(OffTextProperty);
        }
        set
        {
            this.SetValue(OffTextProperty, value);
        }
    }

    protected override void OnAttached()
    {
        bool value;
        if (IsolatedStorageSettings.ApplicationSettings.TryGetValue(this.SettingName, out value) == false)
        {
            this.AssociatedObject.IsChecked = false;
        }
        else
        {
            this.AssociatedObject.IsChecked = value;
        }

        UpdateContent();

        this.AssociatedObject.Checked += AssociatedObject_Checked;
        this.AssociatedObject.Unchecked += AssociatedObject_Unchecked;
    }

    protected override void OnDetaching()
    {
        this.AssociatedObject.Checked -= AssociatedObject_Checked;
        this.AssociatedObject.Unchecked -= AssociatedObject_Unchecked;
    }

    private void UpdateContent()
    {
        this.AssociatedObject.Content =
            (this.AssociatedObject.IsChecked ?? false) ? this.OnText : this.OffText;
    }

    private void AssociatedObject_Checked(object sender, RoutedEventArgs e)
    {
        IsolatedStorageSettings.ApplicationSettings[this.SettingName] = true;
        UpdateContent();
    }

    private void AssociatedObject_Unchecked(object sender, RoutedEventArgs e)
    {
        IsolatedStorageSettings.ApplicationSettings[this.SettingName] = false;
        UpdateContent();
    }
}

というようなビヘイビアを作っておいて、

<ListBox Grid.Row="1" Margin="0,0,0,0" Padding="0,0,0,0"
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem"
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
        </Style>
    </ListBox.ItemContainerStyle>

    <toolkit:ToggleSwitch Header="正規表現を使用する">
        <i:Interaction.Behaviors>
            <Behaviors:AppSettingsBehavior SettingName="IsRegexMode" OnText="オン" OffText="オフ" />
        </i:Interaction.Behaviors>
    </toolkit:ToggleSwitch>

    <toolkit:ToggleSwitch Header="大小文字を区別する">
        <i:Interaction.Behaviors>
            <Behaviors:AppSettingsBehavior SettingName="IsCaseSensitiveMode" OnText="オン" OffText="オフ" />
        </i:Interaction.Behaviors>
    </toolkit:ToggleSwitch>
</ListBox>

と書くだけで、次々とToggleSwitch項目を簡単に増やすことができる。SettingNameには、分離ストレージに格納するキーの名前を、OnTextとOffTextはスイッチ左側に表示される状態を示すテキストを指定する。これらは依存関係プロパティにしてあるので、バインディングで多国語化することもできる。

投稿者:

kekyo

A strawberry red slime mold. Likes metaprogramming. MA. Bicycle rider. http://amzn.to/1SeuUwD