用WPF实现桌面锁屏壁纸的应用
目录
- 用WPF实现桌面锁屏壁纸的应用
- 需求分析
- 需求
- 方案
- 实现
- App.xaml
- App.xaml.cs
- MainWindow.xaml
- MainWindow.xaml.cs
- ImportImageHelper.cs
- KeyboardHookLib.cs
- 需求分析
- 壁纸
需求分析
需求
-
存取数据库二进制文件
-
轮播图片
-
显示系统时间
-
滑动解锁
-
禁用键盘
-
添加托盘图标
-
开机自启动
方案
- 采用SQLite数据库,NuGet:
System.Data.SQLite 1.0.119.0
- 读取文件
FileStream->BinaryReader->byte[]
- 读取二进制
object->MemoryStream->BitmapImage.StreamSource
-
设置进程WallPaperChangeThread,固定频率刷新图片
-
设置进程TimeChangeThread,刷新时间
-
添加滑动按钮的MouseUp\MouseOn\MouseMove,修改坐标点
-
用钩子函数监听键盘事件
-
C#托盘图标库
Hardcodet.NotifyIcon.Wpf 2.0.1
- 启动目录下创建快捷方式
C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Startup
- 壁纸链接
哲风壁纸
实现
App.xaml
<Application x:Class="Wpf.LockWindow.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:Wpf.LockWindow"xmlns:tb="http://www.hardcodet.net/taskbar"><Application.Resources><ContextMenu x:Shared="false" x:Key="SysTrayMenu"><MenuItem x:Name="showItem" Click="showItem_Click" Header="显示窗口"/><MenuItem x:Name="closeItem" Click="closeItem_Click" Header="关闭窗口"/><Separator /><MenuItem x:Name="quitItem" Click="quitItem_Click" Header="退出"/></ContextMenu><tb:TaskbarIcon x:Key="Taskbar"TrayMouseDoubleClick="TaskbarIcon_TrayMouseDoubleClick"ContextMenu="{StaticResource SysTrayMenu}"IconSource="/icon.ico" ></tb:TaskbarIcon></Application.Resources>
</Application>
App.xaml.cs
using Hardcodet.Wpf.TaskbarNotification;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;namespace Wpf.LockWindow
{/// <summary>/// App.xaml 的交互逻辑/// </summary>public partial class App : Application{public static TaskbarIcon TaskbarIcon;protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);TaskbarIcon = (TaskbarIcon)FindResource("Taskbar");}private void TaskbarIcon_TrayMouseDoubleClick(object sender, RoutedEventArgs e){if (MainWindow == null){MainWindow = new MainWindow();}MainWindow.Show();MainWindow.WindowState = WindowState.Maximized;}private void showItem_Click(object sender, RoutedEventArgs e){if (MainWindow == null){MainWindow = new MainWindow();}MainWindow.Show();MainWindow.WindowState = WindowState.Maximized;}private void closeItem_Click(object sender, RoutedEventArgs e){if (MainWindow == null){MainWindow = new MainWindow();}MainWindow.Hide();}private void quitItem_Click(object sender, RoutedEventArgs e){Process.GetCurrentProcess().Kill();//Application.Current.Shutdown();}}
}
MainWindow.xaml
<Window x:Class="Wpf.LockWindow.MainWindow"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:local="clr-namespace:Wpf.LockWindow"mc:Ignorable="d"WindowStartupLocation="CenterScreen"WindowState="Maximized"WindowStyle="None"Background="Transparent"Topmost="True"Opacity="2"AllowsTransparency="True"Title="点击锁屏"><Window.Resources><ResourceDictionary><Style TargetType="Button"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><Border x:Name="MyBackgroundElement" BorderThickness="0"><ContentPresenter x:Name="ButtonContentPresenter" VerticalAlignment="Center" HorizontalAlignment="Center"/></Border><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter TargetName="MyBackgroundElement" Property="Background" Value="Transparent"/><Setter TargetName="MyBackgroundElement" Property="Opacity" Value="0.7"/></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter><Setter Property="Cursor" Value="Hand" /></Style></ResourceDictionary></Window.Resources><Grid x:Name="Win"><Grid.ColumnDefinitions><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition><ColumnDefinition></ColumnDefinition></Grid.ColumnDefinitions><Grid.RowDefinitions><RowDefinition></RowDefinition><RowDefinition></RowDefinition><RowDefinition></RowDefinition></Grid.RowDefinitions><!--壁纸背景--><Image x:Name="WallPaper" Grid.Row="0" Grid.RowSpan="3" Grid.Column="0" Grid.ColumnSpan="3" Stretch="Fill"/><!--系统时间--><TextBlock x:Name="DateTime" Grid.Row="0" Grid.Column="0" Background="Transparent" Opacity="2" Foreground="White" FontWeight="Bold" FontSize="50" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="10 0 0 0" TextAlignment="Left"></TextBlock><!--切回桌面--><Button x:Name="UnLockWindow" FocusVisualStyle="{x:Null}" Click="UnLockWindow_Click" Grid.Row="2" Grid.Column="1" Width="200" Height="60" Content="上滑解锁" Background="Transparent" Opacity="2" Foreground="White" FontSize="20" BorderThickness="10" BorderBrush="Black" Margin="0 0 0 10" VerticalAlignment="Bottom"PreviewMouseDown="Button_MouseDown"PreviewMouseMove="Button_MouseMove"PreviewMouseUp="Button_MouseUp"></Button><!--导入壁纸--><Button x:Name="Import" FocusVisualStyle="{x:Null}" Click="Import_Click" Grid.Row="2" Grid.Column="2" Width="50" Height="50" Background="Transparent" Opacity="2" Foreground="White" FontSize="40" BorderThickness="0" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0 0 20 10"><!--<Image Source="/import.png"></Image>--><Image Source="/处理完成图片20241218110105.png" /></Button></Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Infrastructure;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Forms;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using static Wpf.LockWindow.KeyboardHookLib;
using Control = System.Windows.Controls.Control;
using MessageBox = System.Windows.MessageBox;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;namespace Wpf.LockWindow
{/// <summary>/// MainWindow.xaml 的交互逻辑/// </summary>public partial class MainWindow : Window{public MainWindow(){try{m_dbConnection = new SQLiteConnection("Data Source=WallPaper.db;Version=3;");//没有数据库则自动创建m_dbConnection.Open();string sql = "create table if not exists ImageTable (Id integer PRIMARY KEY AUTOINCREMENT,ImageData BLOB, ImageName TEXT)";SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);command.ExecuteNonQuery();InitializeComponent();if (WallPaperChangeThread == null){WallPaperChangeThread = new Thread(WallPaperChange);WallPaperChangeThread.Start();}this.Height = Screen.PrimaryScreen.Bounds.Height;this.Width = Screen.PrimaryScreen.Bounds.Width;if (TimeChangeThread == null){TimeChangeThread = new Thread(TimeChange);TimeChangeThread.Start();}}catch (Exception ex){MessageBox.Show(ex.Message,"异常");}}Thread TimeChangeThread = null;private void WallPaperChange(){try{while (true){string sql = "";//读取数据库二进制流文件转图片SQLiteCommand cmd = new SQLiteCommand(sql, m_dbConnection);if (m_dbConnection.State != ConnectionState.Open){m_dbConnection.Open();}DataSet ds = new DataSet();sql = "select * from ImageTable";cmd.CommandText = sql;SQLiteDataAdapter adp = new SQLiteDataAdapter(cmd);adp.Fill(ds);foreach (DataRow dr in ds.Tables[0].Rows){this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>{BitmapImage img = new BitmapImage();img.BeginInit();img.CacheOption = BitmapCacheOption.OnLoad;byte[] picData = (byte[])dr[1];MemoryStream ms = new MemoryStream(picData);ms.Seek(0, System.IO.SeekOrigin.Begin);img.StreamSource = ms;img.EndInit();this.WallPaper.Source = img;img.Freeze();ms.Dispose();//this.WallPaper.Source = new BitmapImage(new Uri("C:\\Users\\EDY\\Downloads\\【哲风壁纸】金克斯-雨中美女.png"));}));Thread.Sleep(10000);}}}catch (Exception ex){MessageBox.Show(ex.Message, "异常");}}private void TimeChange(){try{while (true){this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>{this.DateTime.Text = System.DateTime.Now.ToString("MM月dd日 HH:mm:ss");if (this.WindowState != WindowState.Minimized && _keyboardHook == null){_keyboardHook = new KeyboardHookLib();//把客户端委托函数传给键盘钩子类KeyBoardHookLib_keyboardHook.InstallHook(this.Form1_KeyPress);}else if (this.WindowState == WindowState.Minimized && _keyboardHook != null){//卸载钩子_keyboardHook.UninstallHook();_keyboardHook = null;}}));Thread.Sleep(1000);}}catch (Exception ex){MessageBox.Show(ex.Message, "异常");}}Thread WallPaperChangeThread = null;private void UnLockWindow_Click(object sender, RoutedEventArgs e){try{}catch (Exception ex){MessageBox.Show(ex.Message, "异常");}}//数据库连接SQLiteConnection m_dbConnection;private void Import_Click(object sender, RoutedEventArgs e){try{string strFileName = "";OpenFileDialog ofd = new OpenFileDialog();ofd.Filter = "图像文件|*.png;*.jpg";ofd.ValidateNames = true; // 验证用户输入是否是一个有效的Windows文件名ofd.CheckFileExists = true; //验证路径的有效性ofd.CheckPathExists = true;//验证路径的有效性if (ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) //用户点击确认按钮,发送确认消息{strFileName = ofd.FileName;//获取在文件对话框中选定的路径或者字符串}if (String.IsNullOrEmpty(strFileName)){MessageBox.Show("文件为空", "错误");}else{ImportImageHelper.Updata_SQL(m_dbConnection, strFileName);}}catch (Exception ex){MessageBox.Show(ex.Message, "异常");}}//鼠标是否按下bool _isMouseDown = false;//鼠标按下的位置Point _mouseDownPosition;//鼠标按下控件的初始位置Point _mouseDownStartPosition;//鼠标按下控件的位置Point _mouseDownControlPosition;//鼠标按下事件private void Button_MouseDown(object sender, MouseButtonEventArgs e){var c = sender as Control;_isMouseDown = true;_mouseDownPosition = e.GetPosition(this);var transform = c.RenderTransform as TranslateTransform;if (transform == null){transform = new TranslateTransform();c.RenderTransform = transform;}_mouseDownControlPosition = new Point(transform.X, transform.Y);_mouseDownStartPosition = _mouseDownControlPosition;c.CaptureMouse();}private void Button_MouseMove(object sender, MouseEventArgs e){if (_isMouseDown){var c = sender as Control;var pos = e.GetPosition(this);var dp = pos - _mouseDownPosition;var transform = c.RenderTransform as TranslateTransform;//transform.X = _mouseDownControlPosition.X + dp.X;transform.Y = _mouseDownControlPosition.Y + dp.Y;if (4 * Math.Abs(transform.Y) > Screen.PrimaryScreen.Bounds.Height){transform.Y = _mouseDownStartPosition.Y;_isMouseDown = false;c.ReleaseMouseCapture();this.WindowState = WindowState.Minimized;}}}private void Button_MouseUp(object sender, MouseButtonEventArgs e){var c = sender as Control;var transform = c.RenderTransform as TranslateTransform;transform.Y = _mouseDownStartPosition.Y;_isMouseDown = false;c.ReleaseMouseCapture();}private void Win_KeyDown(object sender, System.Windows.Input.KeyEventArgs e){try{if (e.Key == Key.LeftAlt || e.Key == Key.RightAlt || e.Key == Key.LWin || e.Key == Key.RWin || e.Key == Key.Tab || e.Key == Key.F4){return;}}catch (Exception ex){MessageBox.Show(ex.Message,"异常");}}private void Win_PreviewKeyDown(object sender, System.Windows.Input.KeyEventArgs e){Key key = (e.Key == Key.System ? e.SystemKey : e.Key);if (key == Key.LeftAlt || key == Key.RightAlt || key == Key.LWin || key == Key.RWin || key == Key.Tab || key == Key.F4){e.Handled = true;}}private void Win_PreviewKeyUp(object sender, System.Windows.Input.KeyEventArgs e){Key key = (e.Key == Key.System ? e.SystemKey : e.Key);if (key == Key.LeftAlt || key == Key.RightAlt || key == Key.LWin || key == Key.RWin || key == Key.Tab || key == Key.F4){e.Handled = true;}}private KeyboardHookLib _keyboardHook = null;//客户端传递的委托函数private void Form1_KeyPress(KeyboardHookLib.HookStruct hookStruct, out bool handle){handle = true; //预设不拦截return;}}
}
ImportImageHelper.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data.SqlClient;
using System.Data.SQLite;
using System.Windows;
using System.Data.Common;
using System.Drawing;
using System.Windows.Media.Imaging;
using System.Windows.Threading;namespace Wpf.LockWindow
{public static class ImportImageHelper{//上传二进制流数据到数据库public static void Updata_SQL(SQLiteConnection conn,string FileName){try{byte[] picData = GetFileBytes(FileName);FileName = "\'" + Path.GetFileName(FileName) + "\'";string sql = "";//conn.Open();SQLiteCommand cmd = new SQLiteCommand(sql, conn);if (conn.State != ConnectionState.Open){conn.Open();}// 直接返这个值放到数据就行了 sql = $"Insert into ImageTable (Id,ImageData,ImageName) Values (null,@Data, {FileName})";cmd.CommandText = sql;cmd.Parameters.Add("@Data", DbType.Object, picData.Length);cmd.Parameters["@Data"].Value = picData;cmd.ExecuteNonQuery();}catch (Exception ex){MessageBox.Show(ex.Message, "异常");}}//直接上传图片 内部自动转换为二进制流数据public static void Updata_SQL(SQLiteConnection conn,string FileName, Image Picture){try{byte[] picData = ImageToByte(Picture);string sql = "";//conn.Open();SQLiteCommand cmd = new SQLiteCommand(sql, conn);if (conn.State != ConnectionState.Open){conn.Open();}// 直接返这个值放到数据就行了 sql = $"Insert into ImageTable (ImageData,ImageName) Values (@Data, {FileName})";cmd.CommandText = sql;cmd.Parameters.Add("@Data", DbType.Object, picData.Length);cmd.Parameters["@Data"].Value = picData;cmd.ExecuteNonQuery();}catch (Exception ex){MessageBox.Show(ex.Message, "异常");}}//将图片数据转换为二进制流数据private static byte[] ImageToByte(Image Picture){try{MemoryStream ms = new MemoryStream();if (Picture == null)return new byte[ms.Length];Picture.Save(ms, System.Drawing.Imaging.ImageFormat.Png);byte[] BPicture = new byte[ms.Length];BPicture = ms.GetBuffer();return BPicture;}catch (Exception ex){MessageBox.Show(ex.Message, "异常");return null;}}//二进制流转为图片方法public static Stream Byte_Image(object value){try{byte[] picData = (byte[])value;MemoryStream ms = new MemoryStream(picData);ms.Seek(0, System.IO.SeekOrigin.Begin);Stream stream = ms;//StreamToFile(ms, "C:\\Users\\EDY\\Downloads\\【哲风壁纸】金克斯-雨中女.png");return stream;}catch (Exception ex){MessageBox.Show(ex.Message, "异常");return null;}}//转文件public static void StreamToFile(Stream stream, string fileName){// 把 Stream 转换成 byte[]byte[] bytes = new byte[stream.Length];stream.Read(bytes, 0, bytes.Length);// 设置当前流的位置为流的开始stream.Seek(0, SeekOrigin.Begin);// 把 byte[] 写入文件FileStream fs = new FileStream(fileName, FileMode.Create);BinaryWriter bw = new BinaryWriter(fs);bw.Write(bytes);bw.Close();fs.Close();}//将文件读取转换为二进制流文件public static byte[] GetFileBytes(string Filename){try{if (Filename == "")return null;FileStream fileStream = new FileStream(Filename, FileMode.Open, FileAccess.Read);BinaryReader binaryReader = new BinaryReader(fileStream);byte[] fileBytes = binaryReader.ReadBytes((int)fileStream.Length);binaryReader.Close();return fileBytes;}catch (Exception ex){MessageBox.Show(ex.Message, "异常");return null;}}}
}
KeyboardHookLib.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;
using MessageBox = System.Windows.MessageBox;namespace Wpf.LockWindow
{public class KeyboardHookLib{//钩子类型:键盘private const int WH_KEYBOARD_LL = 13; //全局钩子键盘为13,线程钩子键盘为2private const int WM_KEYDOWN = 0x0100; //键按下private const int WM_KEYUP = 0x0101; //键弹起//全局系统按键private const int WM_SYSKEYDOWN = 0x104;//键盘处理委托事件,捕获键盘输入,调用委托方法private delegate int HookHandle(int nCode, int wParam, IntPtr lParam);private static HookHandle _keyBoardHookProcedure;//客户端键盘处理委托事件public delegate void ProcessKeyHandle(HookStruct param, out bool handle);private static ProcessKeyHandle _clientMethod = null;//接收SetWindowsHookEx返回值 判断是否安装钩子private static int _hHookValue = 0;//Hook结构 存储按键信息的结构体[StructLayout(LayoutKind.Sequential)]public class HookStruct{public int vkCode;public int scanCode;public int flags;public int time;public int dwExtraInfo;}//安装钩子//idHook为13代表键盘钩子为14代表鼠标钩子,lpfn为函数指针,指向需要执行的函数,hIntance为指向进程快的指针,threadId默认为0就可以了[DllImport("user32.dll")]private static extern int SetWindowsHookEx(int idHook, HookHandle lpfn, IntPtr hInstance, int threadId);//取消钩子[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]public static extern bool UnhookWindowsHookEx(int idHook);//调用下一个钩子[DllImport("user32.dll")]public static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);//获取当前线程id[DllImport("kernel32.dll")]public static extern int GetCurrentThreadId();//通过线程Id,获取进程快[DllImport("kernel32.dll")]public static extern IntPtr GetModuleHandle(String name);private IntPtr _hookWindowPtr = IntPtr.Zero;public KeyboardHookLib() { }#region//加上客户端方法的委托的安装钩子public void InstallHook(ProcessKeyHandle clientMethod){try{//客户端委托事件 _clientMethod = clientMethod;//安装键盘钩子if (_hHookValue == 0){_keyBoardHookProcedure = new HookHandle(GetHookProc);_hookWindowPtr = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);_hHookValue = SetWindowsHookEx(WH_KEYBOARD_LL,_keyBoardHookProcedure,_hookWindowPtr,0);if (_hHookValue == 0){//设置钩子失败UninstallHook();}}}catch (Exception ex){MessageBox.Show(ex.Message,"异常");}}#endregion//取消钩子事件public void UninstallHook(){if (_hHookValue != 0){bool ret = UnhookWindowsHookEx(_hHookValue);if (ret){_hHookValue = 0;}}}private static int GetHookProc(int nCode, int wParam, IntPtr lParam){if (nCode >= 0){HookStruct kbh = (HookStruct)Marshal.PtrToStructure(lParam, typeof(HookStruct));if (kbh.vkCode == 91) // 截获左win(开始菜单键){return 1;}if (kbh.vkCode == 92)// 截获右win{return 1;}if (kbh.vkCode == (int)Keys.Escape && (int)Control.ModifierKeys == (int)Keys.Control) //截获Ctrl+Esc{return 1;}if (kbh.vkCode == (int)Keys.F4 && (int)Control.ModifierKeys == (int)Keys.Alt) //截获alt+f4{return 1;}if (kbh.vkCode == (int)Keys.Tab && (int)Control.ModifierKeys == (int)Keys.Alt) //截获alt+tab{return 1;}if (kbh.vkCode == (int)Keys.Escape && (int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Shift) //截获Ctrl+Shift+Esc{return 1;}if (kbh.vkCode == (int)Keys.Space && (int)Control.ModifierKeys == (int)Keys.Alt) //截获alt+空格{return 1;}if (kbh.vkCode == 241) //截获F1{return 1;}//if (kbh.vkCode == (int)Keys.Delete && (int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Alt) //截获Ctrl+Alt+Delete//{// return 1;//}if (kbh.vkCode == 122) //截取F11{return 1;}}return CallNextHookEx(_hHookValue, nCode, wParam, lParam);}}
}
壁纸