WPF工作筆記:本地化支持、主進程通知、兩種最常用異步編程方式


1、本地化支持

(1)重寫控件默認的依賴屬性LanguageProperty

FrameworkElement.LanguageProperty.OverrideMetadata(
                typeof(FrameworkElement), new FrameworkPropertyMetadata(
                    XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

(2)在項目資源文件中添加Resources.resx,Resources.zh-CN.resx等等本地化字符串資源。

       文件中依次輸入Key-Value鍵值對,key相同,Value中輸入本地化語言字符串,如下所示

       

       

(3)在界面中引用資源文件所在命名空間。如:

xmlns:resc="clr-namespace:WpfApplication.Resources"

(4)引用字符串資源。如 :

<Button Content="{x:Static resc:Resources.Open}"/>

 

2、主進程通知

    在多文件支持和音視頻播放界面應用中,經常需要在外部通知主進程。比如您已經打開了酷狗音樂播放界面,在外部文件夾中,雙擊.mp3音樂文件,不會啟動第二個酷狗音樂播放界面,而是通知主窗口接收外部請求。下面給出一種實現方式:

    首先聲明WPF開發的系統只有一個入口,那就是Application類,也就是App.xaml

(1)App.xaml中不需要StartupUri,在后台啟動主窗口。首先在App.xaml.cs中定義事件句柄,用於通知主窗口

public static EventWaitHandle ProgramStarted;
private bool CreatedNew;

(2)App.xaml.cs重寫OnStartup,判斷是否需要新建主窗口

ProgramStarted = new EventWaitHandle(false, EventResetMode.AutoReset, "MyStartEvent", out CreatedNew);

    通過上面語句得到的CreatedNew值來決定是否需要創建主窗口,CreatedNew等於true時按一般情況聲明主窗口:

if (CreatedNew)
{
      MainWindow mainWin = new MainWindow();
      mainWin.Show();
}

(3)下面才是重點,在主窗口已經啟動的情況下,如何將外部的文件傳遞到主窗口去

     因為前面已經定義了事件句柄ProgramStarted,我們首先需要將外部文件寫入到一個本地文件或者注冊表中(名其為Global),已經啟動的窗口進程得到通知后,去讀取新建App進程寫入的內容。

     然后調用ProgramStarted.Set();Thread.Sleep(100);主窗口就可以得到通知。

(4)主窗口的線程池中需要注冊Wait請求:

    MainWindow.xaml.cs構造函數中:

ThreadPool.RegisterWaitForSingleObject(App.ProgramStarted, OnProgramStarted, null, -1, false);

    事件回調處理函數:

        /// <summary>
        /// 主進程在接收到其他進程通知后回調函數
        /// </summary>
        /// <param name="state"></param>
        /// <param name="timeout"></param>
        private void OnProgramStarted(object state, bool timeout)
        {
            Thread thread = new Thread(new ThreadStart(new Action(() =>
            {
                this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (System.Threading.ThreadStart)delegate()
                {
                    //處理Global
                });
            })));
            //因為是線程池通知主進程,必須在單線程單元ApartmentState.STA執行
            thread.SetApartmentState(ApartmentState.STA);
            thread.IsBackground = true;
            thread.Start();
        }

  注意上面代碼中使用了Dispatcher,只有WPF這樣使用,能夠訪問主窗口控件,因為主窗口控件所在的線程是主窗口,不能在新建的線程中調用,如果要使用,需要使用Dispatcher。

      默認Dispatcher執行的環境也是ApartmentState.STA,所以上面的代碼可以簡單為(只能在WPF中可以這樣使用):

        private void OnProgramStarted(object state, bool timeout)
        {
                this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (System.Threading.ThreadStart)delegate()
                {
                   //處理Global
                });
        }

 

3、兩種最常用異步編程

(1)DispatcherObject

            this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (ThreadStart)delegate()
            {
                // Simulate some work taking place.
                Thread.Sleep(TimeSpan.FromSeconds(5));
                btnContent.Text = "Here is some new text.";
            }
            );

(2)BackgroundWorker

BackgroundWorker是WPF異步編程經常使用的類,使用方式比較正規,很容易學會。

BackgroundWorker bgw = new BackgroundWorker();
bgw.WorkerSupportsCancellation = true;
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);
bgw.RunWorkerAsync(argument);

  

//bgw_DoWork不能直接使用主線程元素,只能通過e.Argument得到主線程傳過來的參數
private void bgw_DoWork(object sender, DoWorkEventArgs e)
{
    string argument= e.Argument.ToString();
    e.Result = new LongTimeFun(argument);
}

private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    MyObject  obj = e.Result as MyObject ;
    //這個時候才能使用主界面控件元素
}

private  MyObject LongTimeFun(string argument){

}

 簡單形式(Lambda語法):

BackgroundWorker bgw = new BackgroundWorker();
bgw.WorkerSupportsCancellation = true;
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler((sender, e) => {
         e.Result = new LongTimeFun(argument);
}); 
bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler((sender, e) => {
        MyObject  obj = e.Result as MyObject ;
});

(3)DispatcherObject和BackgroundWorker結合使用

    我們知道BackgroundWorker的DoWork事件回調事件中不能使用界面元素,但是在WPF中可以結合使用DispatcherObject、BackgroundWorker達到目的,

這樣就不需要BackgroundWorker的RunWorkerCompleted回調事件了。(這個幾乎在書本和其它技術資料中沒有介紹,但是很多時候是很有用的)

BackgroundWorker bgw = new BackgroundWorker();
bgw.WorkerSupportsCancellation = true;
bgw.WorkerReportsProgress = true;
bgw.DoWork += new DoWorkEventHandler((sender, e) =>
{
     this.Dispatcher.BeginInvoke(System.Windows.Threading.DispatcherPriority.Normal, (System.Threading.ThreadStart)delegate()
     {
           //這樣DoWork回調事件中可以使用主界面控件元素
     });
});
bgw.RunWorkerAsync();

 

4、滾動條內容設置可見

(1)使用FrameworkElement方法 BringIntoView

FrameworkElement.BringIntoView();

(2)ListBox

listbox.ScrollIntoView(listbox.Items[index]);

(3)Scrollviewer

scrollViewer.ScrollToVerticalOffset(VisualTreeHelper.GetOffset(VisualObject).Y);


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM