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命名空間
持續更新中…