2010年2月1日月曜日

第11回 つぶやきを投稿する

前準備としてSystem.Web.dllへの参照を追加してください。

前回RoutedUICommandを使いましたが、
いきなりですが、これをやめます。

RoutedCommand(またはRoutedUICommand)はあらかじめ用意された実装で、
WPFではRoutedCommandを前提に作られている部分も多そうなのでこっちにしようかと思っていましたが、
MVVMの記事で使われているRelayCommandを素直に使うことにします。
http://msdn.microsoft.com/ja-jp/magazine/dd419663.aspx

作り込んでみないとわかりませんが、RoutedCommandに比べてRelayCommandは
・簡単なコマンドに対してはCommandBindingや
Viewのイベントハンドラなどの記述が不要ですっきりする。
・ViewModelだけでロジックを完結させやすい。
の2点がメリットかなと思っています。
RelayCommandはそれ自体に処理を持たせることができます。
RelayCommandのコードは上記リンクを見てください。

まず前回のURLを開くコマンドを作り直します。
ViewModelにコマンドを作ります。



 class TimelineItemViewModel {
  private Status _item;

  private RelayCommand _openByBrowserCommand;
  /// <summary>
  /// パラメータで与えられたURLをブラウザで開くコマンド
  /// </summary>
  public RelayCommand OpenByBrowserCommand {
   get {
    if (_openByBrowserCommand == null) {
     _openByBrowserCommand = new RelayCommand(this.OnOpenByBrowserRequested);
    }
    return _openByBrowserCommand;
   }
  }

  /// <summary>
  /// ブラウザで開く
  /// </summary>
  /// <param name="parameter">開くURL(string)が入ったobject</param>
  private void OnOpenByBrowserRequested(object parameter) {
   var url = parameter as string;
   if (!string.IsNullOrEmpty(url)) {
    Process.Start(url);
   }
  }



コマンドの処理を実装するメソッドOnOpenByBrowserRequestedを作り、
そのメソッドへ関連づけられたコマンドを表すOpenByBrowserCommandプロパティを公開します。

ViewはコマンドのBind方法が以下のように変わります。
CommandBindingなどの記述がなくなっていることに注意してください。
Commandsクラスもなくなっています。



<Hyperlink Command="{Binding Path=OpenByBrowserCommand}" CommandParameter="{Binding Path=UserUrl}" >

今回の追加機能である投稿機能を作ります。
まずViewModel。



 class SubmitPanelViewModel : ViewModelBase {
  private UserInfo _userInfo;

  private string _editingText = "";
  /// <summary>
  /// 入力中のテキスト
  /// </summary>
  public string EditingText {
   get { return _editingText; }
   set {
    if (_editingText != value) {
     _editingText = value;
     OnPropertyChanged("EditingText");
    }
   }
  }

  private ICommand _submitCommand;
  /// <summary>
  /// 投稿
  /// </summary>
  public ICommand SubmitCommand {
   get {
    if (_submitCommand == null) {
     _submitCommand = new RelayCommand(
      param => this.Submit(), param => this.CanSubmit);
    }
    return _submitCommand;
   }
  }

  /// <summary>
  /// コンストラクタ
  /// </summary>
  /// <param name="info">ユーザー認証情報</param>
  public SubmitPanelViewModel(UserInfo info) {
   _userInfo = info;
  }

  /// <summary>
  /// 投稿する
  /// </summary>
  public void Submit() {
   StatusMethods.Update(_editingText, _userInfo);
   EditingText = "";
  }

  /// <summary>
  /// 投稿できる状態かどうかの判断
  /// </summary>
  public bool CanSubmit {
   get { return _editingText.Length > 0; }
  }

  public override string ToString() {
   return "SubmitPanelViewModel";
  }
 }


編集中のテキストを持っていて、投稿(Submit)のためのコマンドも持っています。
また、文字が入力されている(Length>0)かどうかで
CanExecute(メソッド名はCanSubmit)を判断しています。


そのほかに新しいのはViewModelBaseを作って継承しています。
これは今はまたViewModelに共通の処理OnPropertyChangedを提供するだけです。
ViewModelBaseはMVVMの記事でも紹介されていますが、
INotifyPropertyChangedを実装します。
PropertyChangedイベントを発行することで、プロパティ(今回の例ではEditingText)が
変化したことをViewに伝えることができます。

投稿するメソッドStatusMethods.Upate()は長くなるので最後のリンク先のコードを見てください。
タイムラインを取得するときとやることはあんまり変わりません。

上記のViewModelに対応するViewを作ります。
それぞれBindしてやるだけです。



<UserControl x:Class="WTwitter.View.SubmitView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:vw="clr-namespace:WTwitter.View">
 
 <DockPanel>
  <Button Content="投稿" Command="{Binding Path=SubmitCommand}"
    HorizontalAlignment="Right" Width="Auto" DockPanel.Dock="Right" />
  
  <TextBox Text="{Binding Path=EditingText, UpdateSourceTrigger=PropertyChanged}"
     MinHeight="50"/>

 </DockPanel>
</UserControl>




UpdateSourceTrigger=PropertyChangedを指定してやることで
1文字入力するごとに変更がViewModelに伝わって
CanExecuteが判定されます(それによってボタンが無効になったりします。)

最後に
1.MainWindowViewModelに今回のSubmitPanelViewModelを持たせてやる
2.MainWindowにContentPresenterを使ってデータを表示するように指示する
3.DataTemplateを作って2のデータの表示方法をSubmitViewになるようにする



<Window x:Class="WTwitter.View.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 xmlns:vm="clr-namespace:WTwitter.ViewModel"
 xmlns:vmt="clr-namespace:WTwitter.ViewModel.Twitter"
 xmlns:vw="clr-namespace:WTwitter.View"
 xmlns:CompModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
    Title="WTwitter" Height="500" Width="400">
 
 <Window.Resources>
  <DataTemplate DataType="{x:Type vmt:TimelineViewModel}">
   <vw:TimelineView/>
  </DataTemplate>
  
  <DataTemplate DataType="{x:Type vm:SubmitPanelViewModel}">
   <vw:SubmitView/>
  </DataTemplate>
 </Window.Resources>
 
 <DockPanel>
  <ContentPresenter Content="{Binding Path=SubmitPanel}"
   DockPanel.Dock="Bottom" />

  <TabControl ItemsSource="{Binding Path=Timelines}">
   <TabControl.ItemTemplate>
    <DataTemplate>
     <TextBlock Text="{Binding Path=DisplayName}"/>
    </DataTemplate>
   </TabControl.ItemTemplate>
  </TabControl>
 
 </DockPanel>
</Window>



長くなったので結構説明はしょりました。すみません。。


今回のコード
http://wtwitter.codeplex.com/SourceControl/changeset/view/39862

3 件のコメント:

  1. My programmer iѕ trying to cοnvinсe me to movе tо .
    net from РНP. I havе alwaуs diѕlikeԁ
    the idea because of thе expenses. But hе's tryiong none the less. I've beеn uѕing WordPгеsѕ on
    ѕeνeгal wеbsіtes foг аbοut а year and
    am сoncernеԁ about ѕwіtching to another platform.
    I haѵe heагd very goοԁ thingѕ about blogengіne.
    net. Ӏs therе а ωaу I can transfеr all my woгdpress content into it?
    Any help would be greаtly appгeciatеd!
    Here is my page ; small url

    返信削除
  2. Unfortunately, I have no idea about your concern,
    and didn't touch with .net these years.
    In addition, I have never heard that .net has advantage for websites.

    and, I can't open your link.

    返信削除
  3. Its like you read my mind! You seem to know
    so much about this, like you wrote the book in it or something.
    I think that you can do with some pics to drive the message home a bit,
    but instead of that, this is wonderful blog. An excellent read.

    I will certainly be back.
    My webpage :: buy website traffic

    返信削除