【Win 10 應用開發】在代碼中載入文本資源

來源:互聯網
上載者:User

標籤:輸入   檔案名稱   標記   維修   執行個體   return   family   direct   有一個   

記得前一次,老周給大夥,不,小夥伴們介紹了如何填寫 .resw 檔案,並且在 XAML 中使用 x:Uid 標記來載入。也順便給大伙兒分析了運行時是如何解析 .resw 檔案的。

本來說好了,後續老周會寫一篇關於如何在代碼裡面手動載入文本資源的博文,但一直拖到今天,因為老周前陣子在忙著開發自己的 UWP app,已經嚮應用商店提交了一個版本,昨天剛提交完一次更新。

好,今天咱們就聊聊代碼載入文本資源的事情。

在 XAML 中使用 uid 載入資源雖然方便,但是它有個缺點——不同控制項有不同的屬性,有時候不太方便匹配,當然了,如果你的資源所針對的控制項類型不多,那是無所謂的。

為了彌補 uid 載入的不足,我們完全可以自己來編寫資源載入代碼。這種做法向來是老周慣用的。大家應該還記得當年的 WinForm 應用吧,它也是可以在設計器中直接翻譯和編輯資源的(.resx),然後 VS 會幫我們產生一個管理資源的類。

在實際開發中,老周一向不用這一招的,一般是自己寫資源類的,這樣很靈活,可以自由控制,再讓資源類公開一些屬性,然後與 UI 進行綁定即可。在WPF中老周並沒有開發過多語言的應用,所以沒怎麼去弄。

同樣的道理,在UWP應用中我們也照樣可以自己去封裝,然後與 UI 綁定即可,這樣自己管理起來也方便,而且可以同時用於 XAML 與非 XAML 代碼上。故,還是很有意義的。有時候,多折騰一下也是好的,愛折騰的人生更精彩。所以,去年春天老周學 PR,夏天學AE,秋天學CAD,冬天學葫蘆絲。今年過年時學單反相機,清明節後學巴烏,勞動節後學電器維修,請在瓦斯公司工作的同學教我安裝燃氣灶,七月份學陶笛,九月份去看老師傅做絲綢卷畫,十月份臨摹柳公權的《玄秘塔碑》。

人一旦有事情可做,就不會胡思亂想了。

 

下面老周示範一個例子。

項目中放兩個資源檔,一個是英文資源,一個是中文資源。

 

在中文資源中,輸入以下三項內容。

 

在英文資源中,輸入以下三項。

 

 

資源準備完成後,咱們開始封裝。其實,在UWP中,載入資源有個很NND簡單的方法,就是用 Windows.ApplicationModel.Resources 命名空間下的 

ResourceLoader 類。這個類很好用,調用靜態 GetForCurrentView 方法就能得到一個執行個體,然後用 GetString 方法就可以載入到字串資源了。

注意,GetForCurrentView 方法有兩個重載,一個是帶參數的,參數指定你的.resw 檔案名稱,不帶路徑和副檔名,這個在前一篇鳥文中老周介紹過的,比如,本例中,資源檔為 Goods.<language tag>.resw,所以傳遞的參數就是 Goods。另一個是不帶參數的 GetForCurrentView方法,如果調用這個版本的重載,那麼,你的 .resw 檔案必須命名為 Resources.resw,如 Resources.lang-zh-cn.resw,Resources.lang-zh-tw.resw 等。

 

