2013年7月1日月曜日

[Sivlerlight][C#]テンプレートのコントロール取得

カスタムコントロールに限るけど、そのコントロールに割り当てられた Style で設定された ControlTemplate 内にあるコントロールを取得するには。

GetTemplateChild というメソッドに Template 内で定義したコントロールに割り当てられている Name を渡してあげると取得出来る。

ただし、Loaded の時点ではまだテンプレートが適用されていないので、OnApplyTemplate の処理後に GetTemplateChild を Call すると取得出来るようになる。




Visual Studio Image Library

ここからダウンロード出来るんだね。

http://www.microsoft.com/en-us/download/confirmation.aspx?id=35825



Silverlight 終了のお知らせ

現時点(2013/7/1)で、Silverlight 5 のデザイナツールは存在しない、、、という話。

Silverlight 5 のデザイナツールとして、「Expression Blend for Silverlight 5」がマイクロソフトから提供されていた。Preview版とはいえ、正式に使えるものだったのだが、使用期限が6/30までで、本日からは使えない。開いてみたら案の定、次のを買えっていうメッセージとともに終了した。

以前、調べた時に、Visual Studio 2012 には Blend が付属するけど Windows ストアアプリ限定だということで、しょうがなく Preview 版を採用したのだけれども、今、調べてみたら春頃にリリースされた VS2012 の Update2 というのを適応することで、WPF4.5/Silverlight5がBlend for Visual Studio で使えるようになったとある。ちなみに今は Update3 までリリースされている。

試しに、Web 用 Visual Studio Express 2012 を入れてみて、既存のプロジェクトを表示してみた。デザイナの UI は2010とは異なり、かなり Blend に近いものになっている。複雑なアニメーションなどがなく、配置程度であればこれで十分だ。しかし、、、画像関係が一切表示されない。どうも、ResourceDictionary に登録した BitmapImage を参照しているところが全部ダメのようだ。ちなみに Express 版には Blend for Visual Studio が含まれない。

さて、製品版の Professional を入れてみた。結果は同じだった。
Update 3を適用し、Blend for Visual Studio で開く。おぉ、UI は Expression Blend 4 とほぼ変わらない。が、こちらも同様に画像が表示されない。

WPF で同じコードを書いてみたら表示されたので、Sivlerlight のときだけダメっぽい。VS2010だと編集はしょぼいけど、表示は出来る。不具合なんだろうけど、、、結構困る。これからデザイナーの方に数百枚のXAMLを書いてもらわなければいけないのに、肝心のデザイナツールが存在しないのだから。手を止めてもらっている。。。

とりあえず  Visual Studio のフォーラムで質問したり、バグ報告を投げてみたりした。サポートに問い合わせたいのだけど、イマイチ問い合わせフォームに辿り着けない。。。

Windows 8 とか Silverlight とか、失策多くないっすか?>Microsoftさん



[Symfoware]遅延

Windows から Symfoware サーバに接続するにあたり、Symfoware クライアントとして、Symfoware .NET Data Provider を使っている。

サーバー側が複数あり、ほとんどが接続出来ない状態だと、接続出来るところが遅延する現象が発生した。

テストプロを作って調査したところ、接続待ちの処理があった場合、別スレッドで接続出来るところへ接続を試みると、待たされているようだ。マルチスレッドに対応していないのか?

試しにODBCで接続してみると、全く遅延せずに接続出来てしまった。

完全に SNDP の不具合だな。


[WPF]デザイナエラー


突然、Visual Studio の XAML のデザイナを開くと描画されなくて、下記エラーが出るようになった。

エラー 1 CLR 名前空間が定義されていません。'clr-namespace' URI が、アセンブリに含まれていない名前空間 'XXXXX' を参照しています。

なんか変えちゃったかな―。
プロジェクトのプロパティを見ると、プラットフォームが「Any CPU」から「x86」に変わっていて、選択項目に「Any CPU」が表示されない。
どうもこれが原因ぽい。

・ソリューションのプロパティを開き、構成プロパティ選択->構成マネージャを開く。
・対象のプロジェクトをのプラットフォームを新規作成にして、Any CPUを選ぶ。
 ⇒ふつうここで行けるっぽいけど、私の環境では
 「同じ名前のプラットフォームが既に存在するため、このプラットフォームを作成できませんでした。」
 と表示されたので、「x64」を新規作成した。
・プロジェクトのプロパティを開いて、プラットフォームを Any CPU(もしくはx64)、プラットフォームターゲットを「Any CPU」に変更。

したら表示されるようになった。

なんだったんだろーか。なんかプロジェクトが壊れている気がするけど、とりあえずなおったので放置。(問題の先送り)

Windows 7 の同時接続数


XPでは同時に接続できる数が10に制限されていたが、Vista/2008Serverからは無制限になった。

■Notable Changes in Windows Server 2008 SP2 and Windows Vista SP2
http://technet.microsoft.com/en-us/library/dd335036%28WS.10%29.aspx?ppud=4

「SP2 removes the limit of 10 half open outbound TCP connections. By default, SP2 has no limit on the number of half open outbound TCP connections.」

Windows 7 の情報がないけど、多分そうなんだろうね。
試してみないと。

2013年5月19日日曜日

VMWARE FUSION 5

MBA上の Windows7は VMWARE FUSION 4で動いてるんだけど、RHELの6が動かんのでそのうち買おうと思ってた5が、act2で買うと4900円だけど amazonで3800円くらいだったからポチっと。


大体2日くらいで届く。早いねー。


インストーラはCDだけど、USBも付いててそれでインストール出来る。
ドライブがないMBAには実にありがたい。

製品登録してて気づいたけど、Act2にユーザ登録してたらもしかしたら無償でアップグレード出来たかも。まあいいか。いい製品への投資と考えて。

2013年5月11日土曜日

[Silverlight]CSV出力

Silverlight で CSV データを保存しよう。
たぶん、やり方は2つ。



Silverlight アプリケーションでデータを生成し、ローカル保存するのが1つ目。


    string csvData = "";

    // カンマ区切りの文字列を csvData に設定


    SaveFileDialog dialog = new SaveFileDialog();
    dialog.DefaultExt = ".csv";
    dialog.Filter = "データ | *.csv";
    dialog.DefaultFileName = DateTime.Now.ToString("yyyyMMddHHmmss") + ".csv";
    if (dialog.ShowDialog() == true)
    {
        using (var stream = dialog.OpenFile())
        {
            using (var writer = new StreamWriter(stream, Encoding.UTF8))
            {
                writer.Write(csvData);
                writer.Flush();
            }
        }
    }



CSVファイルの文字コードは shift-jis じゃないと Excel で開いたときに文字化けしてしまう。普通にファイル出力してしまうと、UTF-8 で出力される。とはいえ、Silverlight には標準で shift-jis にサクッと変換するすべは無い。だが、Excel も UTF-8 をサポートしているはずなので、調べてみたところ BOM(Byte Order Mark) が付与されているものであれば、UTF-8 でも開けるとのこと。

BOM を付与するには、StreamWriter の第二パラメータにちゃんと UTF8 ですよってつけてあげればおk。

DefaultFileName を未設定だと、保存ダイアログのファイル名のところが空になってしまい、設定しちゃうと、保存ダイアログ表示前に勝手に確認ダイアログが出るのが気に入らない。
UTF-8 じゃなくて shift-jis で出したい場合は、ちょっと手間だけど次の方法。



サーバーサイドで作ってダウンロードさせる。これが2つ目。

aspx 作って POST で返すのもいいけど、今回はジェネリックハンドラを使う。
まずはサーバーサイド。



    /// <summary>
    /// CsvDownload の概要の説明
    /// </summary>
    public class CsvDownload : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            string csvData = "";

            // カンマ区切りの文字列を csvData に設定

            context.Response.ContentType = "text/csv";
            context.Response.AddHeader("Content-Disposition", "attachment;filename=" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".csv");
            context.Response.ContentEncoding = System.Text.Encoding.GetEncoding("shift-jis");
            context.Response.Write(csvData);
        }

        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }



