不満なのは
- UnitTestがやりづらい構造になっている
- twitterにべっとりの作りになっている
- パフォーマンスが悪い
あとは、単純に.net framework 4.0の機能をがんがん使ってみたかったり。
もちろん今の構造を徐々に修正していくのもありですが、
今ならまだ作り直した方がいいかなぁ、、と。
もちろん流用できるところはそのまま持ってくるので、
作り直しでも、そこまで今までのが無駄になるとは思っていません。
ブログの再開はあと1週間後くらいからかなぁ。。と。
public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); //オプションの読込 var option = Option.Instance; //アプリケーションの実行ファイルのフォルダ var baseUri = Directory.GetParent( System.Reflection.Assembly.GetExecutingAssembly().Location).FullName; //選択されたスキン名(=フォルダ名) //まだ機能追加していないのでデフォルト限定 var skinFolderName = "Default"; if (System.IO.Directory.Exists(string.Format(@"{0}\Skins\{1}", baseUri, option.Skin))) { skinFolderName = option.Skin; } //スキンの読込 ResourceDictionary rd = new ResourceDictionary(); foreach (DictionaryEntry entry in this.Resources) {//既存のリソースに追加するため rd[entry.Key] = entry.Value; } rd.MergedDictionaries.Add( Application.LoadComponent(new Uri("/Resources/CommonTemplates.xaml", UriKind.Relative)) as ResourceDictionary); //スキンフォルダの共通スキンを読込(Skinsフォルダ直下は共通) foreach (var file in Directory.GetFiles(string.Format(@"{0}\Skins", baseUri), @"*.xaml")) { var theme = XamlReader.Load(XmlReader.Create(file)) as ResourceDictionary; rd.MergedDictionaries.Add(theme); } //選択されたスキンの読込 foreach (var file in Directory.GetFiles( string.Format(@"{0}\Skins\{1}", baseUri, skinFolderName), @"*.xaml")) { var theme = XamlReader.Load(XmlReader.Create(file)) as ResourceDictionary; rd.MergedDictionaries.Add(theme); } this.Resources = rd;
<Style x:Key="WindowStyle" TargetType="{x:Type Window}"> <Setter Property="Template" Value="{DynamicResource WindowTemplate}"/> <Setter Property="WindowStyle" Value="None"/> <Setter Property="Background" Value="Transparent"/> <Setter Property="AllowsTransparency" Value="True"/> </Style>
<UserControl x:Class="WTwitter.View.Parts.TitlebarView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:root="clr-namespace:WTwitter" xmlns:util="clr-namespace:WTwitter.ViewModel.Utility"> <DockPanel Background="{DynamicResource TitlebarBackground}"> <!--左端のアプリのアイコン--> <Image Source="{DynamicResource AppImage}" Width="16" Height="16" DockPanel.Dock="Left"/> <!--閉じるボタン--> <Button DockPanel.Dock="Right" Command="{Binding Path=CloseCommand}" Foreground="White" Background="{DynamicResource CloseButtonBackground}" Margin="5,0,0,0" Width="25" Height="20" HorizontalContentAlignment="Center" VerticalContentAlignment="Center"> X</Button> <!--オプション画面を開くボタン--> <Button Command="{Binding Path=OptionDialogCommand}" DockPanel.Dock="Right" Style="{DynamicResource ImageButtonStyle}" Margin="3,1"> <Image Source="{DynamicResource SettingImage}" Height="16" Width="16"/> <Button.ToolTip>設定</Button.ToolTip> </Button> <!--TwitterのHOMEをブラウザで開くボタン--> <Button Command="{x:Static util:CommonCommands.OpenByBrowser}" CommandParameter="http://twitter.com" DockPanel.Dock="Right" Style="{DynamicResource ImageButtonStyle}" Margin="3,1"> <Image Source="{DynamicResource TwitterHomeImage}" Height="16" Width="16"/> <Button.ToolTip>TwitterHomeをブラウザで開く</Button.ToolTip> </Button> <!--タイトルバーのタイトルテキスト--> <TextBlock Text="{Binding Path=DisplayName}" Foreground="White" Margin="2"/> <!--右クリックメニュー--> <DockPanel.ContextMenu> <ContextMenu> <MenuItem Header="最前面に表示(_T)" IsCheckable="True" IsChecked="{Binding Source={x:Static root:App.Current}, Path=MainWindow.Topmost, Mode=TwoWay}"/> </ContextMenu> </DockPanel.ContextMenu> </DockPanel> </UserControl>
<ControlTemplate x:Key="WindowTemplate" TargetType="{x:Type Window}"> <DockPanel Background="Transparent"> <parts:TitlebarView DockPanel.Dock="Top"/> <ContentControl Content="{TemplateBinding Property=Content}" Background="Transparent"/> </DockPanel> </ControlTemplate>
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { DragMove(); }
<ResizeGrip HorizontalAlignment="Right" VerticalAlignment="Bottom" Width="3" Height="3" />
あとはMainWindowにResizeMode="CanResizeWithGrip"を設定しておいてください。<SolidColorBrush x:Key="HitVisibleTransparentBrush"> <SolidColorBrush.Color>White</SolidColorBrush.Color> <SolidColorBrush.Opacity>0.01</SolidColorBrush.Opacity> </SolidColorBrush> <SolidColorBrush x:Key="MouseOverBackgroundBrush"> <SolidColorBrush.Color>LightBlue</SolidColorBrush.Color> <SolidColorBrush.Opacity>0.5</SolidColorBrush.Opacity> </SolidColorBrush>
class Model : INotifyPropertyChanged { private bool _isOn; public bool IsOn { get { return _isOn; } set { if (_isOn != value) { _isOn = value; var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs("IsOn")); } } } } public event PropertyChangedEventHandler PropertyChanged; }
<Window x:Class="TriggerSample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TriggerSample" Title="MainWindow" Height="350" Width="525"> <!--3タイプのTriggerを使ってみたサンプル--> <Window.DataContext> <local:Model x:Name="data"/> </Window.DataContext> <StackPanel> <!--自分自身のプロパティに従って、他のプロパティを変更する--> <Border BorderBrush="Green" BorderThickness="2" Margin="5"> <TextBlock>Borderの上にマウスを置いたらBorderの色が変わる</TextBlock> <Border.Style> <Style TargetType="{x:Type Border}"> <Setter Property="Background" Value="Yellow"/> <Style.Triggers> <Trigger Property="IsMouseOver" Value="True"> <Setter Property="Background" Value="Red"/> </Trigger> </Style.Triggers> </Style> </Border.Style> </Border> <!--外のプロパティに従って内側のプロパティを変更する--> <Border Background="LightBlue" BorderBrush="Red" BorderThickness="3" Name="_outer"> <StackPanel Orientation="Horizontal"> <TextBlock>外側のBorderにマウスを置いたら内側のBorderの色が変わる</TextBlock> <Border BorderBrush="Black" BorderThickness="3" CornerRadius="3"> <TextBlock>内側のBorder</TextBlock> <Border.Style> <Style TargetType="{x:Type Border}"> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=_outer, Path=IsMouseOver}" Value="True"> <Setter Property="Background" Value="Blue"/> </DataTrigger> </Style.Triggers> </Style> </Border.Style> </Border> </StackPanel> </Border> <!--(Borderに関係ない)データの値に従ってプロパティを変更する--> <Border BorderBrush="Pink" BorderThickness="3" Margin="5" Name="border"> <TextBlock>データの値でBorderの色が変わる</TextBlock> <Border.Style> <Style TargetType="{x:Type Border}"> <Setter Property="Background" Value="Orange"/> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=data, Path=IsOn}" Value="True"> <Setter Property="Background" Value="DarkGray"/> </DataTrigger> </Style.Triggers> </Style> </Border.Style> </Border> <CheckBox IsChecked="{Binding ElementName=data, Path=IsOn, Mode=TwoWay}">ここを押してデータを変える</CheckBox> </StackPanel> </Window>
<Button>OK</Button>
namespace WTwitter.Tests.Model.Twitter { class TwitterItemTest { private static class TestDataFactory { public static Status CreateStatus() { return new Status() { Id = 100, Favorited = false, CreatedAtString = "Mon Jan 11 15:26:14 +0000 2010", Text = "おはようございます", InReplyToScreenName = "yuki", InReplyToStatusId = null, InReplyToUserId = null, Truncated = false, User = new User() { Id = 33, Following = false, Name = "yuki_", ScreenName = "yuki", Url = "http://wtwitter.codeplex.com/", ProfileImageUrl = "http://someimage", Description = "description for user", } }; } } [Test] public void TestConstructor() { var status = TestDataFactory.CreateStatus(); var target = new TwitterItem(status); Assert.AreEqual(100,target.Id); Assert.IsFalse(target.Favorited); var date = new DateTime(2010, 1, 11, 15, 26, 14, DateTimeKind.Utc); Assert.AreEqual(date.ToLocalTime(), target.CreatedAt, "CreatedAtはLocalTimeで持つ"); Assert.AreEqual(ItemType.TwitterStatus, target.Type); Assert.AreEqual("おはようございます", target.Text); Assert.AreEqual("yuki", target.User.ScreenName); Assert.AreEqual("yuki_", target.User.Name ); Assert.AreEqual("description for user", target.User.Description ); } [Test] public void TestEquality() { //EqualsはIdで判断する var status1 = TestDataFactory.CreateStatus(); var status2 = TestDataFactory.CreateStatus(); var status3 = TestDataFactory.CreateStatus(); status1.Id = 10; status2.Id = 10; status3.Id = 20; var item1 = new TwitterItem(status1); var item2 = new TwitterItem(status2); var item3 = new TwitterItem(status3); Assert.IsTrue(item1.Equals(item2)); Assert.IsFalse(item1.Equals(item3)); } [Test] public void TestTextComponent() { //細かい動作はSplitterクラスのテストで確認する var status1 = TestDataFactory.CreateStatus(); var item1 = new TwitterItem(status1); Assert.AreEqual(1, item1.TextComponents.Count); var status2 = TestDataFactory.CreateStatus(); status2.Text = "@yuki1090 てすと http://www.google.com てすと"; var item2 = new TwitterItem(status2); //※"@" "yuki1090" " てすと " "http://www.google.com" " てすと"に分かれる //IDに@は含まれないので注意 Assert.AreEqual(5, item2.TextComponents.Count); Assert.AreEqual(TextComponentType.Plain, item2.TextComponents[0].Type); Assert.AreEqual(TextComponentType.UserName, item2.TextComponents[1].Type); Assert.AreEqual(TextComponentType.Plain, item2.TextComponents[2].Type); Assert.AreEqual(TextComponentType.Url, item2.TextComponents[3].Type); Assert.AreEqual(TextComponentType.Plain, item2.TextComponents[4].Type); Assert.AreEqual("@", item2.TextComponents[0].Text); Assert.AreEqual("yuki1090", item2.TextComponents[1].Text); Assert.AreEqual(" てすと ", item2.TextComponents[2].Text); Assert.AreEqual("http://www.google.com", item2.TextComponents[3].Text); Assert.AreEqual(" てすと", item2.TextComponents[4].Text); } } }