2012年7月6日金曜日

[WPF][C#]ビットイメージ配列位置選択数値変換ユーザコントロール

タイトル長!

通信系のデータを扱う場合、こういうエディタがあると喜ばれるので、作ってみた。
絵でいうとこんなかんじ。


16個の四角枠のところがユーザコントロール。
ビットが立っているところが水色。
マウスオーバーはオレンジ。

ToggleButton で ON/OFF を表現している。

int <=> byte[4] <=> BitArray(16)

ToggleButton の IsChecked とBitArray[0] 〜 BitArray[15] がデータバインドしている。

ちょっと長くなるが、コードを一式貼付ける。





    /// <summary>
    /// ビット配列イメージ
    /// </summary>
    public partial class BitArraySelect : UserControl
    {
        /// <summary>
        /// データプロパティ
        /// </summary>
        public static readonly DependencyProperty DataProperty = DependencyProperty.Register("Data", typeof(int),
                                                                 typeof(BitArraySelect), 
                                                                 new FrameworkPropertyMetadata(0, new PropertyChangedCallback(OnDataChanged)));
        /// <summary>
        /// データを取得または設定する
        /// </summary>
        public int Data
        {
            get { return (int)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }
        /// <summary>
        /// データ変更イベント
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((BitArraySelect)d).Update();
        }
        /// <summary>
        /// ビット配列イメージ
        /// </summary>
        private BitImageWrapper bitArrayImage = new BitImageWrapper();
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public BitArraySelect()
        {
            InitializeComponent();
            this.DataContext = this.bitArrayImage;
            this.Loaded += (sender, e) => { Update(); };
        }
        /// <summary>
        /// トグルボタンクリック
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ToggleButton_Click(object sender, RoutedEventArgs e)
        {
            byte[] data = new byte[4];
            this.bitArrayImage.Data.CopyTo(data, 0);
            this.Data = BitConverter.ToInt32(data, 0);
        }
        /// <summary>
        /// 更新
        /// </summary>
        public void Update()
        {
            this.bitArrayImage.Data = new BitArray(BitConverter.GetBytes(this.Data));
        }
    }
    /// <summary>
    /// ビットイメージラッパー
    /// </summary>
    public class BitImageWrapper : INotifyPropertyChanged
    {
        /// <summary>
        /// ビット配列
        /// </summary>
        private BitArray data = new BitArray(16);
        /// <summary>
        /// ビット配列データを取得または設定します。
        /// </summary>
        public BitArray Data
        {
            get { return data; }
            set
            {
                data = value;
                OnPropertyChanged("Data");
            }
        }
        /// <summary>
        /// プロパティ変更イベントハンドラ
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;
        /// <summary>
        /// プロパティ変更処理
        /// </summary>
        /// <param name="name">プロパティ名</param>
        public void OnPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }





<UserControl x:Class="WpfValueBitImage.BitArraySelect"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:WpfValueBitImage"
             mc:Ignorable="d" 
             d:DesignHeight="60" d:DesignWidth="480" Width="480" Height="30">
    <UserControl.Resources>
        <LinearGradientBrush x:Key="PressedGradientBrush" 
            StartPoint="0.5,0" EndPoint="0.5,1">
            <GradientStop Color="White" Offset="0" />
            <GradientStop Color="LightBlue" Offset="1" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="MouseOverGradientBrush" 
            StartPoint="0.5,0" EndPoint="0.5,1">
            <GradientStop Color="White" Offset="0" />
            <GradientStop Color="#FFFFD452" Offset="1" />
        </LinearGradientBrush>
        <LinearGradientBrush x:Key="SelectedGradientBrush" 
            StartPoint="0.5,0" EndPoint="0.5,1">
            <GradientStop Color="#FFEBFAFF" Offset="0" />
            <GradientStop Color="#FFA2E0FB" Offset="1" />
        </LinearGradientBrush>
        <Style TargetType="{x:Type ToggleButton}">
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="Background" Value="White"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type ToggleButton}">
                        <Grid>
                            <Border BorderBrush="Gray" BorderThickness="0" CornerRadius="0"  Width="{TemplateBinding Property=Button.Width}" Height="{TemplateBinding Property=Button.Height}" Background="{TemplateBinding Property=Foreground}">
                                <Rectangle  Fill="{TemplateBinding Property=Background}"/>
                            </Border>
                            <TextBlock Text="{TemplateBinding ToggleButton.Content}" HorizontalAlignment="Center" VerticalAlignment="Center"  />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="IsPressed" Value="true">
                    <Setter Property="Foreground" Value="Red" />
                    <Setter Property="Background" Value="{StaticResource PressedGradientBrush}" />
                </Trigger>
                <Trigger Property="IsChecked" Value="true">
                    <Setter Property="Background" Value="{StaticResource SelectedGradientBrush}" />
                </Trigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsMouseOver" Value="True" />
                        <Condition Property="IsChecked" Value="False" />
                        <Condition Property="IsPressed" Value="False" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="{StaticResource MouseOverGradientBrush}" />
                </MultiTrigger>
            </Style.Triggers>
        </Style>
        <Style x:Key="BorderStyle" TargetType="{x:Type Border}">
            <Setter Property="Width" Value="30" />
            <Setter Property="Height" Value="30" />
            <Setter Property="BorderBrush" Value="Gray" />
            <Setter Property="BorderThickness" Value="1,1,0,1" />
        </Style>
    </UserControl.Resources>
    <Grid>
        <StackPanel Orientation="Horizontal">
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="F" IsChecked="{Binding Path=Data[15], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="E" IsChecked="{Binding Path=Data[14], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="D" IsChecked="{Binding Path=Data[13], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="C" IsChecked="{Binding Path=Data[12], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="B" IsChecked="{Binding Path=Data[11], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="A" IsChecked="{Binding Path=Data[10], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="9" IsChecked="{Binding Path=Data[9], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="8" IsChecked="{Binding Path=Data[8], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="7" IsChecked="{Binding Path=Data[7], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="6" IsChecked="{Binding Path=Data[6], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="5" IsChecked="{Binding Path=Data[5], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="4" IsChecked="{Binding Path=Data[4], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="3" IsChecked="{Binding Path=Data[3], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="2" IsChecked="{Binding Path=Data[2], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}">
                <ToggleButton Content="1" IsChecked="{Binding Path=Data[1], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
            <Border Style="{StaticResource BorderStyle}" BorderThickness="1">
                <ToggleButton Content="0" IsChecked="{Binding Path=Data[0], Mode=TwoWay}" Click="ToggleButton_Click"/>
            </Border>
        </StackPanel>
    </Grid>
</UserControl>







サンプルの画像は上部にあるテキストボックスの Text プロパティ とこのユーザコントロールの Data プロパティがバインディングで連結されている。



Data="{Binding Path=Text, Mode=TwoWay, ElementName=textBox}"












[C#][WPF]ColorPicker

色を ComboBox で選択するカスタムコントロールを作ってみた。
イメージはこんな感じ。




全部 C# で書いているが、ItemTemplate を xaml で書けば、Siliverlight でも使える。ただし、Siliverlight に Brushes が無いので Colors を使うことになると思うが。


    /// <summary>
    /// カラーピッカー
    /// </summary>
    public class ColorPicker : ComboBox
    {
        /// <summary>
        /// コンストラクタ
        /// </summary>
        public ColorPicker()
        {
            // テンプレート設定
            this.ItemTemplate = getItemTemplate();
            this.ItemsPanel = getItemsPanelTemplate();
            // Brushes からカラーのリストを生成
            List<Brush> list = (from brush in typeof(Brushes).GetProperties() select (Brush)brush.GetValue(null, null)).ToList();
            list.Sort(delegate(Brush source, Brush target) { return source.ToString().CompareTo(target.ToString()); });
            this.ItemsSource = list;
            this.Loaded += new RoutedEventHandler(ColorPicker_Loaded);
        }
        /// <summary>
        /// ロード完了イベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ColorPicker_Loaded(object sender, RoutedEventArgs e)
        {
            this.SelectedItem = Brushes.Black;
        }
        /// <summary>
        /// ItemTemplate取得
        /// </summary>
        /// <returns></returns>
        private DataTemplate getItemTemplate()
        {
            DataTemplate dataTemplate = new DataTemplate();
            FrameworkElementFactory element = new FrameworkElementFactory(typeof(Border));
            element.SetValue(Border.BorderBrushProperty, Brushes.Black);
            element.SetValue(Border.BorderThicknessProperty, new Thickness(1.0));
            element.SetValue(Border.VerticalAlignmentProperty, VerticalAlignment.Center);
            element.SetValue(Border.WidthProperty, 18.0);
            element.SetValue(Border.HeightProperty, 18.0);
            element.SetValue(Border.MarginProperty, new Thickness(0, 2, 0, 2));
            element.SetBinding(Border.BackgroundProperty, new Binding());
            dataTemplate.VisualTree = element;
            return dataTemplate;
        }
        /// <summary>
        /// ItemsPanelTemplate取得
        /// </summary>
        /// <returns></returns>
        private ItemsPanelTemplate getItemsPanelTemplate()
        {
            ItemsPanelTemplate panel = new ItemsPanelTemplate();
            FrameworkElementFactory element = new FrameworkElementFactory(typeof(WrapPanel));
            element.SetValue(WrapPanel.WidthProperty, 150.0);
            element.SetValue(WrapPanel.OrientationProperty, Orientation.Horizontal);
            panel.VisualTree = element;
            return panel;
        }
    }

2012年7月5日木曜日

Silverlight どうでしょう。


何から書き始めていいかわからんが、思いつくままに。


Windows 8 Windows 8 Release Preview 版が公開され、いよいよ今秋にリリースされる。Windows 8 からは新しい UI (ユーザインターフェース) として Metro UI が採用される。画面上に配置された大小様々でカラフルなパネルを選択すると、対象のアプリケーションがフルスクリーンで表示されるという感じ。見た目は新しくていいね。くるくるまわるやつと面白い。Release Preview 版を Mac の VMWare Fusion に入れて動かしたりしているが、操作についてはいつまでたっても慣れない。( Mac と比較するとかわいそうになる) タッチ操作を基本といいつつも Windows キーが押せないとかなり不便なのである。
結局、これまで通りのデスクトップで使うような気がする。ただ、ネットとかメールとか写真・音楽などのコンテンツのために使うのであれば、これはこれでいいのかもしれない。ターゲットが企業というよりは一般ユーザ用のように感じる。業務ではきっと使いづらいだろうて。


ブラウザは IE10。デスクトップ版とタッチ( Metro )版がある。びっくりしますわぁ。タッチ版はプラグインを入れられないときた。プラグインてのは Flash とかのブラウザ上で動くアプリケーションのこと。つまり、Microsoft がクロスプラットフォームでアプリケーションを動かすために開発したSiliverLight も動かせないっていうこと。HTML 5 で行け的な。プラグインを使わせないというのは不具合だったり電力問題だったり、どうしても apple の方針を彷彿させ、後追いか!と思ってしまうのだが、個人的にはもう一つ理由があるように思う。





それは性能面である。

タッチ版ということは、主にタブレット的なもので使うことになると思うのだろうが、スペックでいうとネットブック並みが想定される。WPF (Windows Presentation Foundation といい.NET Framework の4大技術の1つでプレゼンテーション部分の機能)の美しい描画とアニメーションは GPU を直接使っているからマシンパワーをそれほど使わなくても動くのであるが、GPU がショボイと CPU でカバーしようとする。GPU も CPU もそこそこのせいのであればまともに動くとは考えにくい。



先日、お客様にデモンストレーションするためのアプリケーションを作ってくれという依頼があった。要件はタッチパネルのデスクトップで、帳票的なものをタッチして選択したり手書きしたり云々。帳票とはいえ、入力項目がたくさんある。ので配置されるコントロールも多くなる。そこそこの性能の PC であれば十分動くのであるが、蓋をあけてみたら、今度、富士通から発売される Arrows のタブレット PC を使うというではないか。恐る恐る作ってみたアプリを入れてみたが、遅すぎて使い物にならん。手書きのほうが早い!ってお客さんに怒られちゃうレベル。じゃぁ、SiliverLightはどう?って作り変えてって言われちゃった。簡単にいうよなぁ。ちょちょいだけど。それで SilverLight で動かしてみたんだけど、まぁぎりぎりセーフっていうところ。


 #Arrows は Androidしかないが、そのうち Windows 版が出る。
 #決して Arrows が悪いと言っているわけではない。
 #使ってみた感じ、手書き入力とか超なめらかで慣れれば結構使えると思う。



ちょっとお勉強で Visual Studio 12 RT を入れて Metro UI のアプリ作ってみたりしてる。感触としてそのまま Silverlight で業務系アプリ作れるかっていうと疑問符がつく。



これが IE10 のタッチUI用にプラグインをのせない理由の1つではなかろうかと考えている。

2012年7月3日火曜日

[C#]SNMP Trap

今回は.NET でSNMP の Trap を検知する方法のご紹介。

System.Management 空間の WMI を使う。


1.参照設定にまずこれを追加する。
2.機能(WMI SNMP プロバイダ)を有効化する
[コントロールパネル] - [プログラムと機能] - [Windows の機能の有効化または無効化]
・簡易ネットワーク管理プロトコル(SNMP)
3.Windows のサービスを動かす。
[コントロールパネル] - [管理ツール] - [サービス]
・SNMP Service
・SNMP Trap
4.コーディング

using System.Management;
        /// <summary>
        /// イベントウォチャー
        /// </summary>
        private ManagementEventWatcher watcher = null;
        /// <summary>
        /// 監視開始
        /// </summary>
        public void Start()
        {
            ManagementPath path = new ManagementPath("\\\\.\\root\\snmp\\localhost:SNMP_RFC1213_MIB_system");
            ManagementScope scope = new ManagementScope(path);
            this.watcher = new ManagementEventWatcher(scope, new EventQuery("SELECT * FROM SnmpNotification"));
            this.watcher.EventArrived += this.trapRecieveEvent;
            this.watcher.Start();
        }
        /// <summary>
        /// 監視停止
        /// </summary>
        public void Stop()
        {
            this.watcher.EventArrived -= this.trapRecieveEvent;
            this.watcher.Stop();
            this.watcher.Dispose();
            this.watcher = null;
        }
        /// <summary>
        /// トラップ受信イベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void trapRecieveEvent(object sender, EventArrivedEventArgs e)
        {
            //---------------------------------------------------------
            // プロパティ取得
            //---------------------------------------------------------
            string agentAddress = e.NewEvent.Properties["AgentAddress"].Value.ToString();
            string agentTransportAddress = e.NewEvent.Properties["AgentTransportAddress"].Value.ToString();
            string agentTransrportProtocol = e.NewEvent.Properties["AgentTransportProtocol"].Value.ToString();
            string community = e.NewEvent.Properties["Community"].Value.ToString();
            string identification = e.NewEvent.Properties["Identification"].Value.ToString();
            if (e.NewEvent.Properties["VarBindList"] != null)
            {
                ManagementBaseObject[] variableBindingArray = (ManagementBaseObject[])e.NewEvent.Properties["VarBindList"].Value;
                List<VariableBinding> variableBindings = new List<VariableBinding>();
                foreach (var mib in variableBindingArray)
                {
                    try
                    {
                        variableBindings.Add(new VariableBinding()
                        {
                            Oid = (string)mib.Properties["ObjectIdentifier"].Value,
                            Encoding = (string)mib.Properties["Encoding"].Value,
                            Value = (byte[])mib.Properties["Value"].Value
                        });
                    }
                    catch
                    {
                    }
                }
                // イベントを発生させるなり連動処理云々…
            }
        }

※異常系は省略


【2012.07.24追記】
書き忘れがあったので追記する。


    public class VariableBinding
    {
        /// <summary>
        /// オブジェクト識別子
        /// </summary>
        public string Oid { get; set; }
        /// <summary>
        /// エンコード情報
        /// </summary>
        public string Encoding { get; set; }
        /// <summary>
        /// データ
        /// </summary>
        public byte[] Value { get; set; }
    }





2012年7月1日日曜日

USB LANアダプター購入

支給されているPCのスペックがしょぼすぎて使い物にならないので、開発用マシンを自分で用意することになった。

VAIO とかなり迷ったが、10数年来の Mac ユーザということもあり、Mac Book Air + VMware Fusion + Windows 7 + Visual Studio (+ Expression) とスタイルを採ることとした。使い始めて2ヶ月弱になるが、マジですげー使いやすいわぁ。(6月に新しいのが出るのを知ってたのに買ってやったぜ〜、ワイルドだろ〜)

ショートカットも VM 君が割とうまく割り当ててくれるので、キー操作でそれほど困ることも無い。

解像度(1440 × 900)についてはフルハイ(1920 × 1080)で画面を作ることが多く、最悪デュアルディスプレイでなんとかするか〜ぐらいで思っていたが、VM 君がホンと優秀で若干のピンぼけはするが、↓ここまで自由に変えることが出来るのである!!!


まぁ書き始めるとキリがないので本題。

明日から工場にて品証さんによる工場試験が始まる。問題はいろいろと結合して試験する訳だが、Mac Book Air には有線 LAN ポートがないのでネットワークに接続出来ないことである。

なので、amazon でポチとやってしまいました。

BUFFALO USB2.0 LAN アダプター LUA3-U2-ATX ¥1,264

ついでに安かったのでこっちも。

 iBUFFALO 【PS3動作確認済】USB       ¥ 518

なんせ USB ポート2つしかないからねぇ。内1つを占有されると不安でドキドキするのである。予備が無いと落ち着かない性格で、シャンプーも予備がないと嫁さんをなじる小さい男なのだ・・・話はそれたが、さっそく接続してみた。



「Mac Book Air に挿すだけで使える」と謳ってることだけのことはある。
さて、気になっているのが VM 上の Windows がつながるかどうか。

とりあえず 「仮想マシン」 - 「USB と Bluetooth」でアダプターを接続してみる。



も、ドライバーがわかんねぇ〜っていうエラーが出た。
Windows は簡単設定ツールでドライバーを入れなければいけないのね。


と思ったが、いやいや、ネットワークはMacと共有してるんだから、そんなことしなくてもつながるんじゃない・・・つながった。ちゃんちゃん。



2012年2月2日木曜日

ふわふわ

いつから作業開始かはっきりしないまま2月に突入したんだけど、今日は午後(と言ってもほぼ夕方だけど)からお客様のところで契約等についての打ち合わせがあり、なんとなく流れで明日からお客様のところに行く事になった。

とはいえ、担当の方もまさかすんなり明日からになるとは思ってなかったみたいで、PCどうする?入館証は?云々もやもやしたところが沢山あり、明日から作業が開始出来るのかは全くわからない。

始まったのか始まってないのかよくわからん地に足がついていないふわふわした感じがここ数ヶ月続いている。


打ち合わせ終了後、そのまま担当者の方にお願いされ、前に携わっていたプロジェクトで発生している障害を見る事になった。(携わっていたとはいえ、別の人間が作ったところで全く困ったものである)


その後、担当者の方が歓迎会ということで居酒屋さんへ行く事に。終電まであれやこれや話し込んで、色々とごちそうしてくれた。この方には足を向けて寝る事は出来ないくらいの大恩がある。ぼろぞうきんのように使ってもらおう(笑)