WPF RichTextBox でハイパーリンクをクリックしたとき

WPFアプリケーションの中で、RichTextBox のHyperlink で、NavigationUri をセットしても、Clickイベントがキックされない。

RichTextBox のHyperlink は、NavigationWindow or Frame で navigation がサポートされているときだけ
http://social.msdn.microsoft.com/forums/en-US/wpf/thread/85171e54-7f98-425e-820d-46a17e19721e
という記事があるが、本当?

ということで、WPFアプリケーションの中で、RichTextBox のHyperlink をクリックしたときに、そのURLを開くには、MouseLeftButtonDown を使って、こんな感じ

<RichTextBox Height="100" Name="richTextBox1" Width="200" >
    <FlowDocument>
        <Paragraph>
            <Run>Paragraph 1</Run>
            <Run>Paragraph 2</Run>
            <Label >hello</Label>
            <Hyperlink NavigateUri="http://uchukamen.com"  MouseLeftButtonDown="Hyperlink_MouseLeftButtonDown"  >
                <Run>http://uchukamen.com</Run>
            </Hyperlink>
        </Paragraph>
    </FlowDocument>
</RichTextBox>

private void Hyperlink_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    System.Diagnostics.Process.Start(((Hyperlink)sender).NavigateUri.ToString());
}

=================

とするか、コードで書く場合は、

var fd = new FlowDocument();
this.RTB.Document = fd;

var p = new Paragraph();
p.Inlines.Add("ハイパーリング");

Hyperlink l = new Hyperlink();
l.Inlines.Add(http://uchukamen.com);
l.NavigateUri = new Uri("http://uchukamen.com");
l.MouseLeftButtonDown +=new MouseButtonEventHandler(l_MouseLeftButtonDown);

p.Inlines.Add(l);

fd.Blocks.Add(p);

——————————–

void l_MouseLeftButtonDown(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Process.Start(((Hyperlink)sender).NavigateUri.ToString());
}

ラベルをリサイズするユーザーコントロール

ちょっとしたテスト

<UserControl x:Class="WpfControlLibrary1.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
      <UserControl.Resources>
            <Storyboard x:Key="Storyboard1">
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(TextElement.FontSize)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="12"/>
                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="32"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(FrameworkElement.HorizontalAlignment)">
                <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static HorizontalAlignment.Center}"/>
                <DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static HorizontalAlignment.Center}"/>
            </ObjectAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(FrameworkElement.VerticalAlignment)">
                <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static VerticalAlignment.Center}"/>
                <DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static VerticalAlignment.Center}"/>
            </ObjectAnimationUsingKeyFrames>
            <ThicknessAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(FrameworkElement.Margin)">
                <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0"/>
                <SplineThicknessKeyFrame KeyTime="00:00:01" Value="0"/>
            </ThicknessAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="Storyboard2">
            <ThicknessAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(FrameworkElement.Margin)">
                <SplineThicknessKeyFrame KeyTime="00:00:00" Value="0"/>
                <SplineThicknessKeyFrame KeyTime="00:00:01" Value="0"/>
            </ThicknessAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(FrameworkElement.VerticalAlignment)">
                <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static VerticalAlignment.Stretch}"/>
                <DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static VerticalAlignment.Stretch}"/>
            </ObjectAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(TextElement.FontSize)">
                <SplineDoubleKeyFrame KeyTime="00:00:00" Value="32"/>
                <SplineDoubleKeyFrame KeyTime="00:00:01" Value="12"/>
            </DoubleAnimationUsingKeyFrames>
            <ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="label" Storyboard.TargetProperty="(FrameworkElement.HorizontalAlignment)">
                <DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static HorizontalAlignment.Center}"/>
                <DiscreteObjectKeyFrame KeyTime="00:00:01" Value="{x:Static HorizontalAlignment.Center}"/>
            </ObjectAnimationUsingKeyFrames>
        </Storyboard>

        </UserControl.Resources>
        <UserControl.Triggers>
            <EventTrigger RoutedEvent="Mouse.MouseEnter" SourceName="label">
                <BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
            </EventTrigger>
            <EventTrigger RoutedEvent="Mouse.MouseLeave" SourceName="label">
                <BeginStoryboard x:Name="Storyboard2_BeginStoryboard" Storyboard="{StaticResource Storyboard2}"/>
            </EventTrigger>
            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                <BeginStoryboard x:Name="Storyboard2_BeginStoryboard1" Storyboard="{StaticResource Storyboard2}"/>
            </EventTrigger>
        </UserControl.Triggers>

        <Label x:Name="label" HorizontalAlignment="Center" >Hello world</Label>