これで、CsvDownload.ashx をクライアント側から呼び出すだけでおk。

呼び出し方はいくつかあって、Silverlight アプリケーションから直接呼び出す場合は、WebClient クラスを使ってバイトデータを読み出したあとに、1つ目と同じ方法で保存する。

javascript 側からリクエストする方法もいくつかある。
流れはjsにリクエストさせる為のメソッドを用意して、Silverlight側からCALLする。


☆js側

    <script type="text/javascript">
        function getCsv() {
        }
    </script>


☆SL側

            HtmlPage.Window.Invoke("getCsv");






getCsv の中でHTTPリクエストをやるんだけど、まずは一番かっちょわるいやりかた。
新規Window作ってそこからリクエストする。


            var w = window.open("CsvDownload.ashx", "csv", "width=1,height=1", null);
            w.onload = function () {
                w.close();
            };
            self.focus();

Windowが見えるのはやだよね。
これを回避する為には隠しiframeを使う。

            var iframe = document.createElement("iframe");
            if (iframe != null) {
                iframe.style.display = "none";
                iframe.onload = function () {
                    document.body.removeChild(iframe);
                }
                document.body.appendChild(iframe);
                iframe.src = "CsvDownload.ashx";
            }


ほかにも jQuery の ajax 使うのとか色々ありそうだけど、キリが無いので今日はここまで。

2013年3月22日金曜日

[Silverlight]XAMLにデータをXMLとして記述する

