一直在使用dtapp大神寫的STK在工作時間看股票,簡單大方,非常方便。
由於單位使用的是日文的OS,stk的menu顯示亂碼,最近行情大好,導致使用頻率增高,亂碼的menu也無法忍受了。
所以下決心自己做一個,這個東東用了大約3天的閑暇時間初步功能完成,現一步一步的說明一下。
先上圖

先簡單說說實現的功能吧
1.定時刷新股票行情(HttpWebRequest取得新浪行情數據)
2.自定義添加股票,保存到ini文件(ini讀寫)
3.最小化時隱藏到任務欄,不在taskbar表示,雙擊任務欄圖標啟動程序(wpf使用NotifyIcon)
4.熱鍵表示/隱藏(hotkey)
5.保存上次關閉時的位置,存到ini文件中
----------------------------------------------------------------------------
接下來分別說明一下:
1.定時刷新股票行情(HttpWebRequest取得新浪行情數據)
1 Dim request As WebRequest = HttpWebRequest.Create(String.Format(dataURL, _stockCodes)) 2 Dim response As HttpWebResponse = DirectCast(request.GetResponse(), HttpWebResponse) 3 Dim reader As New StreamReader(response.GetResponseStream, Encoding.GetEncoding(response.CharacterSet)) 4 Dim html = reader.ReadToEnd()
說明:dataURL是去行情的網址,這里使用的是http://hq.sinajs.cn/list={0}。定時器就是使用的timer代碼就不貼了,很簡單。
2.自定義添加股票,保存到ini文件(ini讀寫)
1 Public Class INIHelper 2 3 Private inipath As String = Environment.CurrentDirectory & "\DtStock.ini" 4 5 <DllImport("kernel32")> _ 6 Private Shared Function WritePrivateProfileString(section As String, key As String, val As String, filePath As String) As Long 7 End Function 8 9 <DllImport("kernel32")> _ 10 Private Shared Function GetPrivateProfileString(section As String, key As String, def As String, retVal As StringBuilder, size As Integer, filePath As String) As Integer 11 End Function 12 13 Public Sub IniWriteValue(Section As String, Key As String, Value As String) 14 WritePrivateProfileString(Section, Key, Value, Me.inipath) 15 End Sub 16 17 Public Function IniReadValue(Section As String, Key As String) As String 18 Dim temp As New StringBuilder(500) 19 Dim i As Integer = GetPrivateProfileString(Section, Key, "", temp, 500, Me.inipath) 20 Return temp.ToString() 21 End Function 22 23 Public Function ExistINIFile() As Boolean 24 Return File.Exists(inipath) 25 End Function 26 End Class
說明:這里是把ini讀寫專門做了一個helper,方便使用,調用的時候如下
'讀 iniHelper.IniReadValue("Stock", "Code") '寫 iniHelper.IniWriteValue("Stock", "Code", String.Empty)
3.最小化時隱藏到任務欄,不在taskbar表示(wpf使用NotifyIcon)
1 Private Sub ShowNotifyIcon() 2 _notifyIcon = New NotifyIcon() 3 _notifyIcon.Text = "DeskTopStock v1.0" 4 _notifyIcon.Icon = ExtractAssociatedIcon(System.Windows.Forms.Application.ExecutablePath) 5 _notifyIcon.Visible = True 6 7 Dim openMenu As New MenuItem("Add or Setting", AddressOf AddStock) 8 Dim aboutMenu As New MenuItem("About us", AddressOf About) 9 Dim exitMenu As New MenuItem("Exit me", AddressOf CloseMe) 10 11 _notifyIcon.ContextMenu = New ContextMenu({openMenu, aboutMenu, exitMenu}) 12 13 AddHandler _notifyIcon.MouseDoubleClick, AddressOf OnNotifyIconDoubleClick 14 End Sub
說明:引入System.Windows.Forms,綁定上需要用的event就可以了
4.熱鍵表示/隱藏(hotkey)
Imports System.Windows.Forms Imports System.Windows.Interop ''' <summary> ''' 直接構造類實例即可注冊 ''' 自動完成注銷 ''' 注意注冊時會拋出異常 ''' </summary> Class HotKey '注冊系統熱鍵類 '熱鍵會隨着程序結束自動解除,不會寫入注冊表 #Region "Member" Private KeyId As Integer '熱鍵編號 Private Handle As IntPtr '窗體句柄 Private window As Window '熱鍵所在窗體 Private Controlkey As UInteger '熱鍵控制鍵 Private Key As UInteger '熱鍵主鍵 Public Delegate Sub OnHotkeyEventHandeler() '熱鍵事件委托 Public Event OnHotKey As OnHotkeyEventHandeler '熱鍵事件 Shared KeyPair As New Hashtable() '熱鍵哈希表 Private Const WM_HOTKEY As Integer = &H312 ' 熱鍵消息編號 Public Enum KeyFlags '控制鍵編碼 MOD_ALT = &H1 MOD_CONTROL = &H2 MOD_SHIFT = &H4 MOD_WIN = &H8 End Enum #End Region ''' <summary> ''' 構造函數 ''' </summary> ''' <param name="win">注冊窗體</param> ''' <param name="control">控制鍵</param> ''' <param name="key__1">主鍵</param> Public Sub New(win As Window, control As HotKey.KeyFlags, key__1 As Keys) '構造函數,注冊熱鍵 Handle = New WindowInteropHelper(win).Handle window = win Controlkey = CUInt(control) Key = CUInt(key__1) KeyId = CInt(Controlkey) + CInt(Key) * 10 If HotKey.KeyPair.ContainsKey(KeyId) Then Throw New Exception("熱鍵已經被注冊!") End If '注冊熱鍵 If False = HotKey.RegisterHotKey(Handle, KeyId, Controlkey, Key) Then Throw New Exception("熱鍵注冊失敗!") End If If HotKey.KeyPair.Count = 0 Then '消息掛鈎只能連接一次!! If False = InstallHotKeyHook(Me) Then Throw New Exception("消息掛鈎連接失敗!") End If End If '添加這個熱鍵索引 HotKey.KeyPair.Add(KeyId, Me) End Sub #Region "core" <System.Runtime.InteropServices.DllImport("user32")> _ Private Shared Function RegisterHotKey(hWnd As IntPtr, id As Integer, controlKey As UInteger, virtualKey As UInteger) As Boolean End Function <System.Runtime.InteropServices.DllImport("user32")> _ Private Shared Function UnregisterHotKey(hWnd As IntPtr, id As Integer) As Boolean End Function Private Shared Function InstallHotKeyHook(hk As HotKey) As Boolean '安裝熱鍵處理掛鈎 If hk.window Is Nothing OrElse hk.Handle = IntPtr.Zero Then Return False End If '獲得消息源 Dim source As System.Windows.Interop.HwndSource = System.Windows.Interop.HwndSource.FromHwnd(hk.Handle) If source Is Nothing Then Return False End If '掛接事件 source.AddHook(AddressOf HotKey.HotKeyHook) Return True End Function Private Shared _status As Boolean = False Private Shared Function HotKeyHook(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr '熱鍵處理過程 If msg = WM_HOTKEY Then Dim hk As HotKey = DirectCast(HotKey.KeyPair(CInt(wParam)), HotKey) _status = hk.window.IsVisible If _status Then hk.window.Hide() _status = False Else hk.window.Show() _status = True End If End If Return IntPtr.Zero End Function Protected Overrides Sub Finalize() Try '析構函數,解除熱鍵 HotKey.UnregisterHotKey(Handle, KeyId) Finally MyBase.Finalize() End Try End Sub #End Region End Class
說明:這個是網上找到的一個類,作者寫的很好,直接使用了(忘記作者的原貼地址了,抱歉!!)
需要在Loaded之后調用,直接初期化一下傳入熱鍵就OK了,不寫入注冊表,程序關掉即釋放。
5.保存上次關閉時的位置,存到ini文件中
Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs) Handles Me.Closing _iniHelper.IniWriteValue("WinLocation", "Left", CStr(Me.Left)) _iniHelper.IniWriteValue("WinLocation", "Top", CStr(Me.Top)) End Sub Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded If String.IsNullOrEmpty(_iniHelper.IniReadValue("WinLocation", "Left")) Then Me.WindowStartupLocation = Windows.WindowStartupLocation.CenterScreen Exit Sub End If Me.Left = Double.Parse(_iniHelper.IniReadValue("WinLocation", "Left")) Me.Top = Double.Parse(_iniHelper.IniReadValue("WinLocation", "Top")) Dim HotKey As New HotKey(Me, HotKey.KeyFlags.MOD_WIN, Keys.A) End Sub
說明:窗口關閉的時候把位置保存起來,程序啟動的時候再讀出來,第一次啟動程序的時候設定位置為屏幕中央。
最后把XAML貼出來
1 <Window x:Class="MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 Title="DeskTopStock" SizeToContent="WidthAndHeight" 5 xmlns:my="clr-namespace:DeskTopStock" ResizeMode="CanMinimize" WindowStyle="None" 6 Opacity="0.8" AllowsTransparency ="True" ShowInTaskbar="False" Topmost="True" 7 FontSize="11.5" FontFamily="Microsoft YaHei" MouseMove="TitleBar_MouseMove"> 8 9 <Window.Resources> 10 <my:BackgroundConverter x:Key="myConverter"/> 11 12 <ToolTip x:Key="InforTip"> 13 <StackPanel Orientation="Vertical"> 14 <StackPanel Orientation="Horizontal"> 15 <TextBlock Text="{Binding Name}" /> 16 <TextBlock Text=" " /> 17 <TextBlock Text="{Binding Code}"/> 18 </StackPanel> 19 <StackPanel Orientation="Horizontal"> 20 <TextBlock Text="昨收盤:" /> 21 <TextBlock Text="{Binding YesterdayClose}"/> 22 </StackPanel> 23 <StackPanel Orientation="Horizontal"> 24 <TextBlock Text="今開盤:" /> 25 <TextBlock Text="{Binding TodayOpen}"/> 26 </StackPanel> 27 <StackPanel Orientation="Horizontal"> 28 <TextBlock Text="最 高:" /> 29 <TextBlock Text="{Binding High}"/> 30 </StackPanel> 31 <StackPanel Orientation="Horizontal"> 32 <TextBlock Text="最 低:" /> 33 <TextBlock Text="{Binding Low}"/> 34 </StackPanel> 35 36 </StackPanel> 37 </ToolTip> 38 39 <Style x:Key="myItemStyle" TargetType="{x:Type ListViewItem}"> 40 <Setter Property="Foreground"> 41 <Setter.Value> 42 <Binding RelativeSource="{RelativeSource Self}" Converter="{StaticResource myConverter}" ConverterParameter="{RelativeSource Self}" /> 43 </Setter.Value> 44 </Setter> 45 <Setter Property="ToolTip" Value="{Binding Source={StaticResource InforTip}}" /> 46 </Style> 47 48 </Window.Resources> 49 <Grid> 50 <Grid.RowDefinitions> 51 <RowDefinition Height="22" /> 52 <RowDefinition Height="*" /> 53 <RowDefinition Height="20" /> 54 </Grid.RowDefinitions> 55 <DockPanel Background="AntiqueWhite" > 56 <Button Name="C" ToolTip="關閉" Width="30" Height="20" Content="X" /> 57 <Button Width="30" ToolTip="隱藏" Height="20" Content="—" Name="Button1" /> 58 <Button Name="Add" ToolTip="添加股票" Width="30" Height="20" Content="十" Margin="5,0,0,0" Command="{Binding AddCommand}" HorizontalAlignment="Left" 59 CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=Window, AncestorLevel=1}}" /> 60 </DockPanel> 61 62 <ListView HorizontalAlignment="Stretch" Name="ListView1" ItemsSource="{Binding StockCollection}" VerticalAlignment="Stretch" 63 ItemContainerStyle="{StaticResource myItemStyle}" Grid.Row="1" > 64 <ListView.View> 65 <GridView> 66 <GridViewColumn Width="60" Header="簡稱" DisplayMemberBinding="{Binding Name}" /> 67 <GridViewColumn Width="75" Header="最新價" DisplayMemberBinding="{Binding Current}"/> 68 <GridViewColumn Width="65" Header="漲跌額" DisplayMemberBinding="{Binding ZDF}"/> 69 <GridViewColumn Width="60" Header="漲跌幅" DisplayMemberBinding="{Binding ZDF2}"/> 70 </GridView> 71 </ListView.View> 72 </ListView> 73 <TextBlock Text="數據更新中,請稍候.." Visibility="{Binding IsUpdateVisilility}" HorizontalAlignment="Left" Grid.Row="2"/> 74 <TextBlock Grid.Row="2" HorizontalAlignment="Right" Text="{Binding DateString}"/> 75 </Grid> 76 </Window>
說明:1.BackgroundConverter是控制ListView的行顏色的,上漲的時候是紅色,跌的時候綠色 2.InforTip是Tooltip的顯示內容
如有想需要代碼或者程序的同學給我地址即可。