先看看封裝好的類。

    public class ResourcesItems : INotifyPropertyChanged    {        static readonly ResourcesItems mInstance = new ResourcesItems();        public static ResourcesItems Current { get { return mInstance; } }        private ResourcesItems()        {            // 構造時載入一下,填充預設值            Load();        }        public event PropertyChangedEventHandler PropertyChanged;        private void OnPropertyChanged(string propname)        {            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));        }        public void Load()        {            var loader = ResourceLoader.GetForCurrentView("Goods");            Item1 = loader.GetString("t1");            Item2 = loader.GetString("t2");            Item3 = loader.GetString("t3");        }        #region 屬性        string _it1, _it2, _it3;        public string Item1        {            get { return _it1; }            set            {                if (value != _it1)                {                    _it1 = value;                    OnPropertyChanged(nameof(Item1));                }            }        }        public string Item2        {            get { return _it2; }            set            {                if (_it2 != value)                {                    _it2 = value;                    OnPropertyChanged(nameof(Item2));                }            }        }        public string Item3        {            get { return _it3; }            set            {                if (_it3 != value)                {                    _it3 = value;                    OnPropertyChanged(nameof(Item3));                }            }        }        #endregion    }

 

這裡我用 Item1、Item2和 Item3 三個屬性分別對應資源檔中的三個項。實現 INotifyPropertyChanged 介面是很有劃時代戰略意義的,這樣當語言改變時,從資源檔中重新載入文本時,UI 上的綁定可以即時獲得最新的值。

在 99.99986% 的應用情境中,我們只需要執行個體化一次資源類就行了,所以,保持它在應用生命週期中只有一個執行個體即可,沒必要建立那麼執行個體,浪費食物鏈資源。故而可以把建構函式私人化,然後用一個靜態、唯讀屬性來公開當前類的執行個體。即

        static readonly ResourcesItems mInstance = new ResourcesItems();        public static ResourcesItems Current { get { return mInstance; } }

 

這個類可以公開一個方法,讓外部調用,來載入資源。

        public void Load()        {            var loader = ResourceLoader.GetForCurrentView("Goods");            Item1 = loader.GetString("t1");            Item2 = loader.GetString("t2");            Item3 = loader.GetString("t3");        }

 

回到應用程式頁面類,比如項目模板產生的 MainPage 類,把這個資源管理類作為一個屬性公開一下。

        ResourcesItems TheRes        {            get { return ResourcesItems.Current; }        }

有人會說,老周,你幹嗎這麼多此一舉?因為待會兒我要用 x:Bind 來綁定,但是,XAML 編譯有個“八阿哥”,當你用x:Bind間接綁到執行個體上時,會發生編譯錯誤。據說在今年 7 月份時,SDKTeam Dev已收到這個問題報告,將來會修複的。反正秋季更新1709,16299 中還沒修複。

就是,如果你這樣綁定會出錯。

<Pig Head = "{x:Bind ResourceItems.Current.Item1}" ... />

所以,為了避開這個缺陷,可以在頁面類中封一下,然後我們可以把 x bind 的源指向頁面類的這個屬性,這樣就不會報錯了。

   <TextBlock>       <Run Text="{x:Bind TheRes.Item1,Mode=OneWay}" FontSize="16" Foreground="Blue"/>       <Run Text="{x:Bind TheRes.Item2,Mode=OneWay}" FontSize="16" Foreground="Red"/>       <Run Text="{x:Bind TheRes.Item3,Mode=OneWay}" FontSize="16" Foreground="DarkBlue"/>    </TextBlock>

 

這樣綁定之後,我們就可以在代碼中即時修改應用程式的語言,然後再讓剛剛封裝的資源類重新載入文本就行了。

這裡,刻意封裝了一個方法,用改應用程式的當前語言。

        private void SetLang(string lang)        {            var context = Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView();            var qs = context.QualifierValues;            // 這樣也可以修改當前應用的語言            qs["Language"] = lang;        }

ResourceContext 負責應用內容相關的資源設定,其中,我們有兩個辦法來改語言,一個是改  Languages 屬性,注意它是個列表,也就是說你可以同時設定一串語言群組合,預設應用的應該是列表中的第一個(提前是它與當前 Win 10 系統的語言相同)。

不過,我選擇用第二種方法,就是從 QualifierValues 屬性中獲得一個字典,這個字典裡面的條目是用於描述當前應用程式資源的限定符,Key 是限定符名稱,Value 當然是對應的值。啥是限定符呢。比如當前應用的語言,螢幕縮放比例,是否高對比,是否旋轉螢幕等。

你如果好奇裡面有些啥玩意兒,可以用以下代碼來輸出一下。

#if DEBUG            var strbd = new System.Text.StringBuilder();            foreach (var item in qs)            {                string ts = $"{item.Key} = {item.Value}";                strbd.AppendLine(ts);            }            System.Diagnostics.Debug.WriteLine($"\n\n{strbd}\n\n");#endif

 

然後你會看到類似以下這樣的輸出。

Language = zh-cn
Contrast = standard
Scale = 100
HomeRegion = CN
TargetSize =
LayoutDirection = LTR
Theme = dark
AlternateForm =
DXFeatureLevel =
Configuration =
DeviceFamily = Desktop
Custom =

看到以上輸出,你懂了吧。如果還不懂,那撞牆吧。

 

我們這裡只需要改 Language 的值就行了。所以

            var qs = context.QualifierValues;            // 這樣也可以修改當前應用的語言            qs["Language"] = lang;

 

於是,有人肯定又問老周了,老周你是不是失憶了?上一篇中你不是介紹了一個 Windows.Globalization.ApplicationLanguages 類嗎,裡面只要改一下 PrimaryLanguageOverride 屬性就可以了。對的,那個屬性確實爽用,一行程式碼完成。但是,那個屬性只適合於非即時更改,就是,可能只是應用運行時,或者使用者在設定時改一下。因為那個屬性修改了以後,不會馬上生效的,可能要等 3 秒鐘後才會重新整理,除非你故意讓程式卡 3 秒鐘。不然的話,你要是想讓切換語言馬上生效,就要改資源限定符了。改限定符 Language 是很管用的,一改就靈,即時重新整理。

 

好了,大功告成,看看效果如何。

 

樣本原始碼

OK,今天的文章就寫到這裡了,改天有新的發現,老周會及時分享。我現在是越來越喜歡 UWP app了,效能高,能夠很好適應高分屏,以及各操作方式,最重要的是它安全。

 

【Win 10 應用開發】在代碼中載入文本資源

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.