exe不能下载的话源码里有,资源绑定默认是vip资源,不知道你们能不能下载。
只换一个积分的源码
我觉得值得记录的一些东西
主窗口关闭,程序不退出的问题
WPF 主窗口默认是MainWindow,但是点击主窗口的关闭按钮(X)窗口关闭了,程序未退出。
解决办法:在MainWindow.xaml中Window标签里添加Closing事件函数
Closing=“Window_Closing”
然后在Window_Closing方法中添加
Application.Current.Shutdown();
这样,在主窗口关闭的时候,会关闭整个程序
PS:此方法不能关闭某些子线程,可以在此之前手动关闭,或者使用
Environment.Exit(0);
具体区别点我
子窗口关闭,直接窗口被删除了,而不是隐藏
解决办法:
还是Closing=“Window_Clising”
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
e.Cancel = true;
Hide();
}
键盘按键事件
Window控件有KeyDown、KeyUp、PreviewKeyDown、PreviewKeyUp
对我来说只用KeyDown事件就可以了
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyStates == Keyboard.GetKeyStates(Key.F2))
{
MenuItem_Click(Menu_NewGame, new RoutedEventArgs());
}
}
菜单与菜单点击事件
Xaml中的使用方式:
在Window标签下Grid中
<Menu Grid.Row="0" Background="White">
<MenuItem x:Name="Menu_Game" Header="游戏">
<MenuItem x:Name="Menu_NewGame" Header="新游戏(F2)" Click="MenuItem_Click"/>
<Separator />
<MenuItem x:Name="Menu_Statistics" Header="统计信息(F3)" Click="MenuItem_Click"/>
<MenuItem x:Name="Menu_Options" Header="选项(F4)" Click="MenuItem_Click"/>
<Separator />
<MenuItem x:Name="Menu_Exit" Header="退出(Alt + F4)" Click="MenuItem_Click"/>
</MenuItem>
<MenuItem x:Name="Menu_Help" Header="帮助">
<MenuItem x:Name="Menu_ViewHelp" Header="查看帮助(F1)" Click="MenuItem_Click"/>
<MenuItem x:Name="Menu_About" Header="关于扫雷" Click="MenuItem_Click"/>
</MenuItem>
</Menu>
Menu中每个MenuItem是一列,MenuItem中的MenuItem会点击展开。
是间隔线
效果如下图所示
菜单点击事件
我是根据MenuItem的名字属性区分点了哪个
private void MenuItem_Click(object sender, RoutedEventArgs e)
{
MenuItem menuItem = sender as MenuItem;
switch (menuItem.Name)
{
case "Menu_NewGame":
InitGame();
break;
}
}
内嵌图片到exe中
很多时候图片资源是需要后续动态调整的,而且由于图片比较大,内嵌到exe中会导致exe文件过大
但是对于不需要动态调整,并且图片很小(一堆图片甚至只有几k)的单机小程序来说,单独exe不带资源文件夹是最好用的。
1.先把图片或图片文件夹拖入解决方案下命名空间中
2.把所有图片的属性-生成操作-设置为Resource
如下图
使用方式:
ImageSource image = new BitmapImage(new Uri("pack://application:,,,/resources/mine.png"));
注意这个路径是绝对路径
窗口大小、图标、大小固定
1.窗口大小动态调整
代码直接设置Width和Height即可
2.窗口左上角的图标设置
this.Icon = new BitmapImage(new Uri("pack://application:,,,/resources/mine.png"));
3.大小固定
<Window ResizeMode="NoResize"></Window>
将字符串复制到剪切板
System.Windows.Clipboard.SetDataObject("https://blog.youkuaiyun.com/qq_40543071");
使用默认浏览器打开链接
using System.Diagnostics;
Process proc = new Process();
proc.StartInfo.FileName = "https://go.microsoft.com/fwlink/?LinkId=517009";
proc.Start();
程序所在目录,桌面路径,ApplicationData路径
1.程序所在目录
比如你的exe在D盘Project文件夹下,它会返回D:\Project
注意,结尾不带 \ 你可以自己加一个
System.Environment.CurrentDirectory
2.桌面路径
结尾也不带 \
Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory)
3.ApplicationData路径
运行程序本地数据存储目录之一,要么存这里,要么存exe旁边的文件夹
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
因为只是给了主文件夹,最好还是建一个自己程序的文件夹
Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/Mines_by_Cressfish"
4.创建文件夹
自定义的目录最开始可能不存在,所以新建一个
Directory在System.IO里
if (!Directory.Exists(sPath))
Directory.CreateDirectory(sPath);// 如果这个路径不存在-创建路径
5.由于我做的扫雷是单个exe,并且很小,所以仍桌面直接玩就行,但是本地存档就不知道放哪
放exe旁边是最好的,方便管理,但是在桌面就不合适了。所以判断一下
如果程序在桌面就放到ApplicationData路径里
默认是放exe旁边了
string strPath = Environment.CurrentDirectory + "/config.txt";
if (Environment.CurrentDirectory == Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory))
{
string sPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/Mines_by_Cressfish";
if (!Directory.Exists(sPath))
Directory.CreateDirectory(sPath);// 如果这个路径不存在-创建路径
strPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "/Mines_by_Cressfish/config.txt";
}
ListBox Item切换选中事件
<ListBox SelectionChanged="ListBox_SelectionChanged">
<ListBoxItem IsSelected="True" x:Name="listItem1">初级</ListBoxItem>
<ListBoxItem x:Name="listItem2">中级</ListBoxItem>
<ListBoxItem x:Name="listItem3">高级</ListBoxItem>
</ListBox>
当其中一个Item设置了IsSelected 的时候,在窗口加载的时候会默认选中
1.判断是否有Item被选中了,以及选中后更改背景高亮,获取选中Item的文字
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (ListBoxItem item in listBox.Items)
{
item.Background = Brushes.Transparent;//恢复默认颜色
}
if (listBox.SelectedItem != null)
{
ListBoxItem listBoxItem = listBox.SelectedItem as ListBoxItem;
listBoxItem.Background = Brushes.LightSkyBlue;
if ((string)listBoxItem.Content == "初级")
{
...
}
}
}
按钮鼠标悬浮效果更改,以及指定位置
1.鼠标悬浮效果更改
默认的效果会使Button上的图片直接被覆盖,看不到底图
在网上找了一个Style解决这个问题
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ChangeButtonIsMouseOver" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border" BorderThickness="0" BorderBrush="Black" Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Opacity" Value="0.55" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
使用方法:我的是动态生成Button
Style _btnStyle = new ResourceDictionary
{
Source = new Uri("ChangeButtonIsMouseOver.xaml", UriKind.RelativeOrAbsolute)
}["ChangeButtonIsMouseOver"] as Style;
Button button = new Button(){ Style = _btnStyle };
//这样也行
button.SetValue(StyleProperty, Application.Current.Resources["ChangeButtonIsMouseOver"]);
效果对比一下
这样就能看到底图是什么了。
2.动态设置Button位置
我本来以为直接设置就可以了,但是比我想象中麻烦
首先是需要把按钮放在Canvas下,Grid不行
<Canvas x:Name="Canvas_Game" Margin="15,20,15,25"> </Canvas>
动态设置位置的代码
i 是第几行,j是第几列,17是按钮本身大小(17*17)
btn.SetValue(Canvas.LeftProperty, j * 17.0 + 17);
btn.SetValue(Canvas.TopProperty, i * 17.0 + 17);
Canvas_Game.Children.Add(btn);//添加到Canvas里
动态给Button更换图片
这个Url是内嵌的图片路径
BitmapImage bitmapBlank = new BitmapImage();
bitmapBlank.BeginInit();
bitmapBlank.UriSource = new Uri("pack://application:,,,/resources/blank.png");
bitmapBlank.EndInit();
bitmapBlank.Freeze();
ImageBrush _btnBrush = new ImageBrush() { ImageSource = bitmapBlank };
button.Background = _btnBrush;
Button 左键点击,右键点击
事件:PreviewMouseLeftButtonDown、PreviewMouseRightButtonDown
MouseDown可以右键但是左键不行,不知道为什么
private void Btn_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
sender是点击的Button
XML存读取
存XML
//存
XmlDocument doc = new XmlDocument();
XmlDeclaration dec = doc.CreateXmlDeclaration("1.0", "utf-8", null);
doc.AppendChild(dec);
//创建根节点
XmlElement root = doc.CreateElement("root");
doc.AppendChild(root);
//创建节点-节点可以套节点
XmlElement easy = doc.CreateElement("Easy");
root.AppendChild(easy);// 添加到root节点里
XmlElement time = doc.CreateElement("time");
time.InnerText = "123456"; //<time>123456</time>
time.SetAttribute("name","xxx");//<time name="xxx">123456</time>
//SetAttribute可以有很多个,但是InnerText是唯一的
easy.AppendChild(time);// 添加到easy节点里
//........
doc.Save(strPath);//给他一个路径,比如D:\Mines\config.txt
读XML
XmlDocument doc = new XmlDocument();
//加载要读取的XML
doc.Load(strPath);
//获得根节点
XmlElement books = doc.DocumentElement;
//获得子节点 返回节点的集合。任何一个节点都可以获取其子节点的集合
XmlNodeList xnl = books.ChildNodes;
//foreach循环分析
foreach(XmlNode node in xnl)
{
if(node.Name == "Easy")
{
XmlNodeList easyList = node.ChildNodes;
foreach(XmlNode easyNode in easyList)
{
if(easyNode.Name == "time")
{
string strInnerText = easyNode.InnerText;
string strName = easyNode.Attributes["name"].Value;
//...
}
}
}
}
像是这样。
基本可以满足需求
子窗口访问 MainWindow
有时候我们需要做窗口之间交互,最简单的办法是MainWindow静态自己并开放出去
也就是单例
public static MainWindow mainWindow;
public MainWindow()
{
InitializeComponent();
// 单例指向自己
mainWindow = this;
}
虽然不安全,但确实是最简单,最方便的方法了。
至于主窗口访问其他窗口。
我是直接在主窗口类里声明子窗口类对象,需要用直接使用就好了。
C#计算百分比
忘了在哪找的了,但是很好用,可以自己更改结果格式,默认是"50%"字符串格式
// 获取百分比
public static string ExecPercent(decimal PassCount, decimal allCount, bool isBaiFenhao = true)
{
string res = "";
if (allCount > 0)
{
res = ChinaRound((double)Math.Round(PassCount / allCount * 100, 1), 0).ToString() + (isBaiFenhao ? "%" : "");
}
return res;
}
private static double ChinaRound(double value, int decimals)
{
if (value < 0)
{
return Math.Round(value + 5 / Math.Pow(10, decimals + 1), decimals, MidpointRounding.AwayFromZero);
}
else
{
return Math.Round(value, decimals, MidpointRounding.AwayFromZero);
}
}