2012年4月6日金曜日

memo: munin で MySQL のグラフが生成されない

/var/log/munin/munin-node.log にエラーログが出てた:
Service 'mysql_slow' exited with status 255/0.
Error output from mysql_slow:
    Missing dependency Cache::Cache at /etc/munin/plugins/mysql_slow line 703.
perl の Cache::Cache モジュールが足りなかったようなので、apt-get install libcache-cache-perl で解決。

2012年4月2日月曜日

WP7: DatePicker, TimePicker でアイコンが表示されない

Silverlight Toolkit の DatePicker, TimePicker で、アイコンを表示する手順のメモ。
やるべきことが 3 つあって、
  • プロジェクトルート直下に "Toolkit.Content" フォルダを作る
  • "ApplicationBar.Cancel.png" と "ApplicationBar.Check.png" をそこに追加する
  • これらのプロパティで "ビルドアクション" を "コンテンツ" にする
最後を見落としていて、小一時間悩んでしまった。Silverlight は難しい。。

2012年3月18日日曜日

[メモ] Windows Phoneアプリ公開にあたって抑えておくこと

とリストアップしたけど、結局 http://thinkit.co.jp/book/2012/03/15/3475 に十分まとまっていた。 (2012.3.22 URL 追加)
(2012.3.23 追記)

2012年3月12日月曜日

WP7: アプリケーションの設定の保存

IsolatedStorageSettings.ApplicationSettings を使ってアプリケーションの設定を保存します。
key は string 型、value は object 型。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.IO.IsolatedStorage;
using System.Diagnostics;

namespace ApplicationSettingsTest
{
    public partial class MainPage : PhoneApplicationPage
    {
        // コンストラクター
        public MainPage()
        {
            InitializeComponent();

            IsolatedStorageSettings settings =  IsolatedStorageSettings.ApplicationSettings;

            // 登録済みの値を出力
            foreach (var s in settings)
            {
                Debug.WriteLine("settings[{0}] = {1}", s.Key, s.Value);
            }
            // 登録件数を出力
            Debug.WriteLine("count: {0}", settings.Count());

            // 値を複数登録
            for (int i = 0; i < 3; i++)
            {
                string key = string.Format("key{0}", i);
                // Add() では上書きはできないので消す
                if (settings.Contains(key))
                {
                    settings.Remove(key);
                    Debug.WriteLine("{0}: removed", key);
                }
                settings.Add(key, "value hoge");
            }

            // 辞書の場合は上書き可能
            settings["key"] = "aValue";

            // TryGetValue は、キーがない時 false を返す
            string value1;
            if (settings.TryGetValue<string>("key", out value1))
                Debug.WriteLine("type is string");

            // 型が違う場合は例外が送出される
            //int value2;
            //if (settings.TryGetValue<int>("key", out value2))
            //    Debug.WriteLine("type is not int");

            // 書き込む
            settings.Save();

            // 全削除
            //settings.Clear();
        }
    }
}

2012年3月11日日曜日

wp7: テキストの色を C# から変更する

<TextBlock Name="aTextBlock" Foreground="Black"/>
という XAML があったときに、
aTextBlock.Foreground = new SolidColorBrush(Colors.Red);
などとします。
... とテキストの色を変えるためだけにインスタンスを生成するのは馬鹿げているような気もするけど、そういうもの??

2012年2月26日日曜日

AutoHotKey script for Mac User

以前、visual studio のキーバインドを emacs 風にする方法を書きましたが、 VSの外では依然として元のキーバインドのままで不満がありました。
特にマウススクロールの方向が Lion で逆になったのでとても違和感があります。 横スクロールできないのもストレスでした。
AutoHotKey でそれなりに設定していったところ、Mac 風の操作に近づけることができたので、 GitHub で公開してみました。
github.com/zakkie/MacAHK

2012年2月21日火曜日

ListBoxItem の変更

前回のブログでリストアイテムの追加について書きました。
しかしながらあのコードでは各アイテム内のデータを変更することができません (変更しても UI に反映されない、がより正確か)。
これを実現するためには INotifyPropertyChanged を実装するより他ないようです。 前回のコードの Car class を以下で置き換えます。
    public class Car : INotifyPropertyChanged
    {
        public string _Name;
        public string _Manufacturer;
        public event PropertyChangedEventHandler PropertyChanged;

        // コンストラクター
        public Car(string name, string manufcturer)
        {
            _Name = name;
            _Manufacturer = manufcturer;
        }

        public string Name
        {
            get {return _Name;}
            set {
                _Name = value;
                NotifyPropertyChanged("Name");
            }
        }
        private void NotifyPropertyChanged(string p)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(p));
        }
    }
ビルドして、Button を押すと先頭の RX-7 が RX-8 になるのが分かります。すなわち内容の書き換えがこれで可能になりました。

2012年2月20日月曜日

データバインディングしている ListBox にアイテムを追加する

