вторник, 1 ноября 2011 г.

Отложенная загрузка компонентов

Сейчас приходится писать на Silverlight, поэтому ввожу новый тэг Silverlight и если буду писать нечто характерное именно для него, то буду применять именно этот тэг. В остальных случаях буду использовать тэг WPF.

Сегодня хочу показать пример, как сделать так, чтобы огромный и редко используемый компонент грузился  не вместе с приложением, а только по запросу пользователя.

Итак у нес есть приложение, 80 процентов пользователей которого обходятся пресловутыми 20% функционала. А для остальных функционал мы планируем грузить потом, во время работы.
Для демонстрации создадим два проекта:
1. Главное приложение
2. Библиотека с контролами Silverlight.
Дерево проектов должно иметь вид:


Меняем на вкладке Build свойств проекта ExternalLib путь куда билдить проект на папку ClientBin проекта lazyLoadApp.Web.
Главная форма пусть будет иметь вид:

<UserControl x:Class="LazyLoadApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
 
    <Grid >
        <Grid.RowDefinitions>
            <RowDefinition Height="35" />
            <RowDefinition Height="1*" />
        Grid.RowDefinitions>
        <Button Content="Загрузить" Margin="5" HorizontalAlignment="Left" />
        <ContentPresenter Grid.Row="1" x:Name="LayoutRoot" />
    Grid>
UserControl>
А пользовательский контрол будет показывать картинку:

<UserControl x:Class="ExternalLib.BigUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    
    <Grid x:Name="LayoutRoot" Background="White">
        <Image Source="KO.jpg" />
    Grid>
UserControl>
Собственно, нам осталось сделать загрузку контрола в работающее приложение по клику на кнопке.
Для этого добавляем к ней обработчик клика и еще один вспомогательный метод, который по окончанию загрузки и покажет контрол:
  private void Button_Click(object sender, RoutedEventArgs e)
  {
   WebClient downloader = new WebClient();
   downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
 
   string component = "ExternalLib.dll";
   string absoluteUri = System.Windows.Application.Current.Host.Source.AbsoluteUri;
   string path = absoluteUri.Substring(0, absoluteUri.IndexOf("LazyLoadApp.xap")) + component;
 
   downloader.OpenReadAsync(new Uri(path, UriKind.Absolute));
  }
 
  void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
  {
   AssemblyPart assemblyPart = new AssemblyPart();
   Assembly bigControl = assemblyPart.Load(e.Result);
   UserControl control = (UserControl)bigControl.CreateInstance("ExternalLib.BigUserControl");
   LayoutRoot.Content = control;
  }
Так приложение выглядит после старта:

А вот так, после клика на кнопку:

Собственно все. Загрузка происходит асинхронно, т.е. если компонент очень большой, пользователь может продолжать тыкать в кнопки приложения, и с этим надо быть аккуратнее. С другой стороны, мы можем подгружать эти компоненты во время аутентификации пользователя или там показа ему свежих новостей. А как загрузим, переходить к работе.

Комментариев нет:

Отправить комментарий