</UserControl>

———–

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;

namespace WpfControlLibrary1
{
    /// <summary>
    /// UserControl1.xaml の相互作用ロジック
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public UserControl1(string label)
        {
            InitializeComponent();
            this.label.Content = label;
        }
    }
}

—————

それをスタックパネルに入れる

foreach (var v in list)
{
    WpfControlLibrary1.UserControl1 userCont1 = new WpfControlLibrary1.UserControl1(v.Text);
    stackPanel1.Children.Add(userCont1);
}

WPF DisplayMemberBinding

<Window x:Class="WpfApplication3.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="Window1" Height="189" Width="459">
    <ListView>
        <ListView.View>
            <GridView>
                <GridViewColumn Width="120" Header="Date" />
                <GridViewColumn Width="120" Header="Day Of Week" DisplayMemberBinding="{Binding DayOfWeek}" />
                <GridViewColumn Width="120" Header="Year" DisplayMemberBinding="{Binding Year}" />
            </GridView>
        </ListView.View>
        <sys:DateTime>2001,1,1</sys:DateTime>
        <sys:DateTime>2010,1,1</sys:DateTime>
        <sys:DateTime>7/8/9</sys:DateTime>
        <sys:DateTime>10/11/12</sys:DateTime>
    </ListView>
</Window>

Date のところは、DisplayMemberBinding していないけど、表示されている・・・

image

WPF ListBox で DockPanel を使った例

DockPanel を使った例

複数選択の例だけど、http://msdn.microsoft.com/ja-jp/library/ms742885(VS.80).aspx

image

<Window x:Class="WpfApplication2.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="226" Width="292" >
    <Grid>
        <ListBox SelectionMode="Multiple">
            <DockPanel>
                <Image Source="data\cat.jpg" Width="100" Height="80" />
                <TextBlock>CAT</TextBlock>
            </DockPanel>
            <DockPanel>
                <Image Source="data\dog.jpg" Width="100" Height="80"/>
                <TextBlock>DOG</TextBlock>
            </DockPanel>
            <DockPanel>
                <Image Source="data\fish.jpg" Width="100" Height="80"/>
                <TextBlock>FISH</TextBlock>
            </DockPanel>
        </ListBox>
    </Grid>
</Window>

WPF ListBox のバインディング

わかりにくいなぁ・・・

MSDN ListView
http://msdn.microsoft.com/ja-jp/library/ms743602(VS.80).aspx

<Window x:Class="WpfApplication2.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:src="clr-namespace:WpfApplication1"               <<<<<< ここで、src = ネームスペース

    Title="Window1" Height="300" Width="300" >
    <Canvas>
        <Canvas.Resources>
            <ObjectDataProvider x:Key="Colors" ObjectType="{x:Type src:myColors}"/>    <<<< ここでタイプを指定
        </Canvas.Resources>
        <ListBox Name="myListBox" HorizontalAlignment="Left" SelectionMode="Extended"
      Width="265" Height="117"
      ItemsSource="{Binding Source={StaticResource Colors}}" IsSynchronizedWithCurrentItem="true">  
        </ListBox>
    </Canvas>
</Window>

/////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;

