zoukankan      html  css  js  c++  java
  • 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);
  • 相关阅读:
    5. java 的类和对象
    java 的变量以及构造方法
    idea运行Test时为啥会运行两次
    MYSQL(三)
    MYSQL(二)
    MySql密码操作
    MYSQL(一)
    【数据结构】2.线性表及其结构
    【数据结构】1.数据结构及算法的入门
    推荐四款可视化工具,解决99%的可视化大屏需求
  • 原文地址:https://www.cnblogs.com/wangnmhb/p/4078663.html
Copyright © 2011-2022 走看看