Prism Splash Screen Module

Splash screen is a good thing. It makes your application looks professional while numbers of libraries are being loaded in the background, mean while, users may feel the loading time is actually not that long if they see something updating. So the way we designing a splash screen is indeed very important in terms of a good one.

There’re various ways you can find everywhere to implement a splash screen but very few of them meet my criteria of good ones:

  • A splash screen should provide status updating to prove the application is not hung
  • A splash screen should show as the first visual of the application, especially, the main window should only be visible after the splash screen is gone – which means the initialization process has finished
  • A splash screen should be interactable – Some applications like to show splash screen as topmost – users can’t bring their other stuff to front if it’s overlapped by the splash; A lot of applications’ splash screen is not moveable, what if it happens to be topmost? Some applications has status updates on the splash screen but when you click on it, Windows tends to tell you the application window is busy, even worse, the window is frozen and not responding.
  • A better splash screen should give user more options: either allow them to close it (by double clicking it for example), or allow them drag and move the splash screen around without freeing the window if user still want to see the status updating

Today I’ll introduce one neat approach of implementing a splash screen that meet all of the above criteria, in a MVVM manner, in Prism. Prism is such a good application framework that makes your application modulized naturally, therefore it’s also an intuitive thinking that we can make splash screen a module, so it’s independent to other modules and can be easily reused in future applications.

Ok, seems having said too much :), let’s go to the implementation.

Usually in the unity bootstrapper, we create the shell and show it, like this:

public class Bootstrapper : UnityBootstrapper
{
  protected override DependencyObject CreateShell()
  {
    var shell = Container.Resolve<IShell>();
    shell.Show();
    return shell as DependencyObject;
  }
}

The first thing to do is to create the shell but not showing it – instead we let the splash screen module to do that (through the Show() method of the IShell interface) as we don’t want the shell to be visible before all module loadings are finished.

The splash screen’s Module class will be like this:

public class Module : IModule
{
  public Module(IUnityContainer container_, IEventAggregator eventAggregator_, IShell shell_)
  {
    Container = container_;  //we need the unity container to register and resolve types
    EventAggregator = eventAggregator_;  //we need the event aggregator for interactions between splash screen and the shell
    Shell = shell_;  //we need the shell as it's the splash screen's responsibility to show it
  }
}

Before we move on, one more thing need to be changed is the number of instances of the IShell type, obviously only one instance is needed otherwise the one the Module class above get will be a new unexpected instance. So the BootStrapper will be like this:

public class Bootstrapper : UnityBootstrapper
{
  protected override void ConfigureContainer()
  {
    Container.RegisterType<IShell, Shell>(new ContainerControlledLifetimeManager());
    base.ConfigureContainer();
  }

  protected override DependencyObject CreateShell()
  {
    var shell = Container.Resolve<IShell>();
    return shell as DependencyObject;
  }
}

Next is how do we implement the splash. Double click to close and drag move is easy, two lines of code like below will do (but you better do it in a attached behavior for reuse).

  splash.MouseDoubleClick += (s_, e_) => splash.Close();
  splash.MouseLeftButtonDown += (s_, e_) => splash.DragMove();

Hard part is the interactivity, and the proposed way is to start the splash screen in a separate STA thread and communicate with other modules through EventAggregator, in this way you won’t bother with the responsiveness. Then finally the sequence of the communication is:

  1. Create the shell but don’t show it
  2. Initialize the modules by starting with the splash screen module
  3. The splash screen module will queue a request on the Shell’s dispatcher, create a new STA thread to show the splash screen, subscribe to the MessageUpdateEvent and return.
  4. Keep initialize other modules and publish the status through the MessageUpdateEvent so the splash screen can show it (publishing of the status can also be done by each module to make the bootstrapper cleaner)
  5. After the initialization is done, the request queued on the dispatcher get called, so the Shell shows up and we close the splash screen and shut down the STA thread we created for it.

Sample project download: PrismSplash.zip