namespace WpfApplication1
{
    public class myColors : ObservableCollection<string>
    {
        public myColors()
        {
            Add("LightBlue");
            Add("Pink");
            Add("Red");
            Add("Purple");
            Add("Blue");
            Add("Green");
        }
    }
}

WPF で ListView にデータバインドしたデータソースをアップデートしても表示が自動更新できない

単にデータバインドしていて、データソースをアップデートしただけじゃ、表示は更新してくれないのね。

Queue<Info> queue = new Queue<Info>(200);

Binding myBinding = new Binding();
myBinding.Source = queue;
myBinding.NotifyOnSourceUpdated = true;  /// <<<
BindingOperations.SetBinding(listView1, ListView.ItemsSourceProperty, myBinding);

void DataReceived(object sender, EventArgs e)
{
    foreach (var v in (IList<Info>)sender)
    {
        queue.Enqueue(v);
    }
    listView1.Items.Refresh();  /// <<<<<<<<<<<<<<<< これが必要
}

プログラムソース(C#、VB.NET)をHTMLに変換するツール

zebratchの気まぐれ日記 の [.NET]プログラムコードの変換(C#、VB.NET→HTML)[Page1] に、C#, VB.NETをHTMLに変換してくれるツールが紹介されています。

数行で変換メソッドを呼び出して、きれいな C# HTMLソースコードを生成できる。 

パスワード Triple DES

twitter client を作って遊んでいたら、パスワードを保存する必要があり、昔のメモ(2004年!) を引っ張り出して実装した。すげー、備忘録役になっているなぁ・・・=>自分。

パスワードを暗号化してレジストリに保存する

http://uchukamen.com/Programming/EncryptDecrypt/index.htm

using System.Text;
using System.Security.Cryptography;
using System.IO;

namespace Security
{
    class Encription
    {
        /// PasswordEncoder はパスワードをTriple DESでエンコード、デコードします。

        /// keyStringから TripleDESCryptoServiceProvider のKey を生成します。
        /// 注意: この生成方法を変更するとデコードできなくなります。
        ///
        private static byte[] GenerateKey(string keyString, int len)
        {
            byte[] key = new byte[len];
            for (int i = 0; i < len; i++)
                key[i] = (byte)(keyString[i % keyString.Length] + i);
            return key;
        }

        /// keyStringから tripledescryptoserviceprovider のiv を生成します。
        /// 注意: この生成方法を変更するとデコードできなくなります。
        ///
        private static byte[] GenerateIV(string keyString, int len)
        {
            byte[] iv = new byte[len];
            for (int i = 0; i < len; i++)
                iv[i] = (byte)(keyString[i % keyString.Length] – i);

            return iv;
        }

        /// パスワード文字列 password をキー key でTriple DES暗号化を行います。
        ///
        public static byte[] Encrypt(string password, string key)
        {
            // Tripe DES のサービス プロバイダを生成します
            TripleDESCryptoServiceProvider tDes = new TripleDESCryptoServiceProvider();

            tDes.Key = GenerateKey(key, tDes.Key.Length);
            tDes.IV = GenerateKey(key, tDes.IV.Length);

            // 文字列を byte 配列に変換します
            byte[] source = Encoding.Unicode.GetBytes(password);

            // 入出力用のストリームを生成します
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms,
                tDes.CreateEncryptor(tDes.Key, tDes.IV), CryptoStreamMode.Write);

            // ストリームに暗号化するデータを書き込みます
            cs.Write(source, 0, source.Length);
            cs.Close();

            // 暗号化されたデータを byte 配列で取得します
            byte[] destination = ms.ToArray();
            ms.Close();

            return destination;
        }

        /// パスワード文字列 password をキー key でtriple des復号化を行います。
        ///
        public static string Decrypt(byte[] source, string key)
        {
            // Tripe DES のサービス プロバイダを生成します
            TripleDESCryptoServiceProvider tDes = new TripleDESCryptoServiceProvider();
            tDes.Key = GenerateKey(key, tDes.Key.Length);
            tDes.IV = GenerateKey(key, tDes.IV.Length);

            // 入出力用のストリームを生成します
            MemoryStream ms = new MemoryStream();
            CryptoStream cs = new CryptoStream(ms,
                tDes.CreateDecryptor(tDes.Key, tDes.IV), CryptoStreamMode.Write);

            // ストリームに暗号化されたデータを書き込みます
            cs.Write(source, 0, source.Length);
            cs.Close();

            // 復号化されたデータを byte 配列で取得します
            byte[] destination = ms.ToArray();
            ms.Close();

            // byte 配列を文字列に変換して表示します
            return Encoding.Unicode.GetString(destination);
        }
    }
}

DoubleAnimation の例

Opacity の変更

private void ChangeOpacity(Label label)
{  
    string name = "labelOpacity" + num++;
    this.RegisterName(name, label);

    label.RenderTransform = label.translateTransform;

    DoubleAnimation myDoubleAnimation = new DoubleAnimation();
    myDoubleAnimation.From = 1.0;
    myDoubleAnimation.To = 0.0;
    myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
    myDoubleAnimation.AutoReverse = true;
    myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;

    Storyboard.SetTargetName(myDoubleAnimation, name);
    Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Label.OpacityProperty));

    myStoryboard1.Children.Add(myDoubleAnimation);
}