XML スキーマに合わせてカスタムコントロールを用意すればある程度出来るが、つまづいたのは List<T> 型。XAML からの定義がうまくいかなかったりする。回避するには List<T> を継承したクラスでワンクッション置く必要がある。

以下に数値キーに対するイメージのカスタムコントロールを記述する。


    public class SampleContentControl : ContentControl
    {
        public ImageList ImageList
        {
            get { return (ImageList)GetValue(ImageListProperty); }
            set { SetValue(ImageListProperty, value); }
        }

        public static readonly DependencyProperty ImageListProperty =
            DependencyProperty.Register("ImageList", typeof(ImageList), typeof(SampleContentControl), new PropertyMetadata(new ImageList()));
    }

    public class ImageList : List<ImageInfo>
    {
    }

    public class ImageInfo
    {
        public int Key { get; set; }
        public ImageSource Value { get; set; }
    }




XAML 側の定義はこうなる。(ResourceDicitonary内ね)


    <local:ImageList x:Key="imageList">
        <local:ImageInfo Key="1" Value="{StaticResource aaa}"/>
        <local:ImageInfo Key="2" Value="{StaticResource bbb}"/>
        <local:ImageInfo Key="3" Value="{StaticResource ccc}"/>
    </local:ImageList>




[C#]画像の印刷ダイアログをプロセス起動する

Windows 7 の場合、画像ファイルを指定してプロセス起動すると、Windows フォトビューアーが起動する(はず)。


            Process.Start(@"D:\penguins.jpg");


でも出したいのは印刷プレビュー画面。画像ファイルを右クリック->印刷で選んだ時のダイアログ。こんなやつ。



レジストリとか色々調べてしまったが(それはそれで勉強になった)、プロセス起動時にVerbプロパティに print を指定してあげるといい。

            ProcessStartInfo info = new ProcessStartInfo(@"D:\penguins.jpg");
            info.Verb = "print";
            Process.Start(info);


Windows フォトビューアーをコマンド起動


%SystemRoot%\System32\rundll32.exe "%ProgramFiles%\Windows Photo Viewer\PhotoViewer.dll", ImageView_Fullscreen 画像ファイル名






[WPF]Listアイテムのコンテキストメニューのコマンドバインディング(MVVM)

DataGrid でも ListView でも ListBox でも当てはまると思うけど、行を右クリックしてViewModel に記述されたコマンドをキックするにはちょっとコツが必要。

普通にバインドさせると、ListItem の ViewModel にバインドしようとしてしまうからみたい。

わかってしまえば簡単。
Windowまで遡れば、DataContext に ViewModel が入ってるんで、コマンドまで辿れる。


    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>


            <ContextMenu x:Key="execMenu">
                <MenuItem Header="実行"  Command="{Binding Path=DataContext.ExecuteCommand, 
                                                                             RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/>
            </ContextMenu>

[Silverlight]ResourceDictionary 分離

ResourceDictionary を複数ファイルに分割して、片方のリソースから片方のリソースへの参照があると、XamlParseException が発生して起動出来ない。

-----------------
XamlParseException
Name/Key XXXXXX を持つ Resource が見つかりません [Line: XX Position: XX]

-----------------


Expression Blend Preview For Silverlight 5 だからなのかもしれないが、App.xaml の MergedDictionaries 内で複数のリソースファイルをロードしようとした時に別リソースファイルへの参照があるとダメそう。イメージファイルの定義が1ファイルに纏めたいんだけど。。。

対処としては、App.xaml 内で定義している ResourceDictionary をコードビハインドでロードさせる。


        private void loadResource(Uri uri)
        {
            var info = Application.GetResourceStream(uri);
            string xaml;
            using (var reader = new StreamReader(info.Stream))
            {
                xaml = reader.ReadToEnd();
            }

            ResourceDictionary result = (ResourceDictionary)XamlReader.Load(xaml);
            foreach (DictionaryEntry item in result)
            {
                
                try
                {
                    Application.Current.Resources.Add(item.Key, item.Value);
                }
                catch (Exception ex)
                {
                }
            }
        }




実行時はそれでいんだけど、デザイナで表示出来ないのもなんとかならんか。調べてみると、DesignTimeResources.xaml というものがあり、Blend 起動時に参照が切れているリソースがあると、自動生成してくれる。(Properties ディレクトリ配下出来る)

これでもダメな場合、複数の ResourceDictionary ファイルを1ファイル内でロードするようにしたものをDesignTimeResources.xamlに書くとよい。

それでもダメな場合、一度ビルドして Blend ないし VisualStudio を終了させ、起動させると表示されることがある。

定義の仕方が悪いのかもしれないが、なんともすっきりしないやり方だ〜。

[jQuery]iframeのスムーズな切換え

最近ではあまり使われなくなっている Frame 関係だけど、業務アプリケーションではまだまだ使っていることも多い。

iframe のコンテンツを切り替える際に iframe 内が真っ白になってしまう。
切換え先のページのロードが重たければ、白い画面がしばらく表示されることになるのだが、なんとかならんか〜と考えてみた。

結論から言うと、iframe  を div タグ内に入れて、div タグをフェードイン/フェードアウトさせればフワフワっとページを切り替えることが出来る。

フェードインは iframe の loaded イベントで行う。


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript" language="javascript" src="jquery-1.9.0.min.js"></script>
    <script type="text/javascript" language="javascript">
var index = 0;
var pages = new Array("aaaa.html", "bbbb.html");
function frameChange(){
    $('#contents').animate({ opacity: 0 }, 500, function () {
        $('#contents').css("visibility", "hidden");
        main.location.href = pages[index];
        index++;
        index = index % 2;
    });
}
function loaded(){
    $('#contents').css("visibility", "visible");
    $('#contents').animate({ opacity: '1' }, 800, function () {

    });
}
    </script>
</head>
<body style="background-color:Black;">
<input type="button" value="切替" onclick="frameChange()">
    <div id="contents">
        <iframe name="main" id="main" scrolling="no" onload="loaded();"/>
    </div>
</body>
</html>


[jQuery]アコーディオンメニュー

dtタグを使ってメニューを作成し、サブメニューは sideToggle によるアニメーションでのの表示/非表示を切り替えることでアコーディオン風のメニューが出来上がる。


<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript" language="javascript" src="jquery-1.9.0.min.js"></script>
    <script type="text/javascript" language="javascript">
$(document).ready(function(){
    $('dd').css("display", "none");
    $("dt").click(function () {
        if ($(this).next().children(0).children().length != 0) {
            $(this).next().slideToggle("slow");
        }
        return false;
    });
});
    </script>
</head>
<body>
<dt>メニュー1</dt>
<dd>
<ul>
<li>サブメニュー1</li>
<li>サブメニュー2</li>
<li>サブメニュー3</li>
</ul>
</dd>
<dt>メニュー2</dt>
<dd>
<ul>
<li>サブメニュー1</li>
<li>サブメニュー2</li>
<li>サブメニュー3</li>
</ul>
</dd>
</body>
</html>



[C#]FlagBooleanConverter

DBはBoolean型がなくて、0か1で意味を持たせることが多々あるんで、直接 bool 型として扱えるよう、Converter を作った。スニペット的に貼付けておく。


    public class FlagBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int param;
            if (!int.TryParse(value.ToString(), out param))
            {
                return DependencyProperty.UnsetValue;
            }

            return param.Equals(1);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            bool param;
            if (!bool.TryParse(value.ToString(), out param))
            {
                return DependencyProperty.UnsetValue;
            }
            
            return param ? 1 : 0;
        }
    }