例えば、ListBox のバインディングソースとして、List<T> なオブジェクトを指定していると、 list.Add(hoge) のようなことをしても、それは ListBox に反映されません。
これを反映させるためには INotifyPropertyChanged を実装して、 PropertyChanged イベントを発生させる必要がありますが、 ObservableCollection<t> でくるむと簡単に実装することができることを id:ch3cooh393 さんのブログで知り、試しに作ってみました。
XAML
<phone:PhoneApplicationPage 
    x:Class="ListBoxTemplate1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">
    
    <!-- テンプレート -->
    <phone:PhoneApplicationPage.Resources>
        <DataTemplate x:Key="ItemTemplate">
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=Name}" Width="100" />
                <TextBlock Text="{Binding Path=Manufacturer}" />
            </StackPanel>
        </DataTemplate>
    </phone:PhoneApplicationPage.Resources>

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>


        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <Button Content="Button" HorizontalAlignment="Left" Name="button1"
                    Click="button1_Click" VerticalAlignment="Top" />
            <Grid Margin="0,90,0,0">
                <ListBox Name="listBox1" ItemTemplate="{StaticResource ItemTemplate}"/>
            </Grid>
        </Grid>
    </Grid>
</phone:PhoneApplicationPage>
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace ListBoxTemplate1
{
    public partial class MainPage : PhoneApplicationPage
    {
        List<Car> carList;
        ObservableCollection<Car> ob;

        // コンストラクター
        public MainPage()
        {
            InitializeComponent();
            UpdateListBox();
        }

        private void UpdateListBox()
        {
            carList = new List();
            carList.Add(new Car("RX-7", "Mazda"));
            carList.Add(new Car("Stepwgn", "Honda"));
            carList.Add(new Car("Vitz", "Toyota"));

            ob = new ObservableCollection(carList);
            listBox1.ItemsSource = ob;

            // (*) このバインディングでは UI は更新されない
            //listBox1.ItemsSource = carList;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            ob.Add(new Car("Skyline", "Nissan"));
            ob[0].Name = "RX-8"; // これは UI に反映されない

            // (*)
            //carList.Add(new Car("Impreza", "Subaru"));
            //carList[0].Name = "Demio"
        }
    }

    public class Car
    {
        public string Name { get; set; }
        public string Manufacturer { get; set; }

        // コンストラクター
        public Car(string name, string manufcturer)
        {
            Name = name;
            Manufacturer = manufcturer;
        }
    }
}
"Button" を押した分だけ "Skyline" が追加されます。 しかし、Name の書き換えは動作しません。
これは INotifyPropertyChanged を実装するより仕方が無いようです。これは次回に。

2012年2月19日日曜日

[WP7] WebRequest で同期通信を行う

Windows Phone OS 7.1 では通信によって UI スレッドをブロックすることが無いよう、 同期通信を行うメソッドは使用を制限されています。
でも非同期通信はめんどくさいので、あまり使いたくありません。 今回は WebRequest (の GetResponse) を使いたかったのですが、 dotnet.dzone.com/news/adding-synchronous-methods では、 拡張メソッドを使って解決していました。
以下に元記事のコードを引用します。コメントは私が追記したものです。
    // クラス名は何でも良い。public static である必要がある
    public static class WebRequestExtensions
    {
        // これも public static である必要がある。仮引数は this に拡張したいクラスを続ける
        public static WebResponse GetResponse(this WebRequest request)
        {
            AutoResetEvent autoResetEvent = new AutoResetEvent(false);

            // BeginGetResponse で autoResetEvent を発火させる
            IAsyncResult asyncResult = request.BeginGetResponse(r => autoResetEvent.Set(), null);

            // autoResetEvent.Set() の発火を待つ。すなわちここでブロックする
            autoResetEvent.WaitOne();

            return request.EndGetResponse(asyncResult);
        }

        public static Stream GetRequestStream(this WebRequest request)
        {
            AutoResetEvent autoResetEvent = new AutoResetEvent(false);

            IAsyncResult asyncResult = request.BeginGetRequestStream(r => autoResetEvent.Set(), null);

            autoResetEvent.WaitOne();

            return request.EndGetRequestStream(asyncResult);
        }
    }
以下のようにして使います。
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            // 以下と等価
            // HttpWebResponse response = (HttpWebResponse)WebRequestExtensions.GetResponse(request);
C# を始めたばかりで拡張メソッドなんて知らなかったので、実を言うと最初は下のように使っていました:-) 継承を使わずに、既存のクラスにメソッドを追加することができるんですね。 継承による拡張だと新しいクラスを定義し、既存のコードでこれに置き換える必要がありますが、 拡張メソッドではその必要がありません。
ただ、拡張メソッドを参照している箇所から定義している箇所が見えにくいので、気をつけていないと後でハマリそう。
C#、面白い。

20120226: 一部修正