Popup.Placement属性受SystemParameters.MenuDropAlignment(该值指示弹出菜单相对于相应菜单项是左对齐仍是右对齐。)属性的影响,你能够这么设置:html
if (SystemParameters.MenuDropAlignment) { Popup.Placement = PlacementMode.Left; } else { Popup.Placement = PlacementMode.Right; }
ItemsControl有两个虚方法:app
protected override DependencyObject GetContainerForItemOverride() { //return new CustomListItem(); } protected override bool IsItemItsOwnContainerOverride(object item) { //return item is CustomListItem; }
顾名思义,这两个方法一个是判断有没有子项容器有没有被重写,一个是返回新的子项。你能够建立本身的ListBox,里面容纳本身的ListBoxItem,就像我上面那样(解掉两行注释)。ide
在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方法中调用。动画
看到这个问题你必定是以下设置吧:ui
<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不会显示。this
WPF4.5新增了System.Windows.Shell命名空间,这个命名空间已经集成在了x:命名空间下,因此你如今能够这么建立窗口:spa
<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线程
路由命令的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接口的类则会报“绑定的集合与源集合不一致”异常。
看代码:
void View_Loaded(object sender, RoutedEventArgs e) { if (this.tablesList.Items.CanSort) { //this.myitemsControl.Items.SortDescriptions.Add(new SortDescription("fiSortOrder", ListSortDirection.Ascending)); //this.myitemsControl.Items.SortDescriptions.Add(new SortDescription("fsMTableName", ListSortDirection.Ascending)); } }
其中"fiSortOrder"、"fsMTableName"是你的自定义Model(MVVM)中的属性字符串表示。
支持多列排序,升序逆序排序。
注意:排序性能较低,谨慎使用。
问9:带事件的对象序列化问题
看代码:
public class TestClass : INotifyPropertyChanged { //[field: NonSerialized] public event PropertyChangedEventHandler PropertyChanged; protected void RaisePropertyChanged(string propertyname) { PropertyChangedEventHandler handle = this.PropertyChanged; if (!string.IsNullOrEmpty(propertyname) && handle != null) { handle.Invoke(this, new PropertyChangedEventArgs(propertyname)); } } }
将不须要的序列化的字段标记为[NonSerialized],可是事件不是字段须要标记为[field: NonSerialized] 如代码第三行,解注释便可。
问10:Brush、Color、String的相互转换(本例为摘抄)
using System.Windows.Media;
一、String转换成Color
Color color = (Color)ColorConverter.ConvertFromString(string);
二、String转换成Brush
BrushConverter brushConverter = new BrushConverter();
Brush brush = (Brush)brushConverter.ConvertFromString(string);
三、Color转换成Brush
Brush brush = new SolidColorBrush(color));
四、Brush转换成Color有两种方法:
(1)先将Brush转成string,再转成Color。
Color color= (Color)ColorConverter.ConvertFromString(brush.ToString());
(2)将Brush转成SolidColorBrush,再取Color。
Color color= ((SolidColorBrush)CadColor.Background).Color;
问11:捕获应用程序内的全部异常,并保证程序不会中止工做
看代码:
/// <summary> /// App.xaml 的交互逻辑 /// </summary> public partial class App : Application { public App() { this.DispatcherUnhandledException += App_DispatcherUnhandledException; AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; } void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) { this.HandleException(e.ExceptionObject as Exception); } void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) { e.Handled = true; this.HandleException(e.Exception); } private void HandleException(Exception exception) { } }
处理UI线程中(即Dispatcher)的异常只须要注册App.DispatcherUnhandledException事件便可,在其事件处理程序中e.Handled = true;应用程序便不会中止工做。
对于非UI线程的异常须要注册AppDomain.CurrentDomain.UnhandledException事件,可是这个事件参数没有e.Handled参数,也就是说,只要非UI线程发生了异常只是通知你,该退出仍是要退出,有一个办法解决此问题:
配置文件添加:
<!--这里的legacyUnhandledExceptionPolicy,若是enabled=1的话,用意是使用早期版本的异常处理策略。应用程序不退出--> <runtime> <legacyUnhandledExceptionPolicy enabled="1" /> </runtime>
问12:获取当前可执行程序的所在目录
看到这个问题你的解决方法是什么?使用Environment.CurrentDirectory?这一般状况下不会有问题。对于该属性,MSDN解释为:Environment.CurrentDirectory
使用这个属性有一个问题须要注意:当你双击A.exe来启动A.exe时该属性正常工做。当你双击B.exe时在B.exe里面Process.Start(“A.exe”)时,若A.exe和B.exe不在同一目录下,在A.exe里面使用该属性时,会返回B.exe的路径,解决方法为:
/// <summary> /// 当前可执行程序集的彻底路径 /// </summary> public static readonly string STARTPATH = Assembly .GetExecutingAssembly() .Location; /// <summary> /// 当前执行程序集的所在目录 /// </summary> public static readonly string CURRENTDIRECTORY = Path.GetDirectoryName( Assembly .GetExecutingAssembly() .Location);
问13:程序设置当前计算机输入法(Winform、WPF)
WPF:
void MainWindow_Loaded(object sender, RoutedEventArgs e) { //检索本机安装的输入法 foreach (CultureInfo item in InputLanguageManager.Current.AvailableInputLanguages) { MessageBox.Show(item.DisplayName); } //将本机输入法设置为如下输入法之一 foreach (CultureInfo item in InputLanguageManager.Current.AvailableInputLanguages) { if (item.DisplayName.Contains("百度") || item.DisplayName.Contains("搜狗") || item.DisplayName.Contains("QQ") || item.DisplayName.Contains("谷歌")) { InputLanguageManager.Current.CurrentInputLanguage = item; return; } } //设置为一个中文输入法 foreach (CultureInfo item in InputLanguageManager.Current.AvailableInputLanguages) { if (item.Name.Equals("zh-CN", StringComparison.OrdinalIgnoreCase)) { InputLanguageManager.Current.CurrentInputLanguage = item; return; } } //设置为一个英文输入法 foreach (CultureInfo item in InputLanguageManager.Current.AvailableInputLanguages) { if (item.Name.Equals("en-US", StringComparison.OrdinalIgnoreCase)) { InputLanguageManager.Current.CurrentInputLanguage = item; return; } } }
WinForm:
using Winform = System.Windows.Forms; //设置四种输入法之一 foreach (Winform.InputLanguage item in Winform.InputLanguage.InstalledInputLanguages) { if (item.LayoutName.Contains("百度") || item.LayoutName.Contains("搜狗") || item.LayoutName.Contains("QQ") || item.LayoutName.Contains("谷歌")) { Winform.InputLanguage.CurrentInputLanguage = item; return; } } //设置一个中文输入法 Winform.InputLanguage zh_cnlanguage = Winform.InputLanguage.FromCulture(CultureInfo.GetCultureInfo("zh-CN")); if (zh_cnlanguage != null) { Winform.InputLanguage.CurrentInputLanguage = zh_cnlanguage; } //设置一个英文输入法 Winform.InputLanguage en_uslanguage = Winform.InputLanguage.FromCulture(CultureInfo.GetCultureInfo("en-US")); if (en_uslanguage != null) { Winform.InputLanguage.CurrentInputLanguage = en_uslanguage; }
问14:可翻页的ScrollViewer
自定义一个控件PageControl,将一个ScrollViewer放进去,再放四个Button,部好局。
控件代码经过如下代码找到放置的ScrollViewer和四个Button:
public override void OnApplyTemplate() { base.OnApplyTemplate(); _scrollViewer = GetTemplateChild(PART_SCROLL) as ScrollViewer; if (_scrollViewer == null) { throw new ClientException( "模板加载异常,缺乏模板元素。", ExceptionKind.TemplatePartNull, ExceptionLevel.General); } _scrollViewer.ScrollChanged += _scrollViewer_ScrollChanged; _btTop = GetTemplateChild("TopBt") as Button; _btBottom = GetTemplateChild("BottomBt") as Button; _btRight = GetTemplateChild("RightBt") as Button; _btLeft = GetTemplateChild("LeftBt") as Button; //其实就是调用ScrollViewer相应方法 if (_btTop != null) { _btTop.Click += (sender, e) => { this.PageUp(); }; } if (_btBottom != null) { _btBottom.Click += (sender, e) => { this.PageDown(); }; } if (_btRight != null) { _btRight.Click += (sender, e) => { this.PageRight(); }; } if (_btLeft != null) { _btLeft.Click += (sender, e) => { this.PageLeft(); }; } }
下面才是本例真正要讲述的东西:如何控制四个功能Button的状态及其可见性。
状态:
void _scrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e) { switch (this.PageButtonLocation) { //竖直 case PageButtonLocation.TopButtom: case PageButtonLocation.Top: case PageButtonLocation.Bottom: if (e.ExtentHeight <= this._scrollViewer.ViewportHeight) { this._btBottom.IsEnabled = false; this._btTop.IsEnabled = false; return; } if (e.VerticalOffset + this._scrollViewer.ViewportHeight == e.ExtentHeight) { this._btBottom.IsEnabled = false; } else { this._btBottom.IsEnabled = true; } if (e.VerticalOffset == 0) { this._btTop.IsEnabled = false; } else { this._btTop.IsEnabled = true; } break; //水平 case PageButtonLocation.LeftRight: case PageButtonLocation.Left: case PageButtonLocation.Right: if (e.ExtentWidth <= this._scrollViewer.ViewportWidth) { this._btLeft.IsEnabled = false; this._btRight.IsEnabled = false; return; } if (e.HorizontalOffset + this._scrollViewer.ViewportWidth == e.ExtentWidth) { this._btRight.IsEnabled = false; } else { this._btRight.IsEnabled = true; } if (e.HorizontalOffset == 0) { this._btLeft.IsEnabled = false; } else { this._btLeft.IsEnabled = true; } break; } }可见性(这个在XAML里面比较容易控制):
<ControlTemplate.Triggers> <!-- 控制Button可见性,成对按钮都禁用时才隐藏 --> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding ElementName=TopBt, Path=IsEnabled}" Value="False" /> <Condition Binding="{Binding ElementName=BottomBt, Path=IsEnabled}" Value="False" /> </MultiDataTrigger.Conditions> <Setter TargetName="TopBt" Property="Visibility" Value="Collapsed" /> <Setter TargetName="BottomBt" Property="Visibility" Value="Collapsed" /> </MultiDataTrigger> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding ElementName=LeftBt, Path=IsEnabled}" Value="False" /> <Condition Binding="{Binding ElementName=RightBt, Path=IsEnabled}" Value="False" /> </MultiDataTrigger.Conditions> <Setter TargetName="LeftBt" Property="Visibility" Value="Collapsed" /> <Setter TargetName="RightBt" Property="Visibility" Value="Collapsed" /> </MultiDataTrigger> </ControlTemplate.Triggers>
问15:XAML命名空间
持续更新中…