A spinner and progress for xaml, wpf.

I wanted a spinner control, and a nice one. Google searches did not help, although heaps of recommendations and a few free controls could be found, non of them was satisfying enough for what I wanted to do. And of-course I didn’t want some C# code-behind. So I opened XamlPadX and started building one for myself.

Result is something like this and I am happy with it:

It is nothing more than a template for ProgressBar. By the way, setting the IsInditerminate  to True makes the number in the middle to disappear, resulting a generic wait spinner.

Below is the xaml to achieve the spinner progress bar, you can put it some where in your resources and use it:

<Grid.Resources>
 <Style TargetType="ProgressBar" x:Key="SpinnerProgress">
 <Setter Property="Template">
 <Setter.Value>
 <ControlTemplate TargetType="ProgressBar">
 <Grid>
 <ProgressBar x:Name="pgBar" Value="{TemplateBinding Value}" Visibility="Collapsed" IsIndeterminate="{TemplateBinding IsIndeterminate}"/>
 <TextBox Background="Red" Text="{Binding ElementName=pgBar, Path=Value}">
 <TextBox.Style>
 <Style TargetType="{x:Type TextBox}">
 <Setter Property="Template">
 <Setter.Value>
 <ControlTemplate TargetType="TextBox">
 <Grid>
 <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Orientation="Horizontal">
 <TextBlock Text="{TemplateBinding Text}">
 <TextBlock.Style>
 <Style TargetType="TextBlock">
 <Style.Triggers>
 <DataTrigger Binding="{Binding ElementName=pgBar, Path=IsIndeterminate}" Value="True">
 <Setter Property="Visibility" Value="Collapsed"/>
 </DataTrigger>
 </Style.Triggers>
 </Style>
 </TextBlock.Style>
 <TextBlock Text="%"/>
 </TextBlock>
 </StackPanel>
 <Grid Width="50" Height="50" x:Name="mainGrid">
 <Grid.RenderTransform>
 <RotateTransform Angle="0" CenterX="25" CenterY="25" />
 </Grid.RenderTransform>
 <Grid.Triggers>
 <EventTrigger RoutedEvent="Grid.Loaded">
 <BeginStoryboard>
 <Storyboard RepeatBehavior="Forever">
 <DoubleAnimation From="0" To="360" Duration="00:00:00.750" Storyboard.TargetName="mainGrid" Storyboard.TargetProperty="(Grid.RenderTransform).(RotateTransform.Angle)" />
 </Storyboard>
 </BeginStoryboard>
 </EventTrigger>
 </Grid.Triggers>

<Border x:Name="spinnerMask" BorderThickness="6" CornerRadius="25" BorderBrush="White"/>
 <Rectangle>
 <Rectangle.OpacityMask>
 <VisualBrush Visual="{Binding ElementName=spinnerMask}"/>
 </Rectangle.OpacityMask>
 <Rectangle.Fill>
 <LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
 <GradientStop Color="#FF068206" Offset="0" />
 <GradientStop Color="#FF72CE72" Offset="0.198" />
 <GradientStop Color="#FFC2FFC2" Offset="0.48" />
 <GradientStop Color="#FFC2FFC2" Offset="0.52" />
 <GradientStop Color="#FF72CE72" Offset="0.891" />
 <GradientStop Color="#FF068206" Offset="1" />
 </LinearGradientBrush>
 </Rectangle.Fill>
 </Rectangle>
 <Rectangle Fill="#FF068206">
 <Rectangle.OpacityMask>
 <VisualBrush Visual="{Binding ElementName=spinnerMask}"/>
 </Rectangle.OpacityMask>
 <Rectangle.Clip>
 <RectangleGeometry Rect="0,0,50,25"/>
 </Rectangle.Clip>
 </Rectangle>
 </Grid>
 </Grid>
 </ControlTemplate>
 </Setter.Value>
 </Setter>
 </Style>
 </TextBox.Style>
 </TextBox>
 </Grid>
 </ControlTemplate>
 </Setter.Value>
 </Setter>
 </Style>
 </Grid.Resources>

And here is how to use it:

<ProgressBar Style="{StaticResource ResourceKey=SpinnerProgress}" IsIndeterminate="False" Value="12"/>
Advertisement

Xaml localization: Using .resx Resources in Xaml without x:static

The Microsoft recommended approach to xaml localization is using the locbaml tool. To be honest, it sucks! It has a lot of manual work and is not compatible with previous models.

Many companies have already lots of infrastructure in place for automatic support of localization. Replacing the whole infrastructure, for just a few recently added Silverlight or WPF projects does not make sense.

People give various suggestions, first thing you hear is to use x:static and .resx files. It is alright, and if it works for you then bingo. But designer does not play well with x:static, also it only works if you use the default Visual Studio resource generator to generate classes. In general I don’t like this approach.

Good news is that Dynamic objects are lovely sometimes. Xaml can use them a lot, so I create a dynamic object called ResourceLoader, and use it to load my resources from the .resx file. Then I can use binding (withe the mode=OneTime for better performance) to load resources for the right local.

<TextBlock x:Name="LoginLable" Text="{Binding Source={StaticResource ResourceKey=Res},Path=LogonText, Mode=OneTime}">
</TextBlock>

The only additional thing is to add the static resource which is the ResourceLoader somewhere in the logical tree.

<local:ResourceLoader x:Key="Res" Assembly="LogonDialog" />

The attribute “Assembly” defines the assembly which resource should be loaded from, otherwise the ResourceLoader assembly would be selected which can be wrong depending on the solution structure and location of resources.

