Caliburn.Micro學習筆記目錄
說一下IHandle<T>實現多語言功能
因為Caliburn.Micro是基于MvvM的UI與codebehind分離,
binding可以是雙向的所以我們想動態的實現多語言切換很是方便今天我做一個小demo給大家提供一個思路
先看一下效果
點擊英文 變成英文狀態點chinese就會變成中文
源碼的下載地址在文章的最下邊
多語言用的是資源文件建一個MyLanguage的資源文件再添加一個MyLanguage.en-US的資源文件如果你還想要
其它的語言可自己添加。兩個資源文件里寫上你要的文本如下圖這樣,它們的名稱是一樣的只是值一個是中文一個是英文
下面我們就要開始用Caliburn.Micro的IHandle<T>去實現多語言了
先寫一個資源的接口
public interface IResource { string GetString(string name); CultureInfo CurrentCulture { set; } } public interface IResourceTask { void ChangeLanguage(string language); string GetString(string name); event EventHandler LanguageChanged; }IResource接口是資源要實現的,GetString(stirng name)方法是得到根據名字得到資源里的值CurrentCulture是中英文語言轉換的
ResourceTask接口是一個管理接口它管理資源的我們通過它去實現
語言轉換時把發送廣播把頁面上的所有文字轉換成想要的語言。
再寫一個簡單的信息接口,也就是我們發送廣播時的數據格式
public interface IMessage { } public class LanguageChangedMessage : IMessage { }LanguageChangedMessage就是我們要發送廣播的數據格式下面就來實現一下IResourceTask接口
public class ResourceTask : IResourceTask { public ResourceTask() { System.Data.DataTable _dt = new System.Data.DataTable(); } [ImportMany] public IResource[] Resources { get; set; } public void ChangeLanguage(string language) { CultureInfo culture = new CultureInfo(language); Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; Resources.Apply(item => item.CurrentCulture = culture); IEventAggregator eventAggregator = IoC.Get<IEventAggregator>(); eventAggregator.Publish(new LanguageChangedMessage()); if (LanguageChanged != null) { LanguageChanged(this, null); } } public event EventHandler LanguageChanged; public string GetString(string name) { string str = null; foreach (var resource in Resources) { str = resource.GetString(name); if (str != null) { break; } } return str; } }通過Resources得到所有export IResource的類
ChangeLanguage(string language)方法里的
Resources.Apply(item => item.CurrentCulture = culture);是把所有實現IResult類的CurrentCulture修改成我們要換成的語言格式
eventAggregator.Publish(new LanguageChangedMessage()); 就是去發送廣播,把頁面上所有的的文字切換
EventHandler LanguageChanged;事件是如果我們還想切換完語言后做一些事件就可以寫在這個事件里
再寫一個實現 IResult的類
[Export(typeof(IResource))] [PartCreationPolicy(CreationPolicy.NonShared)] public class MyResource : IResource { PRivate ResourceManager stringResource; private CultureInfo culture = new CultureInfo("zh-cn"); public CultureInfo CurrentCulture { get { return culture; } set { culture = value; } } public MyResource() { stringResource = new ResourceManager("WPFMultLanguage.Resource.MyLanguage", typeof(MyResource).Assembly); } public string GetString(string name) { return stringResource.GetString(name, culture); } }ResourceManager 可以對我們前邊寫的兩種語言的資源文件的讀寫
在類初始化的時候我們給出資源文件的路徑
在GetString(string name)里我們就可以通過ResourceManager根據當前的culture去讀取資源文件里的字符了
接下來的問題就是我們怎么去通過接收廣播把頁面上把文字切換
我們寫一個 XAML 標記擴展類
public class MyResourceExtension : MarkupExtension, INotifyPropertyChanged, IHandle<LanguageChangedMessage> { public string Key { get; set; } public string Value { get { if (Key == null) { return null; } IResourceTask result = IoC.Get<IResourceTask>(); string s = result.GetString(Key); return s; } } public MyResourceExtension() { if (!Execute.InDesignMode) { IoC.Get<IEventAggregator>().Subscribe(this); } } public event PropertyChangedEventHandler PropertyChanged; public void PropertyChanted() { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("Value")); } } public override object ProvideValue(IServiceProvider serviceProvider) { iprovideValueTarget target = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget; Binding binding = new Binding("Value") { Source = this, Mode = BindingMode.OneWay }; return binding.ProvideValue(serviceProvider) as BindingExpression; } public void Handle(LanguageChangedMessage message) { PropertyChanted(); } }這個類我們要實現MarkupExtension基類這樣我們才能把我們的類可以在xmal里標識出來
我們要重寫一下ProvideValue(IServiceProvider serviceProvider)方法這里我們是要把Value雙向綁定到頁面上
這個類實現了還INotifyPropertyChanged和IHandle<LanguageChangedMessage>接口
這兩個類能干什么我想你們應該都知道吧一個是用來binging的一個是用來接收消息的
Key就是我資源文件里的名稱項
value是資源文件里的值項看一下它的get也可以看來出是通過IResourceTask的getstring把值取出來
接口信息的方法Handle(LanguageChangedMessage message)
只要有消息過來我們就PropertyChanged Value值這樣就可以 把字符切換了,
我們再看一下前臺頁面是怎么處理的
<Window x:Class="WPFMultLanguage.Views.MyView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:WPFMultLanguage.Command" xmlns:cal="http://www.caliburnproject.org" cal:Message.Attach="[Event Loaded]=[Action LoadEvent($source)]" Title="MyView" Height="300" Width="300"> <StackPanel> <Menu> <MenuItem Header="{local:MyResource Key=英文}" cal:Message.Attach="[Event Click]=[Action ChanguageLanguage('en')]"></MenuItem> <MenuItem Header="{local:MyResource Key=中文}" cal:Message.Attach="[Event Click]=[Action ChanguageLanguage('zh')]"></MenuItem> </Menu> <TextBlock Text="{local:MyResource Key=語言}"/> <Button Content="{local:MyResource Key=你好}"/> <TextBox x:Name="tb_Show" Text="{local:MyResource Key=文本}"></TextBox> <TextBox x:Name="tb_Load" Text="{local:MyResource Key=文本2}"></TextBox> </StackPanel></Window>xmlns:local="clr-namespace:WPFMultLanguage.Command"
這樣是把我們上邊寫的的xaml擴展類放到頁面上 Header="{local:MyResource Key=英文}"
這樣每一個控件都會初始化一個MyResourceExtension類都會去訂閱IHandle<LanguageChangedMessage>廣播
再看一下viewModel
namespace WPFMultLanguage.ViewModels{ [Export(typeof(IShell))] public class MyViewModel :Screen { public MyViewModel() { } public void LoadEvent(object obj) { //var res = IoC.Get<IResourceTask>(); //((MyView)GetView()).tb_Load.Text = res.GetString("文本2"); } public void ChanguageLanguage(string lan) { var res = IoC.Get<IResourceTask>(); switch (lan) { case "zh": res.ChangeLanguage("zh-CN"); break; case "en": res.ChangeLanguage("en-US"); break; } } }}源碼:WPFMultLanguageDemo.rar
新聞熱點
疑難解答