发表在 WPF | 标签为 , , , | 2条评论

One Instance per Type

Inheritance allows derived classes share common behaviours provided by base class while have special behaviours of their own. In the mean time, maintaining single instance of types is usually a natuaral requirment. Although it looks natural and reasonable enough but it’s actually not intuitive when it comes to combine both together.

Take one real problem as an example, say we have a class DataStore, which is responsible for getting data from multiple data sources, combining the data together and produce a collection of some data type, possibly with some filter applied.

Obviously the functionality of the DataStore class is quite general purpose and we should avoid tie it up with just one type of data. Considering strong type of the collection of data, we want to make the DataStoreclass generic and derived classes can specify the its own data type/filter and share the logic of getting and combining data.

But there’s another problem we can ignore—maintain one instance of each derived DataStore class. The multiple data sources mentioned above take by the DataStore class could be from network, from database, etc, so we don’t want user create too many instance of DataStore class to waste limited resources.

So here’s the problem to solve:

  1. We need a BaseDataStore to provide common feature
  2. We derive ClassADataStore and ClassBDataStore and each overrides some virtual properties/methods of BaseDataStore
  3. We need only one instance of ClassADataStore and ClassBDataStore

To implement a singleton in C# was not hard, good examples can be found here, here and here. Hard part is how to maintain only one instance for each type.
This artical gives a solution to address the problem. It uses a generic base class with a static member of the type to store the sintance.

abstract class BaseClass<T> where T : BaseClass<T>, new()
{
  private static T obj = new T();
  public abstract string ImplementAsStatic();
  public static string CallStaticImplementation()
  {
    return obj.ImplementAsStatic();
  }
}

There’re two flaws of this approach, First one as dani calbet pointed out in the comments is that having a base class is not good sometimes-you can’t have another base class in C#, which means you can’t extend some 3rd party class by deriving from it. Secondly, it requires the class has a parameterless constructor, which is not acceptable in some cases. For example, it’s common that a static method, e.g. GetInstance, is used to pass in some paremeters needed by constructing a sintance and create/return a singleton of the class.

Well if we introduce a generic factory class, we could get all the problems solved.
First let’s say our BaseDataStore class is like this, where T is of type IData, BaseDataStore can be drived from some 3rd party class if it’s needed.

abstract class BaseDataStore<T> where T : IData
{
  protected BaseDataStore(ICollection<IDataSource> dataSources_)
  {
    DataSources = dataSources_;
  }

  public void StartGetDate()
  {
    //Subscribe to the collection of data sources and get data asynchronously
    //and only get data of DataCategory type
  }

  protected ICollection<IDataSource> DataSources { get; set; }

  public abstract string DataCategory { get; }

  public ICollection<T> GetData()
  {
     return new List<T>();
  }
}

Then we can have ClassADataStore/ClassBDataStore class like this, where IClassAData and IClassBData are of type IData, the constructor is made protected and a CreateInstance static method is used to create an instance of each class.

class ClassADataStore : BaseDataStore<IClassAData>
{
  protected ClassADataStore(ICollection<IDataSource> dataSources_)
    : base(dataSources_)
  {
  }

  public override string DataCategory
  {
     get { return "DataOfClassA"; }
  }

  public static ClassADataStore CreateInstance(ICollection<IDataSource> dataSources_)
  {
    return new ClassADataStore(dataSources_);
  }
}

class ClassBDataStore : BaseDataStore<IClassBData>
{
  protected ClassBDataStore(ICollection<IDataSource> dataSources_)
    : base(dataSources_)
  {
  }

  public override string DataCategory
  {
    get { return "DataOfClassB"; }
  }

  public static ClassBDataStore CreateInstance(ICollection<IDataSource> dataSources_)
  {
    return new ClassBDataStore(dataSources_);
  }
}

Everything is normal, these classes are just written in usual way and we can create whetever number of instances we want, but how do we control only one instance per type? The solution is to use a generic static class.

static class DataStoreFactory<TType, TData>;
  where TType : BaseDataStore<TData>;
  where TData : IData
{
  private static readonly object Mutex = new object();

  private static TType Instance { get; set; }

  public static TType GetInstance(Func<ICollection<IDataSource>, TType> instanceFactory_,
    DataSourceCreationParam param_)
  {
    //Double-check to ensure thread safe
    if (Instance == null)
    {
      lock (Mutex)
      {
        if (Instance == null)
        {
          Instance = instanceFactory_(CreateDataSources(param_));
          Instance.StartGetDate();
        }
      }
    }
    return Instance;
  }

  private static ICollection<IDataSource> CreateDataSources(DataSourceCreationParam param_)
  {
    //Create the stuff that is needed by creating a BaseDataStore<TData>
  }
}

Note here the GetInstance takes two parameters. One is a Func that takes same parameters as the constructor of BaseDataStore and return an instance of TType (BaseDataStore), which get rid of the limitation in this artical that only parameterless constructor is allowed. Another parameter is a DataSourceCreationParam, which is to demonstrate that some times preparation of construction is needed (may not be needed in real application). In this case, the BaseDataStore is expecting a ICollection parameter, where we need things like host:port, database name, etc, to build a collection of the data sources-this part of work is also generic, so we put the logic into the DataStoreFactory.

So we can get the single instance of ClassADataStore and ClassBDataStore in this way:

var classADataStore = DataStoreFactory<ClassADataStore, IClassAData>.GetInstance(
 ClassADataStore.CreateInstance, ClassADataStore.Param);
var classBDataStore = DataStoreFactory<ClassBDataStore, IClassBData>.GetInstance(
 ClassBDataStore.CreateInstance, ClassBDataStore.Param);

In a CAL application, this can be registered to a the unity container and used elsewhere.

Sample project download: VirtualStatic

发表在 C#, C# Language | 标签为 , , , , , , | 留下评论

ListBox as Toolbar

In one of my recent projects, I extended the default module loading behaviour of the CAL application to make modules can be loaded on-demand. So some of the modules are loaded on startup (aka loaded modules) while some are not (aka available modules). Apparantly it would be better that we display available modules some where so user can load them when they’re needed.

I dicided to display the modules as a list of ButtonTool in a RibbonGroup of a infragistics RibbonTabItem as it’s the nice GUI we’re using. However, it’s unfortunate that even though the RibbonTabItem is powerful enough to support office 2007 like GUI but it doesn’t seem to have something like ButtonTool-bar there I can use to bind a list of module infos to and it creates buttons for me. What are the alternatives?

ToolBar control looks good as it’s an items control that meet my data binding purpose, but apparently it needs to be re-styled to change the look and feel. I’m not too familiar with the control so I drop it.

ListBox is the second cadidate jumped into my mind and indeed it’s proven to be the one.  Thinking about the requirment, what I wanted is a toolbar like items control that creates buttons based on the items in the list bound to it and do some work when the buttons are clicked. ListBox is the best fit as I don’t need extra features like button group, mutual exclusive button, etc.

Now it’s time for the implementation. First thought was simple, I wanted the button to show large image above the text, and the ButtonTool can happen to be set with a dependency property RibbonGroup.MaximumSize=”ImageAndTextLarge” to have exactly the same appearance.

So re-style the ItemTemplate with a ButtonTool looks should do, I think, but the answer is no, the reason being that because RibbonGroup.MaximumSize works only when the ButtonTool is a directl child of a RibbonGroup or a ToolHorizontalWrapPanel.

I have to do the whole thing all by myself finally.

<StackPanel>
  <StackPanel.Resources>
    <DataTemplate DataType="{x:Type Models:ModuleData}">
      <Button Style="{DynamicResource FlatButtonStyleKey}" Width="60" Height="66"
 Command="{Binding LoadModuleCommand}" ToolTip="{Binding Name}">
        <StackPanel>
          <Image Source="{Binding ModuleImage}" Height="32" Width="32" Margin="0,3,0,0"/>
          <TextBlock Background="Transparent" TextTrimming="CharacterEllipsis" Margin="5,2,5,5"
 Foreground="{DynamicResource TextColorKey}" TextAlignment="Center"
 VerticalAlignment="Bottom" Text="{Binding Name}"/>
        </StackPanel>
      </Button>
    </DataTemplate>
  </StackPanel.Resources>

  <ListBox Style="{DynamicResource WrapListBox}" ItemsSource="{Binding Modules}" Width="Auto"/>
</StackPanel>

Notes:

1. The ListBox shows its contents vertically by default because a VirtualizingStackPanel is used in its ItemsPanel . The WrapListBox above simply replaces the StackPanel with a WrapPanel so items will be shown in a horizontal and wrappable fasion.

<!-- Items of the listbox will be listed virtically and wrappable -->
<Style x:Key="WrapListBox" TargetType="{x:Type ListBox}">
  <Setter Property="ItemsPanel">
    <Setter.Value>
      <ItemsPanelTemplate>
        <WrapPanel/>
      </ItemsPanelTemplate>
    </Setter.Value>
  </Setter>

  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate>
        <ItemsPresenter/>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

2. There’s another thing tricky in the FlatButtonStyleKey. I wanted the flat button looks like the infragistics ButtonTool – a button without focus visual style. Just keep in mind that simply set FocusVisualStyle to x:Null was not perfect – If the infragistics Ribbon is set to collapsed, then you click the tab header to expand the ribbon and click on the button, the ribbon won’t automatically collapse itself if FocusVisualStyle is set to x:Null. Instead, you still need to provide a FocusVisualStyle but just don’t do anything in it.

<Style x:Key="NoFocusVisualStyle">
  <Setter Property="Control.Template">
    <Setter.Value>
      <ControlTemplate/>
    </Setter.Value>
  </Setter>
</Style>

<Style x:Key="FlatButtonStyleKey" TargetType="{x:Type Button}">
  <!-- Set to NoFocusVisualStyle instead of x:Null to keep the button click behaviour -->
  <Setter Property="FocusVisualStyle" Value="{StaticResource NoFocusVisualStyle}"/>
  ......
</Style>

3. Everything looks good so far except for one thing – when you right click on a button you’ll see it actually gets selected and being rendered as highlighted because items in a ListBox are selectable! There’re many ways to solve this problem, changing the behaviour of the ListBox is one of them, but I’m choosing the simpliest way – again, re-styling to rescue, we just don’t hightlight the item when it’s selcted.

  <Style x:Key="{x:Type ListBoxItem}" TargetType="{x:Type ListBoxItem}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ListBoxItem}">
            <Border Name="ItemBorder" SnapsToDevicePixels="true">
              <ContentPresenter />
            </Border>
            <ControlTemplate.Triggers>
              <Trigger Property="IsSelected" Value="true">
                <Setter TargetName="ItemBorder" Property="Background" Value="Transparent"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

Sample project download: ButtonBarApp

发表在 WPF | 标签为 , , , , , , , , | 留下评论

还是抽空写写

以前在CSDN有个Blog,前后两年多写了不少技术文章,至今也有四年多没有更新了。工作越来越忙,生活却越来越糟——不愿动脑,凡事怕麻烦,每天上网除了看看别人转帖的文章就不愿再干别的,文章超过一屏就没有耐性再读下去——整个人及生活已陷入一种停滞不前的状态。

想想看工作忙绝不该成为借口,周围的朋友同事过得至少看起来有劲得多,问题肯定还是出在自己身上,尽管我没找到或者不愿承认原因是什么。

管他的,还是抽空写写吧。还是技术性的笔记,不是日记,不是心路历程,记录而已——给自己找点许久不做的事来忙忙。

发表在 Recover | 留下评论