スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: スポンサー広告

WindowVMの次は、TextBox用VMだろうと。

Window用ViewModelクラスの基礎はほぼ作れたので、次は、各コントロール用VMを作っていく事にした。
一番連携したいプロパティ。
・Textプロパティ
・IsEnabledプロパティ
・IsReadOnlyプロパティ
・IsFocucedプロパティ
この4つは是非ほしいところ。でも、TextプロパティとIsFocucedプロパティ以外は、TextBoxではなく、UIElementクラスのプロパティなんだよな。IsFocucedプロパティとの連動は、添付プロパティでなんとかなるだろ。というわけで、TextBoxよりまず先にUIElement用のVMを作ることにした。
using System;

namespace TawamureDays.ViewModels {

/// <summary>
/// UIElement用ViewModelクラス
/// </summary>
public class UIElementVM : BaseViewModel {

#region プロパティ

/// <summary>有効かどうか</summary>
private bool isEnabled_;

/// <summary>
/// 有効かどうかを取得|設定します。
/// </summary>
public bool IsEnabled {
get {return isEnabled_;}
set {
if (isEnabled_ != value) {
isEnabled_ = value;
this.NotifyPropertyChanged("IsEnabled");
}
}
}

/// <summary>読み取り専用かどうか</summary>
private bool isReadOnly_;

/// <summary>
/// 読み取り専用かどうかを取得|設定します。
/// </summary>
public bool IsReadOnly {
get {return isReadOnly_;}
set {
if (isReadOnly_ != value) {
isReadOnly_ = value;
this.NotifyPropertyChanged("IsReadOnly");
}
}
}

/// <summary>フォーカスを当てるかどうか</summary>
private bool isFocused_;

/// <summary>
/// フォーカスを当てるかどうかを取得|設定します。
/// </summary>
public bool IsFocused {
get {return isFocused_;}
set {
if (isFocused_ != value) {
isFocused_ = value;
this.NotifyPropertyChanged("IsFocused");
}
}
}

#endregion
}
}
これを更に継承して、TextBox用のViewModelを作る。
using System;

namespace TawamureDays.ViewModels {

/// <summary>
/// TextBox用ViewModelクラス
/// </summary>
public class TextBoxVM : UIElementVM {

#region コンストラクタ

/// <summary>
/// コンストラクタ
/// </summary>
public TextBoxVM() : base() {
}

/// <summary>
/// コンストラクタ
/// </summary>
/// <param name="inputValue">初期値</param>
public TextBoxVM(string inputValue) : this() {
inputValue_ = inputValue;
}

#endregion

#region プロパティ

/// <summary>入力値</summary>
private string inputValue_;

/// <summary>
/// 入力値を取得|設定します。
/// </summary>
public string InputValue {
get {return inputValue_;}
set {
if (inputValue_ != value) {
inputValue_ = value;
this.NotifyPropertyChanged("InputValue");
}
}
}

#endregion
}
}


使い方としては、とりあえずこんなもの。
○ViewModel側
using System.Windows;
using System.Windows.Input;

namespace TawamureDays {

/// <summary>
/// ViewModelクラス
/// </summary>
public class TawamureVM : BaseWindowVM {

#region コンストラクタ

/// <summary>
/// コンストラクタ
/// </summary>
public TawamureVM() {
closeCommand_ = new RelayCommand(ExecuteCloseCommand);
TextBoxVM = new TextBoxVM();
return;
}

#endregion

#region プロパティ

/// <summary>終了用コマンド</summary>
private RelayCommand closeCommand_;

/// <summary>
/// 終了用コマンドを取得します。
/// </summary>
public ICommand CloseCommand {
get {return closeCommand_;}
}

/// <summary>
/// テキストボックス用VMを取得します。
/// </summary>
public TextBoxVM TextBoxVM {
get; private set;
}

#endregion
}
}

○View側(XAML)
<Window x:Class="TawamureDays.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tw="http://schemas.tawamuredays.jp/wpf/gui"
Title="MainWindow" Height="350" Width="525">
<tw:TawamureContents>
<StackPanel>
<TextBox DataContext="{Binding TextBoxVM}"
Text="{Binding InputValue}"
IsEnabled="{Binding IsEnabled}"
IsReadOnly="{Binding IsReadOnly}"
tw:FrameworkElementBehavior.IsFocused="{Binding IsFocuced}"
/>
</StackPanel>
<tw:TawamureContents.Footer>
<Button Content="終われ!" Command="{Binding CloseCommand}"/>
</tw:TawamureContents.Footer>
</tw:TawamureContents>
</Window>

