问一:Popup控件Placement属性设置固定值后,在不同的电脑可能有不同行为的问题
Popup.Placement属性受SystemParameters.MenuDropAlignment(该值指示弹出菜单相对于相应菜单项是左对齐还是右对齐。)属性的影响,你可以这么设置:
if (SystemParameters.MenuDropAlignment) { Popup.Placement = PlacementMode.Left; } else { Popup.Placement = PlacementMode.Right; }
问二:将ListBox的ItemsSource,Binding到List<String>为什么ListBox里面不是String列表而是ListBoxItem列表呢?
ItemsControl有两个虚方法:
protected override DependencyObject GetContainerForItemOverride() { //return new CustomListItem(); } protected override bool IsItemItsOwnContainerOverride(object item) { //return item is CustomListItem; }
顾名思义,这两个方法一个是判断有没有子项容器有没有被重写,一个是返回新的子项。你可以创建自己的ListBox,里面容纳自己的ListBoxItem,就像我上面那样(解掉两行注释)。
问三:如何以管理员身份启动应用程序?
在WPF项目添加应用程序清单文件app.manifest,找到如下所示的块:
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3"> <!-- UAC 清单选项 如果要更改 Windows 用户帐户控制级别,请用以下节点之一替换 requestedExecutionLevel 节点。 <requestedExecutionLevel level="requireAdministratorasInvoker" uiAccess="false" /> <requestedExecutionLevel level="requireAdministrator" uiAccess="false" /> <requestedExecutionLevel level="highestAvailable" uiAccess="false" /> 指定 requestedExecutionLevel 节点将会禁用文件和注册表虚拟化。 如果要利用文件和注册表虚拟化实现向后 兼容性,则删除 requestedExecutionLevel 节点。 --> <requestedExecutionLevel level="asInvoker" uiAccess="false" /> </requestedPrivileges>
将<requestedExecutionLevel level="asInvoker" uiAccess="false" />改为<requestedExecutionLevel level="requireAdministratorasInvoker" uiAccess="false" /> 即可,这里还有其他选项,不作赘述。
问四:应用程序启动后如何检查是否以管理员身份运行的?
/// <summary> /// 检查是否是管理员身份 /// </summary> private void CheckAdministrator() { var wi = WindowsIdentity.GetCurrent(); var wp = new WindowsPrincipal(wi); bool runAsAdmin = wp.IsInRole(WindowsBuiltInRole.Administrator); if (!runAsAdmin) { // It is not possible to launch a ClickOnce app as administrator directly, // so instead we launch the app as administrator in a new process. var processInfo = new ProcessStartInfo(Assembly.GetExecutingAssembly().CodeBase); // The following properties run the new process as administrator processInfo.UseShellExecute = true; processInfo.Verb = "runas"; // Start the new process try { Process.Start(processInfo); } catch (Exception ex) { logger.Info(ex); } // Shut down the current process Environment.Exit(0); } }
在App构造函数或者App.OnStartup方法中调用。
问五:WPF无边框阴影窗口
看到这个问题你一定是如下设置吧:
<Window x:Class="WPFTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="525" Height="350" AllowsTransparency="True" Background="Transparent" WindowStyle="None"> <Grid Margin="10" Background="White"> <Grid.Effect> <DropShadowEffect BlurRadius="10" ShadowDepth="0" /> </Grid.Effect> </Grid> </Window>
这样设置可以,但是窗体启动慢、性能低、不能拖动、不能拖改尺寸、不跟随系统窗口动画(最大化最小化时动态拉伸窗口)、没有窗体系统功能,另外你若这样设置窗口,窗口里面如果还有一个WebBrowser,那么这个WebBrowser不会显示。
WPF4.5新增了System.Windows.Shell命名空间,这个命名空间已经集成在了x:命名空间下,所以你现在可以这么创建窗口:
<Window x:Class="WPFTest.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Width="525" Height="350"> <WindowChrome.WindowChrome> <WindowChrome CaptionHeight="30" CornerRadius="0" GlassFrameThickness="1" NonClientFrameEdges="None" ResizeBorderThickness="5" UseAeroCaptionButtons="False" /> </WindowChrome.WindowChrome> <Grid /> </Window>
关于WindowChrome类,查阅MSDN在线文档:WindowChrome
问六:WPF路由命令的可用状态不能及时刷新到UI控件的问题
路由命令的CanExecute事件并不是不停的“投石问路”的。路由命令处于性能考虑在窗体是激活状态的时候才会不停地“投石问路”,但有时候也是会出现不触发的情况,这个时候你需要点击一下窗体其他地方,触发一下焦点切换,才会再次执行CanExecute事件。如何避免这个问题,而让WPF始终不停地“投石问路”呢?
static ControlCommands() { DispatcherTimer dt = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(500) }; dt.Tick += (sender, e) => { //强制 System.Windows.Input.CommandManager 引发 System.Windows.Input.CommandManager.RequerySuggested事件 CommandManager.InvalidateRequerySuggested(); }; dt.Start(); }
使用Tick里面的代码强制路由命令执行CanExecute事件。
问七:属性的更改通知、集合的更改通知
属性的更改通知要实现INotifyPropertyChanged接口,如:
public class MyClass : INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyname) { PropertyChangedEventHandler handle = this.PropertyChanged; if (!string.IsNullOrEmpty(propertyname) && handle != null) { handle.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } public string Property1 { get { return this.Property1; } set { this.Property1 = value; this.RaisePropertyChanged("Property1"); } } }
这样Property1属性就具备了更改通知的功能(在WPFUI中绑定此属性时)。
集合的更改通知要实现INotifyCollectionChanged接口,WPF本身只提供了一个这样的接口就是System.Collections.ObjectModel.ObservableCollection<T>类,ItemsControl的ItemsSource属性绑定到该类时,对该类进行的添加等操作会及时的更新到UI上,而不实现INotifyCollectionChanged接口的类则会报“绑定的集合与源集合不一致”异常。
第一次写博,欢迎大家批评指正。
持续更新中…