[Silverlight]トグルスイッチボタン

ON/OFFボタンを作ってみた。
イメージはこんな感じ。


クリックすると黒い境界が動いてON<->OFFが切り替わる。

Template内にサイズを持たせているので微妙なんだけどねぇ。
XAMLを貼付けておく。


<ControlTemplate x:Key="ToggleSwitchControlTemplate" TargetType="ToggleButton">
<Grid Height="22">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CheckStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.2" To="Checked"/>
<VisualTransition GeneratedDuration="0:0:0.2" To="Unchecked"/>
</VisualStateGroup.Transitions>
<VisualState x:Name="Checked"/>
<VisualState x:Name="Unchecked">
<Storyboard>
<DoubleAnimation Duration="0:0:0.2" To="-45" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="grid" d:IsOptimized="True">
                                <DoubleAnimation.EasingFunction>
                                    <CircleEase EasingMode="EaseIn"/>
                                </DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</VisualState>
<VisualState x:Name="Indeterminate"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Canvas>
<Canvas.Clip>
<RectangleGeometry Rect="0,0,55,22" />
</Canvas.Clip>
<Grid x:Name="grid" Height="22" Width="100" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<CompositeTransform TranslateX="0"/>
</Grid.RenderTransform>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="45"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="45"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="White" BorderThickness="2,2,0,2" BorderBrush="Gray">
<Border Margin="2,2,0,2" Background="#FF41B1E1">
<TextBlock Text="ON" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" Foreground="White"/>
</Border>
</Border>
<Border Grid.Column="1" Background="Black"/>
<Border Grid.Column="2" Background="White"  BorderThickness="0,2,2,2" BorderBrush="Gray">
<Border Margin="0,2,2,2" Background="Gray">
<TextBlock Text="OFF" HorizontalAlignment="Center" VerticalAlignment="Center" FontWeight="Bold" Foreground="White"/>
</Border>
</Border>
</Grid>
</Canvas>
</Grid>
</ControlTemplate>