ScreenToGif項目由四個文件夾組成:
- Files 存放協議文件
- GifRecorder 存放gif編碼器代碼
- ScreenToGif 存放主代碼
- Other 存放Hooktest和Translator的代碼
問題1:GifRecorder 和ScreenToGif、Hooktest、Translator 下面都有了一個Properties,里面有個AssemblyInfo.cs是什么東西?
.net工程的Properties文件夾下自動生成一個名為AssemblyInfo.cs的文件,一般情況下我們很少直接改動該文件。但我們實際上通過另一個形式操作該文件。那就是通過在鼠標右鍵點擊項目的屬性進入“應用程序”->“程序集信息”,然后修改信息。
程序集指的是DLL或者EXE等可執行文件。
問題2:啟動界面分析
<Window x:Class="ScreenToGif.Windows.Other.Startup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:n="clr-namespace:ScreenToGif.Controls"
xmlns:u="clr-namespace:ScreenToGif.Util"
Title="{DynamicResource Title.StartUp}" Height="220" Width="500" Icon="/Resources/Logo.ico" WindowStartupLocation="CenterScreen"
MinWidth="500" MinHeight="220" UseLayoutRounding="True" Loaded="Startup_OnLoaded">
<Window.CommandBindings>
<CommandBinding Command="u:Commands.NewRecording" CanExecute="Buttons_CanExecute" Executed="Recorder_Executed"/>
<CommandBinding Command="u:Commands.NewWebcamRecording" CanExecute="Buttons_CanExecute" Executed="WebcamRecorder_Executed"/>
<CommandBinding Command="u:Commands.NewBoardRecording" CanExecute="Buttons_CanExecute" Executed="Board_Executed"/>
<CommandBinding Command="u:Commands.Editor" CanExecute="Buttons_CanExecute" Executed="Editor_Executed"/>
<CommandBinding Command="u:Commands.Update" CanExecute="Update_CanExecute" Executed="Update_Executed"/>
<CommandBinding Command="u:Commands.Options" CanExecute="Buttons_CanExecute" Executed="Options_Executed"/>
<!--Command后面是命令的名字,實際執行的函數是executed里寫的函數 其他控件必須指明command這個屬性
應用場景是菜單欄和工具欄的功能相同,我們要將其映射到同一個command。還有就是一個控件禁用后,相同功能的控件也要一起被禁用,這有CanExecute 來幫助同步,同時可用,或者同時不可用->
</Window.CommandBindings>
<Grid>
<Grid.RowDefinitions> <!--行定義-->
<RowDefinition Height="45"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0">
<Grid.ColumnDefinitions> <!--列定義-->
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="ScreenToGif" Margin="5" FontSize="18" Foreground="#FF251E46" Effect="{DynamicResource Shadow.Black.Small}"/>
<!--<n:ImageButton Grid.Column="1" x:Name="BoardButton2" Text="Test" Content="{StaticResource Vector.Info}"
Margin="5" Style="{StaticResource Style.Button.Horizontal}" Effect="{StaticResource Shadow.Foreground.Small}"
Padding="3" MaxSize="25" Click="TestButton_OnClick" Visibility="Collapsed"/>-->
<TextBlock Grid.Column="1" Name="UpdateTextBlock" VerticalAlignment="Center" Visibility="Hidden" Effect="{StaticResource Shadow.Black.Small}">
<!--WPF Visibility的用法 Visible 元素在窗體中正常顯示 Collaspsed 元素不顯示,也不占用空間 Hidden 元素不顯示,但是任然為它保留空間 -->
<Hyperlink Command="u:Commands.Update" ToolTip="{DynamicResource NewRelease.Tooltip}" Cursor="Hand">
<Run Name="UpdateRun" Text="{DynamicResource NewRelease}"/>
<!--run指明一連串格式化的或者格式化的內聯文本,類似html的<span>-->
</Hyperlink>
</TextBlock>
<n:ImageButton Grid.Column="3" x:Name="OptionsButton" Text="{DynamicResource Options}" Content="{StaticResource Vector.Options}"
Margin="5" Style="{StaticResource Style.Button.Horizontal}" Effect="{StaticResource Shadow.Black.Small}"
Padding="2" MaxSize="25" Command="u:Commands.Options"/>
<!--Effect是簡單的像素處理 content屬性顯示圖片 text 顯示文本-->
</Grid>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<n:ImageButton Grid.Column="0" x:Name="RecordButton" Text="{DynamicResource Recorder}" Margin="5,0,5,5"
Effect="{StaticResource Shadow.Black.Tiny}" MaxSize="36" Content="{StaticResource Vector.Record.New}"
Command="u:Commands.NewRecording" Style="{StaticResource Style.Button.Vertical.Border}" FontSize="13">
<n:ImageButton.ToolTip>
<n:HeaderedTooltip Header="{DynamicResource Recorder}" Text="{DynamicResource Tooltip.Recorder}"
MaxWidth="250" Placement="Bottom" HorizontalOffset="-5"/>
</n:ImageButton.ToolTip>
</n:ImageButton>
<n:ImageButton Grid.Column="1" x:Name="WebcamButton" Text="{DynamicResource Webcam}" Margin="5,0,5,5"
Effect="{StaticResource Shadow.Black.Tiny}" MaxSize="36" Content="{StaticResource Vector.Camera.New}"
Command="u:Commands.NewWebcamRecording" Style="{StaticResource Style.Button.Vertical.Border}" FontSize="13">
<n:ImageButton.ToolTip>
<n:HeaderedTooltip Header="{DynamicResource Webcam}" Text="{DynamicResource Tooltip.Webcam}" MaxWidth="250" Placement="Bottom" HorizontalOffset="-5"/>
</n:ImageButton.ToolTip>
</n:ImageButton>
<n:ImageButton Grid.Column="2" x:Name="BoardButton" Text="{DynamicResource Board}" Margin="5,0,5,5"
Effect="{StaticResource Shadow.Black.Tiny}" MaxSize="36" Content="{StaticResource Vector.Board.New}"
Command="u:Commands.NewBoardRecording" Style="{StaticResource Style.Button.Vertical.Border}" FontSize="13">
<n:ImageButton.ToolTip>
<n:HeaderedTooltip Header="{DynamicResource Board}" Text="{DynamicResource Tooltip.Board}" MaxWidth="250" Placement="Bottom" HorizontalOffset="-5"/>
</n:ImageButton.ToolTip>
</n:ImageButton>
<n:ImageButton Grid.Column="3" x:Name="EditorButton" Text="{DynamicResource Editor}" Margin="5,0,5,5"
Effect="{StaticResource Shadow.Black.Tiny}" MaxSize="35" Content="{StaticResource Vector.Editor}"
Command="u:Commands.Editor" Style="{StaticResource Style.Button.Vertical.Border}" FontSize="13">
<n:ImageButton.ToolTip>
<n:HeaderedTooltip Header="{DynamicResource Editor}" Text="{DynamicResource Tooltip.Editor}" MaxWidth="250" Placement="Bottom" HorizontalOffset="-5"/>
</n:ImageButton.ToolTip><!---這有一個浮動提示->
</n:ImageButton>
</Grid>
</Grid>
</Window>
問題3:使用的靜態資源和動態資源是怎么個原理?
靜態資源指該資源只在程序載入內存時一次性使用,之后都不會改變。動態資源是相反的概念。
資源的四個層級?
- 數據庫中的資源 ,相當於倉庫
- 資源文件中的資源,相當於旅行箱
- Wpf 對象資源,相當於背包
- 變量中的數據,相當於手里
什么是wpf對象資源?
使用window.Rescources標簽下的ResourceDictionary標簽夾住的資源
<Window.Resources>
<ResourceDictionary> <!--這個ResourceDictionary標簽可以省略-->
<sys:String x:Key=”str”>
我是一個資源
</sys:String>
</ResourceDictionary>
</WIndow.Rescources>
<TextBlock Text=”{StaticResource ResourceKey=str}” <!--這一行的ResourceKey=可以不寫-->
這是在xaml中引用,如何在程序中引用呢?
string text = (string) this.FindResource(“str”)//資源中的文件要自己來進行格式轉換
使用標簽引用和程序中的FindResource引用會在當前控件的Resource屬性中查找,如果找不到,就會找上一級的。
如果得知就是引用當前的,可以使用string text = (string) this.Resources[“str”]
將資源程序寫到外部文件,如何在程序中引用?
<window.Resources>
<ResourceDictionary Source=”xxx.xaml”/>
</window.Resources>
靜態資源和動態資源中的靜態和動態不是描述資源的,描述控件行為的,也說明改資源項是否可以被外部改寫(類似xml的改寫),只載入一次,之后永遠不變,還是可以動態的變化。
對於動態資源可以使用this.Resoures[“res2”]=new TextBlock(){text=”我要改變了”} ,靜態資源不理會對資源的重新賦值
<window.Resources>
<TextBlock x:Key=”res2” text=”我是一只雞”/>
</window.Resources>
<Button content=”{DynamicResources res2}”/>
問題4:一個界面文件,是如何調用另外一個界面文件的?
比如在ScreenToGif這個項目中,有個Windows文件夾,下面有個Other文件,里面有個ColorSelector.xaml,如何在其他界面文件中使用呢?
步驟:
- 添加對該目錄的引用using ScreenToGif.Windows.Other;,不然你需要寫完整目錄
- 書寫代碼
var colorPicker = new ColorSelector(UserSettings.All.BoardColor) { Owner = this };
var result = colorPicker.ShowDialog();
問題5: style屬性是什么東西?
http://blog.csdn.net/aoshilang2249/article/details/45129365
《深入淺出WPF》 深入淺出話模板
問題6:錄制屏幕界面分析
<n:LightWindow x:Name="RecorderLightWindow" x:Class="ScreenToGif.Windows.Recorder"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:n="clr-namespace:ScreenToGif.Controls"
xmlns:u="clr-namespace:ScreenToGif.Util"
xmlns:c="clr-namespace:ScreenToGif.Util.Converters"
Title="ScreenToGif" SnapsToDevicePixels="True" UseLayoutRounding="True" AllowsTransparency="True" WindowStyle="None"
Topmost="True" Icon="../Resources/Logo.ico" Child="{StaticResource Vector.Back}"
IsThin="{Binding RecorderThinMode, Source={x:Static u:UserSettings.All}}"
IsFullScreen="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}}"
Width="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderWidth, Mode=TwoWay}"
Height="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderHeight, Mode=TwoWay}"
Left="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderLeft, Mode=TwoWay}"
Top="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderTop, Mode=TwoWay}"
FocusManager.FocusedElement="{Binding RelativeSource={x:Static RelativeSource.Self}, Mode=OneTime}"
Foreground="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderForeground, Mode=TwoWay, Converter={StaticResource ColorToBrush}}"
Background="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderBackground, Mode=TwoWay, Converter={StaticResource ColorToBrush}}"
SizeChanged="LightWindow_SizeChanged" Loaded="Recorder_Loaded" Closing="Window_Closing" LocationChanged="Window_LocationChanged">
<Window.Resources>
<Storyboard x:Key="ShowDiscardStoryboard">
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="DiscardButton" Storyboard.TargetProperty="IsHitTestVisible" Duration="0:0:0" >
<DiscreteBooleanKeyFrame Value="True" KeyTime="0:0:0"/>
</BooleanAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="DiscardButton" Storyboard.TargetProperty="Visibility" Duration="0:0:0">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" KeyTime="0:0:0"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="DiscardButton" Storyboard.TargetProperty="(Button.Opacity)" From="0" To="1" Duration="0:0:1">
<DoubleAnimation.EasingFunction>
<PowerEase Power="8" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="HideDiscardStoryboard">
<BooleanAnimationUsingKeyFrames Storyboard.TargetName="DiscardButton" Storyboard.TargetProperty="IsHitTestVisible" Duration="0:0:0" >
<DiscreteBooleanKeyFrame Value="False" KeyTime="0:0:0"/>
</BooleanAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="DiscardButton" Storyboard.TargetProperty="Visibility" Duration="0:0:0">
<DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" KeyTime="0:0:0"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetName="DiscardButton" Storyboard.TargetProperty="(Button.Opacity)"
From="{Binding ElementName=DiscardButton,Path=Opacity}" To="0" Duration="0:0:1">
<DoubleAnimation.EasingFunction>
<PowerEase Power="8" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<c:StageToButtonString x:Key="StageToButtonStringConverter"/>
<c:StageToCanvas x:Key="StageToCanvasConverter"/>
<c:ShortcutKeys x:Key="ShortcutKeys"/>
<c:InvertedBoolToVisibility x:Key="InvertedBoolToVisibility"/>
<c:BoolOrToInvertedVisibility x:Key="BoolOrToInvertedVisibility"/>
<c:IntToString x:Key="IntToStringConverter"/>
</Window.Resources>
<Window.CommandBindings><!--命令關聯,命令前是否可以執行該命令,命令后要做什么-->
<CommandBinding Command="u:Commands.Options" CanExecute="Options_CanExecute" Executed="Options_Executed"/>
<CommandBinding Command="u:Commands.EnableSnapshot" CanExecute="EnableSnapshot_CanExecute" Executed="EnableSnapshot_Executed"/>
<CommandBinding Command="u:Commands.EnableThinMode" CanExecute="EnableThinMode_CanExecute" Executed="EnableThinMode_Executed"/>
<CommandBinding Command="u:Commands.EnableFullScreen" CanExecute="EnableFullScreen_CanExecute" Executed="EnableFullScreen_Executed"/>
<CommandBinding Command="u:Commands.EnableSnapToWindow" CanExecute="SnapToWindow_CanExecute"/>
</Window.CommandBindings>
<Grid x:Name="OutterGrid" UseLayoutRounding="True">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="31"/>
</Grid.RowDefinitions>
<!--Hollow part-->
<Border BorderBrush="{Binding ElementName=RecorderLightWindow, Path=BorderBrush}" BorderThickness="{Binding ElementName=RecorderLightWindow, Path=BorderThickness}"/>
<!--Command bar-->
<Grid Grid.Row="1" x:Name="LowerGrid" Height="31" VerticalAlignment="Bottom" Background="{Binding ElementName=RecorderLightWindow, Path=Background}"
KeyboardNavigation.TabNavigation="Cycle" MouseLeftButtonDown="CommandGrid_MouseLeftButtonDown">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid Grid.Column="0" Visibility="{Binding RecorderThinMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource Bool2Visibility}}">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<n:ImageButton Grid.Row="0" Grid.Column="0" x:Name="BackButton" Content="{StaticResource Vector.Back}" Style="{StaticResource Style.Button.NoText}"
ContentHeight="14" Padding="4,1" TabIndex="0" Click="BackButton_Click"/>
<n:ImageButton Grid.Row="1" Grid.Column="0" x:Name="CloseButton" Content="{StaticResource Vector.Close}" Style="{StaticResource Style.Button.NoText}"
ContentHeight="10" Padding="4,1" TabIndex="1" Click="CloseButton_Click"/>
<TextBlock Grid.Row="0" Grid.Column="1" x:Name="CaptionText" Text="{Binding Title, ElementName=RecorderLightWindow}" FontFamily="Segoe UI" FontSize="12"
FontWeight="Regular" Margin="5,0,0,0" Foreground="#FF6F5252" Effect="{DynamicResource Shadow.Foreground.Small}"/>
<TextBlock Grid.Row="1" Grid.Column="1" x:Name="FrameCountTextBlock" Text="{Binding FrameCount, ElementName=RecorderLightWindow, Converter={StaticResource IntToStringConverter}}"
FontFamily="Segoe UI" FontSize="12" FontWeight="Regular" Margin="5,0,0,0" Foreground="#FF061E87" Effect="{DynamicResource Shadow.Foreground.Small}"/>
</Grid>
<StackPanel Grid.Column="1" x:Name="ControlStackPanel" Height="31" Orientation="Horizontal" HorizontalAlignment="Right"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<n:ImageButton x:Name="SnapButton" Content="{StaticResource Vector.Crosshair}" Margin="0" Style="{StaticResource Style.Button.NoText}"
HorizontalContentAlignment="Center" Effect="{StaticResource Shadow.Foreground.Small}" ContentHeight="20" ContentWidth="20"
Visibility="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"
Command="u:Commands.EnableSnapToWindow" Padding="3" TabIndex="2" PreviewMouseDown="SnapButton_PreviewMouseDown">
<n:ImageButton.ToolTip>
<ToolTip HorizontalOffset="-5" Placement="Bottom" Content="{DynamicResource Recorder.SnapToWindow}"/>
</n:ImageButton.ToolTip>
</n:ImageButton>
<n:ImageButton x:Name="OptionsButton" Content="{StaticResource Vector.Options}" Margin="0" Style="{StaticResource Style.Button.NoText}"
Effect="{StaticResource Shadow.Foreground.Small}" ContentHeight="20" ContentWidth="20" Command="u:Commands.Options" Padding="3" TabIndex="3">
<n:ImageButton.ToolTip>
<ToolTip HorizontalOffset="-5" Placement="Bottom" Content="{DynamicResource Options}"/>
</n:ImageButton.ToolTip>
</n:ImageButton>
<Separator Width="1" Margin="5,2"/>
<Viewbox Stretch="UniformToFill" ClipToBounds="True" Focusable="False">
<Viewbox.Visibility>
<MultiBinding Converter="{StaticResource BoolOrToInvertedVisibility}">
<Binding Path="RecorderThinMode" Source="{x:Static u:UserSettings.All}"/>
<Binding Path="SnapshotMode" Source="{x:Static u:UserSettings.All}"/>
</MultiBinding>
</Viewbox.Visibility>
<Grid HorizontalAlignment="Center" VerticalAlignment="Center" FlowDirection="LeftToRight" Margin="-4">
<n:CircularProgressBar StrokeThickness="2" Percentage="100" SegmentColor="Gray" Radius="24" IsTabStop="False"/>
<n:CircularProgressBar StrokeThickness="22" Percentage="100" SegmentColor="#FFF0F1F1" Radius="10" IsTabStop="False"/>
<n:CircularProgressBar StrokeThickness="2" Value="{Binding ElementName=FpsIntegerUpDown, Path=Value, Mode=OneWay}"
IsInverted="True" Minimum="1" Maximum="60" SegmentColor="#FFE28A73" Radius="24" IsTabStop="False"/>
<n:CircularProgressBar StrokeThickness="22" Value="{Binding ElementName=FpsIntegerUpDown, Path=Value, Mode=OneWay}"
IsInverted="True" Minimum="1" Maximum="60" SegmentColor="#FFE28A73" Radius="10" IsTabStop="False"/>
</Grid>
<Viewbox.ToolTip>
<ToolTip HorizontalOffset="-5" Placement="Bottom" Content="{DynamicResource Recorder.FpsRange}"/>
</Viewbox.ToolTip>
</Viewbox>
<n:IntegerUpDown x:Name="FpsIntegerUpDown" Margin="1,3" StepValue="1" Minimum="1" Maximum="60" MinWidth="45" TabIndex="4"
Value="{Binding Source={x:Static u:UserSettings.All}, Path=LatestFps, Mode=TwoWay}"
Visibility="{Binding SnapshotMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}">
<n:IntegerUpDown.ToolTip>
<ToolTip HorizontalOffset="-5" Placement="Bottom" Content="{DynamicResource Recorder.Fps}"/>
</n:IntegerUpDown.ToolTip>
</n:IntegerUpDown>
<Label Content="{StaticResource Recorder.Fps.Short}" FontSize="12" FontFamily="Segoe UI" Margin="1,0,0,0" VerticalContentAlignment="Center" Padding="0"
Foreground="{Binding ElementName=RecorderLightWindow, Path=Foreground}" Visibility="{Binding SnapshotMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<Separator Width="1" Margin="5,2" Visibility="{Binding SnapshotMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<!--<Viewbox Child="{StaticResource Vector.WidthHeight}" Stretch="UniformToFill" Margin="3,4" HorizontalAlignment="Right" FlowDirection="LeftToRight" SnapsToDevicePixels="True"
Visibility="{Binding RecorderThinMode, Converter={StaticResource InvertedBoolToVisibility}, Source={x:Static u:UserSettings.All}}"/>-->
<n:IntegerBox x:Name="WidthIntegerBox" Value="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderWidth, Mode=TwoWay}"
Offset="{x:Static u:Constants.HorizontalOffset}" Minimum="100" Maximum="3000" TabIndex="6" Height="Auto" Padding="4,0" Margin="1,3"
ToolTip="{DynamicResource Recorder.Width}" ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="-5"
Visibility="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<Label Content="×" FontSize="16" FontFamily="Segoe Script" Margin="1" VerticalContentAlignment="Center" Padding="0"
Foreground="{Binding ElementName=RecorderLightWindow, Path=Foreground}"
Visibility="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<n:IntegerBox x:Name="HeightIntegerBox" Value="{Binding Source={x:Static u:UserSettings.All}, Path=RecorderHeight, Mode=TwoWay}"
Offset="{x:Static u:Constants.VerticalOffset}" Minimum="100" Maximum="3000" TabIndex="7" Height="Auto" Padding="4,0" Margin="1,3"
ToolTip="{DynamicResource Recorder.Height}" ToolTipService.Placement="Bottom" ToolTipService.HorizontalOffset="-5"
Visibility="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<Label Content="px" FontSize="12" FontFamily="Segoe UI" Margin="1,0,0,0" VerticalContentAlignment="Center" Padding="0"
Foreground="{Binding ElementName=RecorderLightWindow, Path=Foreground}"
Visibility="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<Separator Width="1" Margin="5,2" Visibility="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<n:ImageButton x:Name="DiscardButton" Text="{DynamicResource Recorder.Discard}" Content="{StaticResource Vector.Remove}" Visibility="Collapsed"
Click="DiscardButton_Click" Style="{StaticResource Style.Button.Horizontal}"
Foreground="{Binding ElementName=RecorderLightWindow, Path=Foreground}"
UseLayoutRounding="True" MaxSize="16" ContentHeight="18" ContentWidth="18" TabIndex="8"
MinWidth="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ActualHeight}"
KeyGesture="{Binding Converter={StaticResource ShortcutKeys}, ConverterParameter='3'}"/>
<!--ToolTip="{Binding Source={x:Static properties:Settings.Default}, Path=StartPauseKey, Converter={StaticResource KeysToStringConverter}}" ToolTipService.Placement="Bottom"-->
<n:ImageButton x:Name="RecordPauseButton" UseLayoutRounding="True" MaxSize="16" ContentHeight="18" ContentWidth="18" TabIndex="9"
Text="{Binding Stage, ElementName=RecorderLightWindow, Converter={StaticResource StageToButtonStringConverter}, FallbackValue={StaticResource Recorder.Record}}"
Content="{Binding Stage, ElementName=RecorderLightWindow, Converter={StaticResource StageToCanvasConverter}, FallbackValue={StaticResource Vector.Record}}"
Click="RecordPauseButton_Click" Style="{StaticResource Style.Button.Horizontal}"
Foreground="{Binding ElementName=RecorderLightWindow, Path=Foreground}"
MinWidth="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ActualHeight}"
KeyGesture="{Binding Converter={StaticResource ShortcutKeys}, ConverterParameter='1'}">
<n:ImageButton.ContextMenu>
<ContextMenu>
<n:ImageMenuItem Header="{DynamicResource Recorder.RecordingOptions}" IsHitTestVisible="False" Image="{StaticResource Vector.Record}" MaxSize="16"/>
<Separator/>
<n:ImageMenuItem Header="{DynamicResource Recorder.Snapshot}" IsCheckable="True" Image="{StaticResource Vector.Camera.Add}" MaxSize="16"
IsChecked="{Binding SnapshotMode, Source={x:Static u:UserSettings.All}, Mode=TwoWay}" Command="u:Commands.EnableSnapshot"/>
<n:ImageMenuItem x:Name="ThinModeMenuItem" Header="{DynamicResource Recorder.ThinMode}" IsCheckable="True" Image="{StaticResource Vector.Application}" MaxSize="16"
IsChecked="{Binding RecorderThinMode, Source={x:Static u:UserSettings.All}, Mode=TwoWay}" Command="u:Commands.EnableThinMode"
Visibility="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Converter={StaticResource InvertedBoolToVisibility}}"/>
<n:ImageMenuItem Header="{DynamicResource Recorder.Fullscreen}" IsCheckable="True" Image="{StaticResource Vector.WidthHeight}" MaxSize="16"
IsChecked="{Binding FullScreenMode, Source={x:Static u:UserSettings.All}, Mode=TwoWay}" Command="u:Commands.EnableFullScreen"/>
</ContextMenu>
</n:ImageButton.ContextMenu>
</n:ImageButton>
<n:ImageButton x:Name="StopButton" Text="{DynamicResource Recorder.Stop}" Content="{StaticResource Vector.Stop}"
Click="StopButton_Click" Style="{StaticResource Style.Button.Horizontal}"
Foreground="{Binding ElementName=RecorderLightWindow, Path=Foreground}"
UseLayoutRounding="True" MaxSize="16" ContentHeight="18" ContentWidth="18" Margin="0" TabIndex="10"
MinWidth="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ActualHeight}"
KeyGesture="{Binding Converter={StaticResource ShortcutKeys}, ConverterParameter='2'}"/>
</StackPanel>
</Grid>
</Grid>
</n:LightWindow>
問題7:如果這個軟件讓你實現,你會怎么做?
啟動界面,是4個選項,錄制桌面、錄制攝像頭、錄制繪圖、視頻幀編輯器
錄制桌面、錄制攝像頭、錄制繪圖其實是一樣的東西。
無非是設置一個定時器,定時的采集圖像放到硬盤中。這部分的代碼在呢?
C:\Users\laiqun\AppData\Local\Temp\ C:\Users\laiqun\AppData\Local\Temp\ScreenToGif\Recording\2018-02-03 14-18-53
<n:ImageButton x:Name="RecordPauseButton" UseLayoutRounding="True" MaxSize="16" ContentHeight="18" ContentWidth="18" TabIndex="9"
Text="{Binding Stage, ElementName=RecorderLightWindow, Converter={StaticResource StageToButtonStringConverter}, FallbackValue={StaticResource Recorder.Record}}"
Content="{Binding Stage, ElementName=RecorderLightWindow, Converter={StaticResource StageToCanvasConverter}, FallbackValue={StaticResource Vector.Record}}"
Click="RecordPauseButton_Click" Style="{StaticResource Style.Button.Horizontal}"
Foreground="{Binding ElementName=RecorderLightWindow, Path=Foreground}"
MinWidth="{Binding RelativeSource={RelativeSource Mode=Self}, Path=ActualHeight}"
錄制按鈕點擊
private void RecordPauseButton_Click(object sender, RoutedEventArgs e)
{
if (!UserSettings.All.SnapshotMode)
RecordPause();
else
Snap();
}
RecordPause函數的實現:
private async void RecordPause()
{
switch (Stage) //Stage在哪兒改變?
{
case Stage.Stopped: //一開始肯定是從stopped 狀態開始的,啟動錄制后,這里會將stopped狀態改變為recording,表示正在錄制。
錄制其實在啟動一個定時器,做各種記錄性的操作。
從UnregisterEvents這個函數可以看出蛛絲馬跡
private void UnregisterEvents()
{
_capture.Tick -= Normal_Elapsed;
_capture.Tick -= NormalAsync_Elapsed;
_capture.Tick -= Cursor_Elapsed;
_capture.Tick -= CursorAsync_Elapsed;
_capture.Tick -= FullCursor_Elapsed;
_capture.Tick -= Full_Elapsed;
}
private void Normal_Elapsed(object sender, EventArgs e)
{
//Actual position on the screen. 獲取要錄制的區域
var lefttop = Dispatcher.Invoke(() =>
{
var left = Math.Round((Math.Round(Left, MidpointRounding.AwayFromZero) + Constants.LeftOffset) * _scale);
var top = Math.Round((Math.Round(Top, MidpointRounding.AwayFromZero) + Constants.TopOffset) * _scale);
return new Point((int)left, (int)top);
});
//Take a screenshot of the area.
var bt = Native.Capture(_size, lefttop.X, lefttop.Y);
if (bt == null || !IsLoaded)
return;
var fileName = $"{Project.FullPath}{FrameCount}.png";
//這里只是簡單的更新一下圖像文件信息,並沒有實際創建圖像文件
Project.Frames.Add(new FrameInfo(fileName, FrameRate.GetMilliseconds(_snapDelay), new List<SimpleKeyGesture>(_keyList)));
_keyList.Clear();
//AddFrames創建圖像文件
ThreadPool.QueueUserWorkItem(delegate { AddFrames(fileName, new Bitmap(bt)); });//線程池
FrameCount++;
}
1. System.Windows.Forms.Timer myTimer = new System.Windows.Forms.Timer();//實例化
2. myTimer.Tick += new EventHandler(函數名); //給timer掛起事件
3. myTimer.Enabled = true;//使timer可用
4. myTimer.Interval = n; //設置時間間隔,以毫秒為單位
5. myTimer.Stop(); //如果要暫停計時則使用Stop()方法
6. myTimer.Enabled = false;//若要停止使用timer,則使之不可用
設置項界面
是一個xml文件,用來讀取和寫入配置的。 程序的相關地方會讀取這些配置,為了方便,最好把讀取配置項的地方寫在一起.這部分的代碼在呢?UserSettings
namespace ScreenToGif.Util
{
internal sealed class UserSettings : INotifyPropertyChanged
{
#region Variables
private static ResourceDictionary _local;
private static ResourceDictionary _appData;
private static readonly ResourceDictionary Default;
public event PropertyChangedEventHandler PropertyChanged;
public static UserSettings All { get; } = new UserSettings();
視頻幀編輯器負責把錄制的一幀幀的圖像載入,創建對應的縮略圖。這部分的代碼在呢?
我想在錄制的時候順勢把鼠標和鍵盤錄制進去,怎么實現?這部分的代碼在呢?
Recorder構造函數
_actHook = new UserActivityHook(true, true); //true for the mouse, true for the keyboard.
_actHook.KeyDown += KeyHookTarget;
_actHook.OnMouseActivity += MouseHookTarget;