・TextBoxのTextプロパティはデフォルトでMode=TwoWay。明示的な設定は不要
・IsEnabledやIsReadOnlyはOneWayでも良いかもしれない。
まあ、これでViewModel側からの連携が可能となる。
(追記)
ただし、上記バインディングを行なってしまうと、TextBoxのIsReadOnlyプロパティをソースとするようなバインディングはできない。いや、できるけど、自分の思うようにはならなかった。
例えば上のXAMLを以下のように変える。
<Window x:Class="TawamureDays.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tw="http://schemas.tawamuredays.jp/wpf/gui"
Title="MainWindow" Height="350" Width="525">
<tw:TawamureContents>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<Trigger Property="TextBox.IsReadOnly" Value="True">
<Setter Property="TextBox.BorderBrush" Value="Black"/>
<Setter Property="TextBox.BorderThickness" Value="2"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBox Name="Text1"
DataContext="{Binding TextBoxVM}"
Text="{Binding InputValue}"
IsEnabled="{Binding IsEnabled}"
IsReadOnly="{Binding IsReadOnly}"
tw:FrameworkElementBehavior.IsFocused="{Binding IsFocuced}"
/>
<CheckBox IsChecked="{Binding IsReadOnly, ElementName=Text1,
Mode=OneWayToSource}">ReadOnlyにするぞ</CheckBox>
</StackPanel>
<tw:TawamureContents.Footer>
<Button Content="終われ!" Command="{Binding CloseCommand}"/>
</tw:TawamureContents.Footer>
</tw:TawamureContents>
</Window>
これは、チェックボックスのチェク状態で、TextBoxのReadOnlyを切り替えようとするもの。切り替わったかどうかを視覚的に見やすくするために、Triggerを仕込んでている。実際に実行すると、たしかに動作する。
20120913_2
チェックをつけると…。
20120913_1
ただし、ViewModel側のIsReadOnlyプロパティとは一切連携できていない。そもそも、画面起動段階で、TextBox.IsEnabled←→DataConxtext(TextBoxVM).IsReadOnly間のデータバインディングが、CheckBox.IsChecked→TextBox.IsReadOnly間のバインディングに切り替わっている。イメージ(思惑)的には、CheckBox.IsChecked→TextBox.IsReadOnly→DataConxtext(TextBoxVM)のIsReadOnlyに伝播して欲しいんだけど、そんなうまい具合にはできていない。直接バインディングが嫌な感じがするようであれば、下のような感じにする。

<Window x:Class="TawamureDays.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:tw="http://schemas.tawamuredays.jp/wpf/gui"
Title="MainWindow" Height="350" Width="525">
<tw:TawamureContents>
<StackPanel>
<StackPanel.Resources>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsReadOnly}" Value="True">
<Setter Property="TextBox.IsReadOnly" Value="True"/>
</DataTrigger>

<Trigger Property="TextBox.IsReadOnly" Value="True">
<Setter Property="TextBox.BorderBrush" Value="Black"/>
<Setter Property="TextBox.BorderThickness" Value="2"/>
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<TextBox Name="Text1"
DataContext="{Binding TextBoxVM}"
Text="{Binding InputValue}"
IsEnabled="{Binding IsEnabled}"
tw:FrameworkElementBehavior.IsFocused="{Binding IsFocuced}"
/>
<CheckBox IsChecked="{Binding IsReadOnly, ElementName=Text1, Mode=OneWay}">ReadOnlyにするぞ</CheckBox>
</StackPanel>
<tw:TawamureContents.Footer>
<Button Content="終われ!" Command="{Binding CloseCommand}"/>
</tw:TawamureContents.Footer>
</tw:TawamureContents>
</Window>
DataTriggerを使って、TextBoxのIsReadOnlyと連携している。直接バインディングしているわけではないので、CheckBoxのIsCheckedに値が流れ込んでいく。
ただし、CheckBoxとのバインディングをTwoWayとかにするととたんに連動しなくなる。ViewModel側の変更をDataTriggerで通知できても、View側の変更をViewModelが認識できていないから。
まあ、直接バインディングするよりは、こっちがまだ融通効くかなと。
スポンサーサイト
当サイトは基本をすっ飛ばしてます。基本文法等は、@ITをどうぞ
カテゴリー: WPF4 | コメント: 0 | トラックバック: 0


この記事へのコメント

コメントの投稿

非公開コメント


サイドバー背後固定表示サンプル

当ブログに書かれたソースコードは流用自由です。

バグ、スペルミス等はありうる事です。

ご利用の際は自己責任でお願いしますm(_ _)m

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。