You can download the ResourceLoader.cs from here.

Please note that you should rename the above file ResourceLoader.cs, because wordpress does not allow uploading .cs files.

Automatic Mid-tier Cache!

I have been thinking about this for a while. I started to work on a Silverlight project last year which was a nifty little business app. One of those apps that is just sitting down and working, you know, a web server, an average DB with a few million records, and a silverlight client with a bunch of forms, grids, and menus.

Everything was straightforward and brainless, like just follow a pattern and do the job. However, I was deeply dis satisfied from one aspect of the project. The Caching. What I could not accept was that in 21st century, when you have Entity Framework and IQueryable, you should still manually cache your data when it is appropriate and do all the pointless work of cache invalidation and loading, etc. Apart from the pain of working on something that should have been automated, I wouldn’t trust a programmer to decide which parts of the data should be cached and which part shouldn’t be. Not that I don’t believe they can do a good job on that, they don’t have enough information (at the time of dev work) to decide on it.

Caching strategy should be based on user behaviour and is subject to change by passage of time. For example at some stage lots of QLD pharmacies are queried, but next week NSW users decide to get ready for their conferences and start hammering the system for NSW pharmacies.

Le me be clear about my expectations of a caching system. It should have the following charachteristics:

  1. It should know what users are going to query a lot and cache that (and only that) part of the database.
  2. It should be able to re-use the caches. For example if I say 1.”Give me all QLD pharmacies”, and next one says 2.”Give me all QLD Chemists Warehouses”, the cache manager should be smart enough to run this new query 2., over the results of query 1. which has been retrieved a few minutes ago.
  3. It should optimize the indexes for performance based on the user queries.
  4. It should change the cache when user behaviour changes.
  5. It can call back the database only if there is absolutely no way of answering the query from cache.

Above requests seems to be a lot, but not really in 2011. All these methods are possible, in fact DBMSs do those kind of stuff for ages. We also have IQueryable, which makes it even easier to have a decent caching system.

So let me write a few examples:

Q1: Pharmacies.Join( … Address …).Join( … State …).Where( s => s.Sate = “QLD”).Select(…)

Q2: Pharmacies.Join( … Address …).Join( … State …).Where( a =>a.Sate = “QLD” && a.PostCode > 4000 && a.PostCode<4079).Select(…)

Q3: Pharmacies.Join( … Address …).Join( … State …).Where( s => s.Sate = “QLD”).GroupBy(…).Where( pg => pg.Count() > 4).Select(…)

Q4:  PharmacyStaff.Where(ps => ps.Position == “Manager”).Select(…)

Q5: Pharmacies.Join( … Address …).Join( … State …).Join(…PharmacyStaff…).Where( s => s.Sate=”QLD” && s.Position == “Manager” ).Select(…)

Users login to our system  and do stuff that will cause the above queries to be issued. Normally they will all be issued against the database, but it means that our caching strategy is stupid as a donkey. Really what I would expect is that only Q1 and Q4 are ran against the database. Q2, Q3, and Q4 are all subsets of Q1, hence if we already have those results from Q1, such a waste to run these new queries against the database. Why not look at the Expression Tree and figure out that Q2 is forms a query which is a subset of Q1. Then change the queries as below:

Q1: not changed…

Q2: Q1.Where(a => a.PostCode > 4000 && a. PostCode<4079).Select(…)

Q3: Q1.GroupBy(…).Where(…)

Q4: not changed…

Q5: Q1.Join(…Q4…).Select(…)

Check out the above queries. Aren’t they much better. We don’t expect user or programmer to waste his time on translating those queries. The caching system should do that. It should be an IQueryable that reads the ExpressionTree and translates it into a new ExpressionTree that uses existing data in the cache if there is no need to query database.

This specially make  sense in CLOUD, where you have to pay for querying your SQL Asure.

Enough talking about the dreams, lets become realistic! I did a bit of research and as I expected no such caching manager exists (if you know some tell me and save my hair). So I decided to do it myself. Check the Auto-mid-tier-cache project which I have already started. I haven’t gone far with it yet. It is just a proof on concepts and it implements no IQueryable. It uses a set of objects defined by myself for Relational Algebra operators. It does the very basic of view-matching to find what query is subset of what other, and it is able to translates queries to run against the database or cache alternatively.

I ran it and it worked fine and a bunch of benchmark analysis proved its effectiveness. What is left now is to complete the view-matching and write an IQueryable on top of it. Lot of work but it is worth it.

I forgot to say that you can limit the cache size by setting cost upper-bound. Next issue is that it does not keep itself up-to-date, but this is really another story.

Authorization Rule Library in SAF and how to use it with RIA Services and Silverlight

A problem of applying rules by decorating objects using attributes is that there is no concept of re-usability. For example, we want NationalAdmins, StateAdmins, and Managers to be have all permissions over everything. Also permissions for my customer, customer_address, customer_emails, etc. are all similar. Normally you should apply all authorization attributes to every part of the model.

SAF provides an ImportAuthorizationAttribute that solves this problem.

public class AuthorizationMetadata
{
    [Grant...]
    [Grant...]
    public class AdminGroup { }

    [Deny...]
    [Deny...]
    [Deny...]
    public class RestrictedWriteGroup {}

    [Grant...]
    public class TitleViewersGroup {}
}

You can use AuthorizationMetadata class to centralize all your authorization rules. You can then use it in your model as follows:

[ImportAuthorization(SourceType=AuthorizationMetadata.AdminGroup)]
public partial class Model
{
}

What else do you want?