转自 林德熙Bloghtml
本文:我遇到的WPF的坑git
目录github
若是使用NamedPipeServerStream、Mutex
作单实例,须要传入字符串,这时若是传入一个固定的字符串,会在多用户的时候没法使用。c#
由于若是在一个用户启动的软件,那么就注册了这个字符串,在另外一个用户就没法启动。解决方法是传入Environment.UserName
。windows
在构造函数传入Environment.UserName
有关的字符串就能够在一个用户进行单例,其余用户打开是本身的软件。api
public partial class App { #region Constants and Fields /// <summary>The event mutex name.</summary> private const string UniqueEventName = "{GUID}"; /// <summary>The unique mutex name.</summary> private const string UniqueMutexName = "{GUID}"; //这里须要加 Environment.UserName /// <summary>The event wait handle.</summary> private EventWaitHandle eventWaitHandle; /// <summary>The mutex.</summary> private Mutex mutex; #endregion #region Methods /// <summary>The app on startup.</summary> /// <param name="sender">The sender.</param> /// <param name="e">The e.</param> private void AppOnStartup(object sender, StartupEventArgs e) { bool isOwned; this.mutex = new Mutex(true, UniqueMutexName, out isOwned); this.eventWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset, UniqueEventName); // So, R# would not give a warning that this variable is not used. GC.KeepAlive(this.mutex); if (isOwned) { // Spawn a thread which will be waiting for our event var thread = new Thread( () => { while (this.eventWaitHandle.WaitOne()) { Current.Dispatcher.BeginInvoke( (Action)(() => ((MainWindow)Current.MainWindow).BringToForeground())); } }); // It is important mark it as background otherwise it will prevent app from exiting. thread.IsBackground = true; thread.Start(); return; } // Notify other instance so it could bring itself to foreground. this.eventWaitHandle.Set(); // Terminate this instance. this.Shutdown(); } #endregion }
使用 UsedImplicitly 特性能够标记一个没有被引用的方法为反射使用,这时就不会被优化删除。app
public class Foo { [UsedImplicitly] public Foo() { //反射调用 } public Foo(string str) { //被引用 } }
设置ToolTipService.ShowOnDisabled
为 true函数
<Button ToolTipService.ShowOnDisabled="True">
经过 WinForms 方法获取post
System.Windows.Forms.Screen.AllScreens
上面就能够拿到全部的屏幕,经过 Count 方法就能够知道有多少屏幕优化
var screenCount = Screen.AllScreens.Length;
在 WPF 找到当前登录的用户使用下面代码
using System.Security.Principal; // 其余代码 WindowsIdentity windowsIdentity = WindowsIdentity.GetCurrent(); string crentUserAd = windowsIdentity.Name;
输出 crentUserAd
能够看到 设备\\用户
的格式
在 WPF 的 xaml 能够经过 x:Static
绑定资源,可是要求资源文件里面的对应资源设置访问为公开
若是没有设置那么将会在 xaml 运行的时候提示
System.Windows.Markup.XamlParseException 在 System.Windows.Markup.StaticExtension 上提供值xxx
此时在设计器里面是能够看到绑定成功,只是在运行的时候提示找不到,展开能够看到下面提示
没法将 xx.Properties.Resources.xx StaticExtension 值解析为枚举、静态字段或静态属性
解决方法是在 Resource.resx 里面的访问权限从 internal 修改成 public 就能够
引用命名空间,复制下面代码,而后调用 IsAdministrator 方法,若是返回 true 就是使用管理员权限运行
using System.Security.Principal; public static bool IsAdministrator() { WindowsIdentity current = WindowsIdentity.GetCurrent(); WindowsPrincipal windowsPrincipal = new WindowsPrincipal(current); //WindowsBuiltInRole能够枚举出不少权限,例如系统用户、User、Guest等等 return windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator); }
C# 判断软件是不是管理员权限运行 - 除却猩猩不是猿 - CSDN博客
若是须要注册一个类型的全局事件,如拿到 TextBox 的全局输入,那么可使用下面代码
EventManager.RegisterClassHandler(typeof(TextBox), TextBox.KeyDownEvent, new RoutedEventHandler(方法));
若是在一个 .net 4.0 的 WPF 程序引用一个 .net 2.0 的库,那么就会让程序没法运行,解决方法添加useLegacyV2RuntimeActivationPolicy
打开 app.config 添加 useLegacyV2RuntimeActivationPolicy="true"
在 startup 元素
下面是 app.config 代码
<?xml version="1.0" encoding="utf-8"?> <configuration> <startup useLegacyV2RuntimeActivationPolicy="true"> <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> </startup> </configuration>
参见:WPF 软件引用其余类库启动无反应问题 - 灰色年华 - CSDN博客
若是有一个 C++ 写的dll,他须要一个函数指针,在C#使用,就能够传入委托。
那么简单的方法是这样写:
private static void Func(){} public void C() { c(Func); }
其中c就是C++写的函数,传进去看起来好像正常。
可是有时候程序不知道怎么就炸了。
由于这样写是不对的。
传入的不是函数地址,传入的是把函数隐式转换委托,而后转换的委托是局部变量,会被gc,因此在C++拿到的是一个被回收的委托,调用时就会炸。
这里没法用catch,因此用这个会让程序退出。
调用C#的函数,使用委托,是隐式转换,上面代码能够写成下面的
private static void Func(){} public void C() { var temp = new delegate(){ Func }; c(temp); }
因而在函数完就把temp放到gc在调用时找不到委托。
一个好的作法
private static void Func(){} private delegate Temp { get; } = new delegate(){Func}; private void C() { c(Temp); }
放在静态变量不会gc调用不会空,能够这样不会出现上面问题。
元素可使用 CaptureMouse 方法得到,这能够用在拖动,一旦拖动出元素能够得到,获得拖动结束。
可是有时会失去得到,若是本身须要失去,可使用 Mouse.Capture(null) 可是在没有本身使用的这个函数,失去得到,能够的是:
设置元素可命中false,若是看到元素失去交互,并且堆栈没有任何地方使用失去得到,那么可能就是存在设置元素可命中false。
若是有两个函数同时 得到 一个元素,会不会出现 失去得到?不会,若是同一个元素屡次 得到,那么不会出现失去得到。若是这是让另外一个得到,那么这个元素就是失去得到。能够经过元素.IsMouseCaptured 判断元素得到。
能够经过 Mouse.Captured 得到如今 Mouse 是否得到。若是返回是 null ,没有得到,可是元素得到存在一些问题,在失去焦点或其余,可能就失去得到。
CaptureMouse/CaptureStylus 可能会失败 - walterlv
这是比较难以说明的问题,总之,可能出现的问题就是引用了一个 xaml 使用的资源库,或使用了一个只有反射才访问的库。
缘由: 若是在引用一个库,引用代码没有直接使用的程序集。使用的方法就是使用 xaml 或反射来使用。那么在生成,vs 不会把程序集放在输出文件夹。
问题: 反射报错,没法找到程序集。
例子: 若是我用了一个程序集,然而代码没有直接引用,而是反射使用,这样,vs判断这个程序集没有使用,最后把他清除。因此会出现反射没法拿到,并且很难知道这里出现坑。
为了解决 xaml 和反射没法拿到的坑,可使用 在任意位置使用 Debug.Write(typeof(程序集里的一个类)) 方法让 vs 引用程序集。
那么在 Release 上为什么还能够把程序集放在输出文件夹呢?由于我也不知道缘由,若是你知道的话,那么请告诉我一下。
在 xaml 若是须要使用 十进制设置颜色,请使用下面代码
<SolidColorBrush x:Key="LikeGreen"> <SolidColorBrush.Color> <Color R="100" G="200" B="30" A="100"/> </SolidColorBrush.Color> </SolidColorBrush>
https://stackoverflow.com/a/47952098/6116637
能够设置一些文件是隐藏文件,那么 WPF 如何判断 FileInfo 是隐藏文件?
简单的代码,经过判断 Attributes 就能够获得,请看下面。
file.Attributes.HasFlag(FileAttributes.Hidden)
触发鼠标点下事件,可使用下面代码
element.RaiseEvent(new MouseEventArgs(Mouse.PrimaryDevice, 1) { RoutedEvent = Mouse.MouseDownEvent });
使用
就能够换行
win10 uwp 在 xaml 让 TextBlock 换行
若是一个索引须要传入空格,那么在 xaml 使用下面代码是没法绑定
{Binding MyCollection[foo bar]}
须要使用下面代码
{Binding MyCollection[[foo&x20;bar]]}
Binding to an index with space in XAML – Ivan Krivyakov
在有时候使用 Task 的 Delay 以后想要返回主线程,可使用 ContinueWith 的方法,请看代码
Task.Delay(TimeSpan.FromSeconds(5)).ContinueWith ( _ => Foo() // 若是 Foo 不须要在主线程,请注释下面一段代码 , TaskScheduler.FromCurrentSynchronizationContext() );
核心是 TaskScheduler.FromCurrentSynchronizationContext 方法
若是 Foo 不须要在主线程,就能够删除 TaskScheduler.FromCurrentSynchronizationContext 代码
{Binding datetime,StringFormat='{}{0:yyyy年MM月dd日 dddd HH:mm:ss}',ConverterCulture=zh-CN}
指定ConverterCulture为zh-CN后星期就显示为中文了。
参见:http://www.cnblogs.com/xjt927/p/5317678.html
经过在窗口添加下面代码
ResizeMode="NoResize"
窗口就剩下一个关闭同时用户也没法拖动修改窗口大小
在一个按钮点击的时候全选 TextBox 的内容,能够在按钮里面调用 SelectAll 方法
textBox.SelectAll();
上面代码的 textBox 就是界面写的 TextBox 元素
若是发现调用上面的代码 TextBox 没有全选,多是 TextBox 没有拿到焦点,能够尝试下面代码
textBox.Focus(); textBox.SelectAll();
经过 SystemParameters.CaretWidth
获取宽度
var caretWidth = SystemParameters.CaretWidth;
详细请看 SystemParameters.CaretWidth Property