C#でtumblrビューアを作ってみる

こんばんは、前回記事を書いてから留年したり色々ありましたが、やしへいは元気です。
さて、今回は先日部内で講座とかもしたのですが、C#によるアプリを作って見ようと思います。作るアプリは、最近部内の一部でtumblrが大流行してたりするのでアーカイブのビューアを作ってみよーって感じです。

それっぽいデザインにする

WinFormsでは多分フラットなデザインに出来ないんですけど、それでは悔しかったんでWPFにしました。ここを参考にelysiumを使ってフラットなデザインにしました。

WS000273

実装するのです!

実際ビューアを作るために何をすればいいのかというと、tumblrのAPIの説明がここに書いてあったりするのですが、GET投げたらJSONが返ってくるからそこから画像のURLを取得しては表示すればいいみたいな感じです。
それで、C#でJSONを処理する必要があるのですが、方法は幾つかあるみたいですが、今回はJSON.NETを使うことにしました。以下コードとか。

MainWindow.xaml.cs

JSON.NETでJSONをパースするためにAPIから返ってくるJSONを受け取るクラスを作ってたりしてたりします(後半のTumblrPostクラス)。一々手で書いてたらやってられないのでここでJSONを入力すると自動的にクラスを作ってくれるです。ちなみに画像の読み込みに致命的なバグがあるので分かったらgithubのIssueまで。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Net;
using System.IO;

using Newtonsoft.Json;
using WpfAnimatedGif;

namespace tumblrAppWPF
{
    public partial class MainWindow : Elysium.Controls.Window
    {
        string domain = "gazo0141.tumblr.com";
        string api_key = "GesVlVXWDOv1DKzVowf2jqsY8ndlgag0Uxy8HlLzN8AXAYd8FE";
        string url = "http://api.tumblr.com/v2/blog/";

        List<BitmapImage> images = new List<BitmapImage>();
        int index = 0;

        public MainWindow()
        {
            InitializeComponent();
            RequestNewImages();
            image1.Source = images[index];
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            index--;
            SlideImage();
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            index++;
            SlideImage();
        }

        private void SlideImage()
        {
            if (index < 0) index = 0;
            else if (index % 10 == 0) RequestNewImages();//FIXME:10枚毎に読み込む
            image1.Source = images[index];//画像をindexに対応するのに差し替える
        }
        
        private void RequestNewImages()
        {
            //apiに問い合わせ
            var req = WebRequest.Create(url + domain + "/posts/photo?api_key=" + api_key + "&offset=" + index + "&limit=10");
            var stream = req.GetResponse().GetResponseStream();

            using (var sr = new StreamReader(stream))
            {
                String json = sr.ReadToEnd();//jsonゲット
                var result = JsonConvert.DeserializeObject<TumblrPost>(json);//jsonをパース

                foreach (var post in result.response.posts)
                {
                    String imgUrl = post.photos[0].original_size.url;
                    var image = new BitmapImage(new Uri(imgUrl));
                    images.Add(image);
                }
            }
        }
    }
    
    //以下json受け取るテンプレクラス
    public class TumblrPost {
        public class Meta
        {
            public int status { get; set; }
            public string msg { get; set; }
        }

        public class Blog
        {
            public string title { get; set; }
            public string name { get; set; }
            public int posts { get; set; }
            public string url { get; set; }
            public int updated { get; set; }
            public string description { get; set; }
            public bool ask { get; set; }
            public string ask_page_title { get; set; }
            public bool ask_anon { get; set; }
            public bool is_nsfw { get; set; }
            public bool share_likes { get; set; }
            public int likes { get; set; }
        }

        public class AltSize
        {
            public int width { get; set; }
            public int height { get; set; }
            public string url { get; set; }
        }

        public class OriginalSize
        {
            public int width { get; set; }
            public int height { get; set; }
            public string url { get; set; }
        }

        public class Exif
        {
            public string Camera { get; set; }
            public int ISO { get; set; }
            public string Aperture { get; set; }
            public string Exposure { get; set; }
            public string FocalLength { get; set; }
        }

        public class Photo
        {
            public string caption { get; set; }
            public List<AltSize> alt_sizes { get; set; }
            public OriginalSize original_size { get; set; }
            public Exif exif { get; set; }
        }

        public class Post
        {
            public string blog_name { get; set; }
            public object id { get; set; }
            public string post_url { get; set; }
            public string slug { get; set; }
            public string type { get; set; }
            public string date { get; set; }
            public int timestamp { get; set; }
            public string state { get; set; }
            public string format { get; set; }
            public string reblog_key { get; set; }
            public List<object> tags { get; set; }
            public string short_url { get; set; }
            public List<object> highlighted { get; set; }
            public int note_count { get; set; }
            public string source_url { get; set; }
            public string source_title { get; set; }
            public string caption { get; set; }
            public string link_url { get; set; }
            public string image_permalink { get; set; }
            public List<Photo> photos { get; set; }
            public string photoset_layout { get; set; }
        }

        public class Response
        {
            public Blog blog { get; set; }
            public List<Post> posts { get; set; }
            public int total_posts { get; set; }
        }

        public Meta meta { get; set; }
        public Response response { get; set; }
    }
}

MainWindow.xaml

XAMLでボタンの配置などのレイアウトが出来るのですが、MarginやWidthとかCSS書いてる気分でレイアウトが出来ます。ボタンをHorizontalAlignmentとかで中央寄せしているのでウィンドウのサイズを変えてもボタンがそれに追従して配置されます。

WS000274

<metro:Window x:Class="tumblrAppWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:metro="http://schemas.codeplex.com/elysium"
        Title="TumblrViewer" Height="450" Width="680" KeyDown="Window_KeyDown">
    <Grid>
        <Image Name="image1" HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Top" UseLayoutRounding="False" />
        <Button Content="Save" HorizontalAlignment="Center" Margin="1,0,0,10" VerticalAlignment="Bottom" Width="75" RenderTransformOrigin="0.253,0.559" Click="Button_Click" Opacity="0.705"/>
        <Button Content="&gt;" HorizontalAlignment="Center" Margin="120,0,0,10" VerticalAlignment="Bottom" Width="30" MinWidth="0" Click="Button_Click_2" Opacity="0.7"/>
        <Button Content="&lt;" HorizontalAlignment="Center" Margin="0,0,120,10" VerticalAlignment="Bottom" Width="30" MinWidth="0" Click="Button_Click_1" Opacity="0.7"/>
    </Grid>
</metro:Window>

未実装なとことか

  • gif再生
  • 保存機能

githubにて開発中…。まだまだ未完成ですが実行ファイルも置いておきます。


コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください