zoukankan      html  css  js  c++  java
  • [Silverlight]MVVM+MEF框架Jounce学习(2):标记和绑定

    这一部分主要讲解如何绑定View和View Model。

     IApplicationService接口

    Jounce实现了 IApplicationService接口,作为一个服务插入到Silverlight应用程序的生命周期。这样,Jounce就有机会在silverlight应用程序开始、结束或者出现未处理的异常时,接管程序的执行。使用Jounce框架的应用程序,App.xaml必须这样定义:

    <Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:Services="clr-namespace:Jounce.Framework.Services;assembly=Jounce"
                 x:Class="SilverlightApplication.App"
                 >
        <Application.Resources>
            
        </Application.Resources>
        <Application.ApplicationLifetimeObjects>
            <Services:ApplicationService IgnoreUnhandledExceptions="False" LogSeverityLevel="Verbose"/>
        </Application.ApplicationLifetimeObjects>
    </Application>

    StartService方法

    当应用程序启动时,自动调用IApplicationService接口的StartService方法:

    public void StartService(ApplicationServiceContext context)
    {
                var logLevel = LogSeverityLevel;
    
                if (context.ApplicationInitParams.ContainsKey(Constants.INIT_PARAM_LOGLEVEL))
                {
                    logLevel =
                        (LogSeverity)
                        Enum.Parse(typeof (LogSeverity), context.ApplicationInitParams[Constants.INIT_PARAM_LOGLEVEL], true);
                }
    
                _mainCatalog = new AggregateCatalog(new DeploymentCatalog());
    
                _container = new CompositionContainer(_mainCatalog);
                
                CompositionHost.Initialize(_container);
                CompositionInitializer.SatisfyImports(this);
    
                if (Logger == null)
                {
                    ILogger defaultLogger = new DefaultLogger(logLevel);
                    _container.ComposeExportedValue(defaultLogger);
                }
                else
                {
                    Logger.SetSeverity(logLevel);
                }
    
                DeploymentService.Catalog = _mainCatalog;
                DeploymentService.Container = _container;
                _mefDebugger = new MefDebugger(_container, Logger);
    }

    这里,Jounce主要做了这么几件事情:
    设置默认的日志级别,你也可以通过以下方式制定某一日志级别:

    <object data="data:application/x-silverlight-2," type="application/x-silverlight-2" width="100%" height="100%">
        <param name="initParams" value="Jounce.LogLevel=Verbose" />
    </object>

    Jounce为当前程序集定义了一个默认的部署类别DeploymentCatalog(Jounce可以为不同的XAP定义不同的部署类别)。

    定义了一个ILogger对象的导入:

    [Import(AllowDefault = true, AllowRecomposition = true)]
    public ILogger Logger { get; set; }

    AllowDefault告诉MEF这个导入不是一定要满足的,允许为null。如果你实现并导出了自己的ILogger对象,会满足这个导入条件;如果没有定义,Jounce使用一个默认的DefaultLogger。这个默认的logger会将日志写到调试窗口,MefDebugger使用此日志对象,输出一些Jounce日志,让我们可以跟踪Jounce做了什么。当View和ViewModel不能按我们预想的绑定时,查看这些日志会很有帮助。看一看MefDebugger的源代码,会对我们理解MEF的如何工作很有帮助。

    MEF: Found part: SilverlightApplication.ViewModels.MainViewModel
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::    With import: Jounce.Core.ViewModel.BaseViewModel.EventAggregator (ContractName="Jounce.Core.Event.IEventAggregator")
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::    With import: Jounce.Core.ViewModel.BaseViewModel.Router (ContractName="Jounce.Core.ViewModel.IViewModelRouter")
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::    With import: Jounce.Core.ViewModel.BaseViewModel.Logger (ContractName="Jounce.Core.Application.ILogger")
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::    With export: SilverlightApplication.ViewModels.MainViewModel (ContractName="Jounce.Core.ViewModel.IViewModel")
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::       With key: ViewModelType = SilverlightApplication.ViewModels.MainViewModel
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::       With key: ExportTypeIdentity = Jounce.Core.ViewModel.IViewModel
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::    With export: SilverlightApplication.ViewModels.MainViewModel (ContractName="Jounce.Core.ViewModel.IViewModel")
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::       With key: ViewModelType = SilverlightApplication.ViewModels.MainViewModel
    2012/11/29 10:25:46 Verbose Jounce.Core.MefDebugger ::       With key: ExportTypeIdentity = Jounce.Core.ViewModel.IViewModel

    Starting方法

    另一个重要的事件是Starting,在visual tree完全激活之前调用。

    public void Starting()
    {
                if (!IgnoreUnhandledExceptions)
                {
                    Application.Current.UnhandledException += _CurrentUnhandledException;
                }
    
                var viewInfo = (from v in Views where v.Metadata.IsShell select v).FirstOrDefault();
    
                if (viewInfo == null)
                {
                    var grid = new Grid();
                    var tb = new TextBlock
                                 {
                                     Text = Resources.ApplicationService_Starting_Jounce_Error_No_view
                                 };
                    grid.Children.Add(tb);
                    Application.Current.RootVisual = grid;
                    Logger.Log(LogSeverity.Critical, GetType().FullName, Resources.ApplicationService_Starting_Jounce_Error_No_view);
                    return;
                }
    
                Application.Current.RootVisual = viewInfo.Value;
                Logger.LogFormat(LogSeverity.Information, GetType().FullName,Resources.ApplicationService_Starting_ShellResolved, MethodBase.GetCurrentMethod().Name,
                                 viewInfo.Value.GetType().FullName);
                Logger.Log(LogSeverity.Information, GetType().FullName, MethodBase.GetCurrentMethod().Name);            
    
                EventAggregator.Publish(viewInfo.Metadata.ExportedViewType.AsViewNavigationArgs());
            }

    Jounce捕捉未处理的异常,并用事件聚合发布异常,令我们的代码可以容易的订阅并处理他们。Jounce只可以标记一个View作为Shell,这个View将作为应用程序的root visual。如果找不到shell,Jounce会抛出异常。

    所有的View元数据会被导入到ApplicationService对象中:

     [ImportMany(AllowRecomposition = true)]
     public Lazy<UserControl, IExportAsViewMetadata>[] Views { get; set; }

    然后,Jounce记录一些消息并触发一个导航事件,Jounce导航到根视图,并绑定到视图模型。

    标记View和View Model

    如何标记Shell根视图:

    [ExportAsView("Welcome",IsShell = true)]
    public partial class Welcome
    {
        public Welcome()
        {
            InitializeComponent();            
        }
    }

    标记View和ViewModel很灵活,可以像上面那样使用字符串(名称必须唯一),也可以使用强类型标记。ViewModel这样标记:

    [ExportAsViewModel("Welcome")]
    public class WelcomeViewModel : BaseViewModel 
    {
        public WelcomeViewModel()
        {
            Title = "Welcome to Jounce!";            
        }
    
        private string _title;
    
        public string Title
        {
            get { return _title; }
            set
            {
                _title = value;
                RaisePropertyChanged(()=>Title);
            }
        }
    
        public override void _Activate(string viewName)
        {            
            GoToVisualState("WelcomeState",true);
        }
    }

    BaseViewModel定义了可以override的方法:

    _Initialize在view model第一次创建时调用,_Activate当视图View绑定到ViewModel并激活时调用,

    _Deactivate在view不再激活时调用。当导航Navigation发生时,Jounce拦截并绑定ViewModel,然后调用相应的这些方法。

    如何绑定View和ViewModel呢?

    [Export]
    public ViewModelRoute Binding
    {
        get
        {
            return ViewModelRoute.Create("Welcome", "Welcome");
        }
    }

    ViewRouter类

    实现了IEventSink接口,

    public class ViewRouter : IPartImportsSatisfiedNotification, IEventSink<ViewNavigationArgs>

    可以接收全局导航消息并调用ViewModelRouter的ActivateView方法:

    public bool ActivateView(string viewName)
    {
        Logger.LogFormat(LogSeverity.Verbose, GetType().FullName, Resources.ViewModelRouter_ActivateView,MethodBase.GetCurrentMethod().Name,viewName);
    
        if (HasView(viewName))
        {
            var view = ViewQuery(viewName);
    
            var viewModelInfo = GetViewModelInfoForView(viewName);
    
            if (viewModelInfo != null)
            {
                var firstTime = !viewModelInfo.IsValueCreated;
    
                var viewModel = viewModelInfo.Value;
    
                if (firstTime)
                {
                    viewModel.GoToVisualState =
                        (state, transitions) =>
                        JounceHelper.ExecuteOnUI(() => VisualStateManager.GoToState(view, state, transitions));
                    _BindViewModel(view, viewModel);
                    viewModel.Initialize();
                }
                viewModel.Activate(viewName);
            }
    
            return true;
        }
        return false;
    }

    viewModel的GoToVisualState可以在不引用view的情况下改变view的VisualState:

    public override void _Activate(string viewName)
    {            
        GoToVisualState("WelcomeState",true);
    }
  • 相关阅读:
    最大回文子串
    求数组中的最大连续子序列和
    如何在10亿数中找出前1000大的数
    给定一个字符串,最多删除一个字符,判断能够构成回文字符串
    HashMap(数组+链表+红黑树)、HashTable、TreeMap
    【转】jmeter如何设置登录接口只调用一次以及遇到的问题:cookie参数放在消息头headers里面
    Kafka命令行操作
    git上无法push代码解决办法
    【转】Jenkins集成Docker镜像实现自动发布
    awk命令总结
  • 原文地址:https://www.cnblogs.com/slmk/p/2792880.html
Copyright © 2011-2022 走看看