用WPF实现桌面锁屏壁纸的应用
目录需求分析
需求
-
存取数据库二进制文件
-
轮播图片
-
显示系统时间
-
滑动解锁
-
禁用键盘
-
添加托盘图标
-
开机自启动
方案
- 采用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,线程钩子键盘为2
private 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);
}
}
}
壁纸