V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yanjinhua
V2EX  ›  Windows

制作 Windows 屏保

  •  1
     
  •   yanjinhua · 2022-07-28 11:18:20 +08:00 · 1098 次点击
    这是一个创建于 635 天前的主题,其中的信息可能已经有所发展或是发生改变。

    分享如何使用WPF 制作 Windows 屏保

    WPF 制作 Windows 屏保

    作者:驚鏵

    原文链接: https://github.com/yanjinhuagood/ScreenSaver

    • 框架使用.NET452

    • Visual Studio 2019;

    • 项目使用 MIT 开源许可协议;

    • 更多效果可以通过GitHub|码云下载代码;

    • 也可以自行添加天气信息等。

    正文

    • 屏保程序的本质上就是一个 Win32 窗口应用程序;

      • 把编译好一个窗口应用程序之后,把扩展名更改为 scr,于是你的屏幕保护程序就做好了;
      • 选中修改好的 scr 程序上点击右键,可以看到一个 安装 选项,点击之后就安装了;
      • 安装之后会立即看到我们的屏幕保护程序已经运行起来了;

    • 处理屏幕保护程序参数如下

      • /s 屏幕保护程序开始,或者用户点击了 预览 按钮;
      • /c 用户点击了 设置按钮;
      • /p 用户选中屏保程序之后,在预览窗格中显示;

    1 )MainWindow.xaml 代码如下;

    <Window x:Class="ScreenSaver.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:system="clr-namespace:System;assembly=mscorlib"
            xmlns:drawing="http://www.microsoft.net/drawing"
            xmlns:local="clr-namespace:ScreenSaver"
            mc:Ignorable="d" WindowStyle="None"
            Title="MainWindow" Height="450" Width="800">
        <Grid x:Name="MainGrid">
            <drawing:PanningItems ItemsSource="{Binding stringCollection,RelativeSource={RelativeSource AncestorType=local:MainWindow}}"
                                  x:Name="MyPanningItems">
                <drawing:PanningItems.ItemTemplate>
                    <DataTemplate>
                        <Rectangle>
                            <Rectangle.Fill>
                                <ImageBrush ImageSource="{Binding .}"/>
                            </Rectangle.Fill>
                        </Rectangle>
                    </DataTemplate>
                </drawing:PanningItems.ItemTemplate>
            </drawing:PanningItems>
            <Grid  HorizontalAlignment="Center" 
                   VerticalAlignment="Top"
                    Margin="0,50,0,0">
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                </Grid.RowDefinitions>
                <Grid.Resources>
                    <Style TargetType="TextBlock">
                        <Setter Property="FontSize" Value="90"/>
                        <Setter Property="FontWeight" Value="Black"/>
                        <Setter Property="Foreground" Value="White"/>
                    </Style>
                </Grid.Resources>
                <WrapPanel>
                    <TextBlock Text="{Binding Hour,RelativeSource={RelativeSource AncestorType=local:MainWindow}}"/>
                    <TextBlock Text=":" x:Name="PART_TextBlock">
                        <TextBlock.Triggers>
                            <EventTrigger RoutedEvent="FrameworkElement.Loaded">
                                <BeginStoryboard>
                                    <Storyboard>
                                        <DoubleAnimation Duration="00:00:01"
                                                     From="1"
                                                     To="0"
                                                     Storyboard.TargetName="PART_TextBlock"
                                                     Storyboard.TargetProperty="Opacity"
                                                     RepeatBehavior="Forever"
                                                     FillBehavior="Stop"/>
                                    </Storyboard>
                                </BeginStoryboard>
                            </EventTrigger>
                        </TextBlock.Triggers>
                    </TextBlock>
                    <TextBlock Text="{Binding Minute,RelativeSource={RelativeSource AncestorType=local:MainWindow}}"/>
                </WrapPanel>
                <TextBlock Grid.Row="1" FontSize="45" HorizontalAlignment="Center" Text="{Binding Date,RelativeSource={RelativeSource AncestorType=local:MainWindow}}"/>
            </Grid>
        </Grid>
    </Window>
    

    2 ) MainWindow.xaml.cs 代码如下;

    • 当屏保启动后需要注意如下
      • 将鼠标设置为不可见Cursors.None;
      • 将窗体设置为最大化WindowState.Maximized;
      • WindowStyle设置为"None";
      • 注意监听鼠标按下键盘按键则退出屏保;
    using System;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.IO;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Threading;
    
    namespace ScreenSaver
    {
        /// <summary>
        ///     MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            public static readonly DependencyProperty stringCollectionProperty =
                DependencyProperty.Register("stringCollection", typeof(ObservableCollection<string>), typeof(MainWindow),
                    new PropertyMetadata(null));
    
            public static readonly DependencyProperty HourProperty =
                DependencyProperty.Register("Hour", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
    
            public static readonly DependencyProperty MinuteProperty =
                DependencyProperty.Register("Minute", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
    
            public static readonly DependencyProperty SecondProperty =
                DependencyProperty.Register("Second", typeof(string), typeof(MainWindow), new PropertyMetadata(null));
    
            public static readonly DependencyProperty DateProperty =
                DependencyProperty.Register("Date", typeof(string), typeof(MainWindow), new PropertyMetadata());
    
            private readonly DispatcherTimer timer = new DispatcherTimer();
    
            public MainWindow()
            {
                InitializeComponent();
                Loaded += delegate
                {
                    WindowState = WindowState.Maximized;
                    Mouse.OverrideCursor = Cursors.None;
                    var date = DateTime.Now;
                    Hour = date.ToString("HH");
                    Minute = date.ToString("mm");
                    Date =
                        $"{date.Month} / {date.Day}   {CultureInfo.CurrentCulture.DateTimeFormat.GetDayName(date.DayOfWeek)}";
                    stringCollection = new ObservableCollection<string>();
                    var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Images");
                    var directoryInfo = new DirectoryInfo(path);
                    foreach (var item in directoryInfo.GetFiles())
                    {
                        if (Path.GetExtension(item.Name) != ".jpg") continue;
                        stringCollection.Add(item.FullName);
                    }
    
                    timer.Interval = TimeSpan.FromSeconds(1);
                    timer.Tick += delegate
                    {
                        date = DateTime.Now;
                        Hour = date.ToString("HH");
                        Minute = date.ToString("mm");
                        Date =
                            $"{date.Month} / {date.Day}   {CultureInfo.CurrentCulture.DateTimeFormat.GetDayName(date.DayOfWeek)}";
                    };
                    timer.Start();
                };
                MouseDown += delegate { Application.Current.Shutdown(); };
                KeyDown += delegate { Application.Current.Shutdown(); };
            }
    
            public ObservableCollection<string> stringCollection
            {
                get => (ObservableCollection<string>)GetValue(stringCollectionProperty);
                set => SetValue(stringCollectionProperty, value);
            }
    
    
            public string Hour
            {
                get => (string)GetValue(HourProperty);
                set => SetValue(HourProperty, value);
            }
    
            public string Minute
            {
                get => (string)GetValue(MinuteProperty);
                set => SetValue(MinuteProperty, value);
            }
    
            public string Second
            {
                get => (string)GetValue(SecondProperty);
                set => SetValue(SecondProperty, value);
            }
    
    
            public string Date
            {
                get => (string)GetValue(DateProperty);
                set => SetValue(DateProperty, value);
            }
        }
    }
    

    参考① 参考②

    2 条回复    2022-07-29 10:34:54 +08:00
    yanjinhua
        2
    yanjinhua  
    OP
       2022-07-29 10:34:54 +08:00
    @guchengzhihuan 谢谢分享,这个是屏保 后期会增加去读取 www.bing.com 的每日图。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1086 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 26ms · UTC 19:01 · PVG 03:01 · LAX 12:01 · JFK 15:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.