フォントサイズの変更

private void ChangeFontSize(Label label)
{
    string name = "labelFontSize" + num++;
    this.RegisterName(name, label);

    label.RenderTransform = label.translateTransform;

    DoubleAnimation myDoubleAnimation = new DoubleAnimation();
    myDoubleAnimation.From = 12.0;
    myDoubleAnimation.To = 50.0;
    myDoubleAnimation.Duration = new Duration(TimeSpan.FromSeconds(5));
    myDoubleAnimation.AutoReverse = true;
    myDoubleAnimation.RepeatBehavior = RepeatBehavior.Forever;

    Storyboard.SetTargetName(myDoubleAnimation, name);
    Storyboard.SetTargetProperty(myDoubleAnimation, new PropertyPath(Label.FontSizeProperty));

    myStoryboard1.Children.Add(myDoubleAnimation);
}

Storyboard myStoryboard1 = new Storyboard();

         ChangeOpacity(label1);
         ChangeFontSize(label1);

         myStoryboard1.Begin(label1);

Storyboard で、textBoxの TranslateTransform を変更

SetTargetPropertyあたりのプログラミングで、どのように表記すればいいのかが分からず難しい。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace wpfsbtest1
{
    /// <summary>
    /// Window1.xaml の相互作用ロジック
    /// </summary>
    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            Play1();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            translateTransform1.BeginAnimation(TranslateTransform.XProperty, daukf);
        }

        Storyboard myStoryboard1 = new Storyboard();

        DoubleAnimationUsingKeyFrames daukf = new DoubleAnimationUsingKeyFrames();

        TranslateTransform translateTransform1 = new TranslateTransform();
        private void Play1()
        {
            textBox1.RenderTransform = translateTransform1;

            SplineDoubleKeyFrame sdkf1 = new SplineDoubleKeyFrame(0, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0)));
            SplineDoubleKeyFrame sdkf2 = new SplineDoubleKeyFrame(200, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 3)));

            daukf.BeginTime = new TimeSpan(0, 0, 0);
            daukf.Duration = new TimeSpan(0, 0, 3);
            daukf.KeyFrames.Add(sdkf1);
            daukf.KeyFrames.Add(sdkf2);

            Storyboard.SetTargetName(daukf, this.textBox1.Name);
            Storyboard.SetTargetProperty(daukf, new PropertyPath(TranslateTransform.XProperty));

            myStoryboard1.Children.Add(daukf);
        }
    }
}