Category Archives: MVVM

ViewModel 1st Child Container PRISM Navigation

I have recently just started work on a greenfield WPF project using PRISM 4. When I started I knew that we would be used a workspace driven design and that I wanted to go VM first route, and that I wanted to make use of PRISMs navigation API.

I was also pretty keen to try and use child IOC containers for my workspaces where possible, such that the life cycle of the child container could be coupled to the VM that would be shown for a workspace. That way when the VM was closed the child container and all its dependencies would also be cleaned up.

So I had a bit of a play around with PRISM and managed to get that work out quite nicely. If this sounds like it would be of use to you, you can learn more by reading the full article, which is available right here:

http://www.codeproject.com/Articles/640573/ViewModel-1st-Child-Container-PRISM-Navigation

Advertisements

MVVM Diagram Designer

A while back a user called “sucram (real name Marcus)” posted a series of articles here about how to create a diagram designer using WPF. Sucrams original links are as follows:

I remember being truly blown away by this series of articles, as they showed you how to do the following things:

  • Toolbox
  • Drag and Drop
  • Rubber band selection using Adorners
  • Resizing items using Adorners
  • Rotating items using Adorners
  • Connecting items
  • Scrollable designer surface, complete with zoombox

WOW that sounds fantastic, sounds exactly like the sort of things you would need to create a fully functional diagram designer. Well Yeah, its was and still is, but……..the thing is I have used WPF a lot, and trying to use the code attached to sucrams series of article in WPF just wasn’t that great. He had taken a very control centric view, in that everything was geared around adding new controls and supplying static styles for said controls.

In reality it was more like working with a Win Forms application. Not that there is anything wrong with that, and I really truly do not mean to sound ungrateful, as that could not be further from the truth, without that original series of articles it would have taken me a lot longer to come up with a working diagram designer that I was happy with. So for that I am truly grateful, thanks sucram you rock.

Anyway as I say sucrams original codebase took a very control centric point of view, and added controls using code behind, and held collections of items directly in the diagram surface control. As I say if that is what you want cool, however, it was not what I wanted. What I wanted was

  • All of the features of curams original code (actually I didn’t want any rotating of items, or resizing of items)
  • A more MVVM driven approach, you know allow data binding of items, delete of items via ICommand etc. etc.
  • Allow me to control the creation of an entire diagram from within a single ViewModel
  • Allow for complex objects to be added to the diagram i.e. ViewModels that I could style using DataTemplate(s). Sucrams original code only allowed simply strings to be used as a DataContext which would control what ImageSource an Image would use to show for a diagram item. I needed my items to be quite rich and allow popups to be shown and associated with the diagram item, such that the data related to the diagram item could be manipulated
  • Allow me to save the diagram to some backing store
  • Allow me to load a previously saved diagram from some backing store

To this end I have pretty much completely re-written sucrams original code, I think there is probably about 2 classes that stayed the same, there is now more code, a lot more, however from an end user experience, I think it is now dead easy to control the creation of diagrams from a centralized ViewModel, which allows a diagram to be created via well known WPF paradigms like Binding/DataTemplating.

So I decided to give this a go, you can read more about it here : http://www.codeproject.com/Articles/484616/MVVM-Diagram-Designer

 

Hope its of some use to someone

Cinch news

If you use my Cinch MVVM framework I have some news.

I have just down a new update to improve several areas, and have also added some extra helper classes.

Here is a breakdown of what has been added/changed

1. Resynced with MefedMVVM version 75221
2. Added GenericRule class, which means no more casting inside rule class
3. Added Validator class, which can be used as stand alone validator class when you do not wish to (or can not) inherit from the Cinch validating base ViewModels/Models
4. Added new ViewModel interface IViewStatusAwareWindowInjectionAware, to allow WPFUIVisualizerService service to inject full IViewAwareStatusWindow into popup ViewModel
5. Added WeakDelegateReference class, does what it says really
6. Altered WPFUIVisualizerService to fix this issue : http://cinch.codeplex.com/discussions/263365

7. Added AsyncHost (WPF Only) (read the comments at top of this file to see example usage)
8. Added CircularProgressBar (WPF Only)
9. Added AsyncFailedUserControl (WPF Only)
10. Added AsyncBusyUserControl (WPF Only)

CinchV2 and PRISM 4 Interoperability

I have been working on 2 small demo apps using my CinchV2 MVVM framework code used in conjunction with the latest PRISM 4 release (which now uses MEF).

I am actually pretty happy with the results of how easy these 2 frameworks work together, it is almost seamless.

So if you are a fan of PRISM features such as Regions/Modules etc etc, but want some of the goodness from Cinch like the ViewModel base classes and UI Services, then the article I have made to cover these demo apps could be for you.

The url to the article is right here : http://www.codeproject.com/KB/WPF/CinchV2AndPRISM4.aspx

PRISM 4 Custom Transitioning Region

Over the XMAS break I had a chance to look into something I wanted to look at, which is cool.

The thing I wanted to look at was to try and see if the new Composite WPF/SL (PRISM) code, which is now using MEF (Managed Extensibility Framework) would work well with Cinch V2.

Great news is works just fine, and I will be writing up a codeproject article for that real soon, but as part of that codebase, I also wrote a custom PRISM region adaptor that uses a TransitionalElement from the fabolous Microsoft Transitionals project.

For those of you that not heard of Transitionals, it is a set of WPF transitions that you can use to go from one bit of content to another bit of content.

It offers the following transitions:

  • FadeAndGrow
  • Translate
  • FadeAndBlur
  • Rotate
  • CheckerboardTransition
  • DiagonalWipeTransition
  • DiamondsTransition
  • DoorTransition
  • DotsTransition
  • DoubleRotateWipeTransition
  • ExplosionTransition
  • FadeTransition
  • FlipTransition
  • HorizontalBlindsTransition
  • HorizontalWipeTransition
  • MeltTransition
  • PageTransition
  • RollTransition
  • RotateTransition
  • RotateWipeTransition
  • StarTransition
  • TranslateTransition
  • VerticalBlindsTransition
  • VerticalWipeTransition

 

So I took it upon myself to split that custom PRISM region adaptor into a small demo app. This blog has that demo code attached.

The demo app is very simple and has a DockPanel with a ComboBox to select the transition type and 3 images that when clicked on will set a custom  transitonals based PRISM region adaptor to transition to that image. Shown below is an example of one the images 1/2 way through a transition.

image

So how does it all work. It’s really down to the following steps

STEP 1 : Create a custom PRISM region adaptor

This is where we create the custom region adaptor for the type of TransitionElement, as shown below:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.Regions;

using Transitionals.Controls;
using System.Collections.Specialized;

namespace PRISMTransitionalRegion.Regions
{
    [Export("PRISMTransitionalRegion.Regions.TransitionElementAdaptor", 
        typeof(TransitionElementAdaptor))]
    public class TransitionElementAdaptor : RegionAdapterBase<TransitionElement>
    {
        [ImportingConstructor]
        public TransitionElementAdaptor(IRegionBehaviorFactory behaviorFactory) :
            base(behaviorFactory)
        {
        }

        protected override void Adapt(IRegion region, TransitionElement regionTarget)
        {
            region.Views.CollectionChanged += (s, e) =>
            {
                //Add
                if (e.Action == NotifyCollectionChangedAction.Add)
                    foreach (FrameworkElement element in e.NewItems)
                        regionTarget.Content = element;

                //Removal
                if (e.Action == NotifyCollectionChangedAction.Remove)
                    foreach (FrameworkElement element in e.OldItems)
                    {
                        regionTarget.Content = null;
                        GC.Collect();
                    }

            };
        }

        protected override IRegion CreateRegion()
        {
            return new AllActiveRegion();
        }

    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

STEP 2 : Create a Region to use this custom region adaptor

Now we need to actually use this custom region adaptor. Which I have decided to do directly in the Shell (standard PRISM starting window), as follows:

<Window x:Class="PRISMTransitionalRegion.Shell"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:cal="clr-namespace:Microsoft.Practices.Prism.Regions;assembly=Microsoft.Practices.Prism"  
        xmlns:transitions="clr-namespace:Transitionals.Transitions;assembly=Transitionals"
        xmlns:transitionals="clr-namespace:Transitionals;assembly=Transitionals"
        xmlns:transitionalsControls="clr-namespace:Transitionals.Controls;assembly=Transitionals"
         xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        Title="Shell" 
        WindowState="Normal"
        WindowStyle="ThreeDBorderWindow"
        WindowStartupLocation="CenterScreen"
        Width="800"
        Height="800">


    <DockPanel Grid.Row="1" Grid.Column="1" Margin="10"
                   LastChildFill="True">

        <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" 
                    HorizontalAlignment="Left">
            <Label Content="Pick Transition Type" FontSize="10" 
                   Foreground="Black" FontFamily="Verdana"/>
            <ComboBox Margin="5,0,0,0" Width="200"
                          ItemsSource="{Binding TransitionTypes}" 
                          SelectedItem="{Binding SelectedTransitonType}"/>
            
            <StackPanel Orientation="Horizontal" Margin="10,0,0,0">
                <Image Source="/PRISMTransitionalRegion;component/Images/robot1.png" 
                       Width="40" Height="40" Margin="5">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="MouseLeftButtonDown">
                            <i:InvokeCommandAction 
                                Command="{Binding ShowViewCommand}" 
                                CommandParameter="/PRISMTransitionalRegion;component/Images/robot1.png"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Image>

                <Image Source="/PRISMTransitionalRegion;component/Images/robot2.png" 
                       Width="40" Height="40" Margin="5">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="MouseLeftButtonDown">
                            <i:InvokeCommandAction 
                                Command="{Binding ShowViewCommand}" 
                                CommandParameter="/PRISMTransitionalRegion;component/Images/robot2.png"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Image>

                <Image Source="/PRISMTransitionalRegion;component/Images/robot3.png"
                       Width="40" Height="40" Margin="5">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="MouseLeftButtonDown">
                            <i:InvokeCommandAction 
                                Command="{Binding ShowViewCommand}" 
                                CommandParameter="/PRISMTransitionalRegion;component/Images/robot3.png"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                </Image>

            </StackPanel>
        </StackPanel>

        <transitionalsControls:TransitionElement 
            x:Name="transitionElement"
            Margin="10"
            VerticalAlignment="Center"
            HorizontalAlignment="Center"
            cal:RegionManager.RegionName="imageRegion"
            Transition="{Binding TransitionToUse}">
        </transitionalsControls:TransitionElement>

    </DockPanel>





</Window>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

We also create a simple ViewModel for the Shell in the Shell.xaml.cs code behind, where the ShellViewModel looks like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Primitives;
using System.ComponentModel;
using System.Windows;

using Microsoft.Practices.Prism.Regions;

using PRISMTransitionalRegion.Regions;
using PRISMTransitionalRegion.Views;
using PRISMTransitionalRegion.Interfaces;
using PRISMTransitionalRegion.Commands;
using Transitionals;
using Transitionals.Transitions;

namespace PRISMTransitionalRegion.ViewModels
{


    public enum TransitionType
    {
        FadeAndGrow = 1,
        Translate,
        FadeAndBlur,
        Rotate,
        CheckerboardTransition,
        DiagonalWipeTransition,
        DiamondsTransition,
        DoorTransition,
        DotsTransition,
        DoubleRotateWipeTransition,
        ExplosionTransition,
        FadeTransition,
        FlipTransition,
        HorizontalBlindsTransition,
        HorizontalWipeTransition,
        MeltTransition,
        PageTransition,
        RollTransition,
        RotateTransition,
        RotateWipeTransition,
        StarTransition,
        TranslateTransition,
        VerticalBlindsTransition,
        VerticalWipeTransition

    }



    public class ShellViewModel : INPCBase
    {

        private Transition transitionToUse = new FadeAndBlurTransition();
        private Dictionary<TransitionType, Transition> transitionsLookup = 
            new Dictionary<TransitionType, Transition>();
        private DependencyObject view;
        private Lazy<IRegion> region;

        public ShellViewModel(DependencyObject view)
        {
            this.view = view;


            //add transition lookups
            transitionsLookup.Add(TransitionType.FadeAndBlur, 
                new FadeAndBlurTransition());
            transitionsLookup.Add(TransitionType.FadeAndGrow, 
                new FadeAndGrowTransition());
            transitionsLookup.Add(TransitionType.Translate, 
                new TranslateTransition());
            transitionsLookup.Add(TransitionType.Rotate, 
                new RotateTransition());
            transitionsLookup.Add(TransitionType.CheckerboardTransition, 
                new CheckerboardTransition());
            transitionsLookup.Add(TransitionType.DiagonalWipeTransition, 
                new DiagonalWipeTransition());
            transitionsLookup.Add(TransitionType.DiamondsTransition, 
                new DiamondsTransition());
            transitionsLookup.Add(TransitionType.DoorTransition, 
                new DoorTransition());
            transitionsLookup.Add(TransitionType.DotsTransition, 
                new DotsTransition());
            transitionsLookup.Add(TransitionType.DoubleRotateWipeTransition, 
                new DoubleRotateWipeTransition());
            transitionsLookup.Add(TransitionType.ExplosionTransition, 
                new ExplosionTransition());
            transitionsLookup.Add(TransitionType.FadeTransition, 
                new FadeTransition());
            transitionsLookup.Add(TransitionType.FlipTransition, 
                new FlipTransition());
            transitionsLookup.Add(TransitionType.HorizontalBlindsTransition, 
                new HorizontalBlindsTransition());
            transitionsLookup.Add(TransitionType.HorizontalWipeTransition, 
                new HorizontalWipeTransition());
            transitionsLookup.Add(TransitionType.MeltTransition, 
                new MeltTransition());
            transitionsLookup.Add(TransitionType.PageTransition, 
                new PageTransition());
            transitionsLookup.Add(TransitionType.RollTransition, 
                new RollTransition());
            transitionsLookup.Add(TransitionType.RotateTransition, 
                new RotateTransition());
            transitionsLookup.Add(TransitionType.RotateWipeTransition, 
                new RotateWipeTransition());
            transitionsLookup.Add(TransitionType.StarTransition, 
                new StarTransition());
            transitionsLookup.Add(TransitionType.TranslateTransition, 
                new TranslateTransition());
            transitionsLookup.Add(TransitionType.VerticalBlindsTransition, 
                new VerticalBlindsTransition());
            transitionsLookup.Add(TransitionType.VerticalWipeTransition, 
                new VerticalWipeTransition());


            ShowViewCommand = new SimpleCommand<Object, Object>(ExecuteShowViewCommand);

            region = new Lazy<IRegion>(() =>
                {
                    IRegionManager regionManager = RegionManager.GetRegionManager(view);
                    return regionManager.Regions["imageRegion"];
                });

        }



        public SimpleCommand<Object, Object> ShowViewCommand { get; private set; }

        public Array TransitionTypes
        {
            get
            {
                return Enum.GetValues(typeof(TransitionType));
            }
        }


        public TransitionType SelectedTransitonType
        {
            set
            {
                TransitionToUse = transitionsLookup[value];
            }
        }

        public Transition TransitionToUse
        {
            get { return transitionToUse; }
            private set
            {
                transitionToUse = value;
                NotifyPropertyChanged("TransitionToUse");
            }
        }

        private void ExecuteShowViewCommand(Object args)
        {
            if (!String.IsNullOrEmpty(args.ToString()))
                ShowViewInRegion(args.ToString());
        }


        private void ShowViewInRegion(string imageUrl)
        {
            ImageView imageView = 
                (App.Current as App).PrismCompositionContainer.GetExportedValue<ImageView>();
            ((IContextualDataAware<string>)imageView).ContextualData = imageUrl;
            IRegion lazyRegion = region.Value;
            var oldView = lazyRegion.GetView("imageView");
            if (oldView != null)
                lazyRegion.Remove(oldView);
            lazyRegion.Add(imageView, "imageView");
        }
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

STEP 2 : Make sure the custom region adaptor is registered with PRISM

For our custom region adaptor to work with PRISM we need to make sure it registered with PRISM. We can do this in the PRISM 4.0 bootstrapping code, as follows:

using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.Text;
using System.Windows;
using System.Reflection;
using System.Windows.Controls;
using Transitionals.Controls;

using Microsoft.Practices.Prism.MefExtensions;
using Microsoft.Practices.Prism.Regions;

using PRISMTransitionalRegion.Regions;
using PRISMTransitionalRegion.Views;


namespace PRISMTransitionalRegion
{
    public class PRISMTransitionalRegionBootstrapper : MefBootstrapper
    {

        public override void Run(bool runWithDefaultConfiguration)
        {
            base.Run(runWithDefaultConfiguration);
        }

        protected override void ConfigureAggregateCatalog()
        {
            this.AggregateCatalog.Catalogs.Add(
                new AssemblyCatalog(typeof(App).Assembly));
        }

        protected override void InitializeShell()
        {
            base.InitializeShell();

            (App.Current as App).PrismCompositionContainer = this.Container;

            Application.Current.MainWindow = (Shell)this.Shell;
            Application.Current.MainWindow.Show();
        }


        protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
        {
            RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();
            mappings.RegisterMapping(typeof(TransitionElement), 
                Container.GetExportedValue<TransitionElementAdaptor>());
            return mappings;
        }


        protected override DependencyObject CreateShell()
        {
            return this.Container.GetExportedValue<Shell>();
        }



    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

 

As always here is a small demo app:

http://dl.dropbox.com/u/2600965/Blogposts/2011/01/PRISMTransitionalRegion.zip

Enjoy….Happy new year all

Cinch V2 : Question For The Reader

As some of you may know I have written a fairly popular MVVM framework called Cinch I continue to listen to peoples feedback/requests etc etc. I like to make these changes when enough requests have come through to warrant pushing out new codebase.

Unless there is of course a serious bug, in which case I will try and fix that straight away.

Question is, are you readers happy with this approach, or would you prefer to have updates as soon as possible?

They are enhancements really, and there is nothing wrong with the current codebase, but from time to time a good suggestion comes along that I like to include. Question is are you lot happy to wait for these to creep into the framework, or do you want them like now, and just have to download code again?

Could you let me know your thoughts

PS: I will not be answering these forum entries, as I just want to hear from you lot.

CinchV2 : Latest News

I have just uploaded a new set of source code files for Cinch. I have taken this opportunity to fix several issues/suggestions that people put forward, and also fixed 1 silly MEF related mistake I made.

The release notes/source code codeplex comments tell the full story, but if you are using CinchV2, you should grab the latest copy, as it has 1 important fix that you should make sure you have latest code to fix.

Thanks

Look At AOP : Getting Rid Of INPC Using Aspects

Some of you may know me, and know that I am quite into WPF, some of you may even be into WPF yourselves and come to my blog to see what posts I have here to do with WPF.

Well I just released a new article all about Aspect Orientated Programming (AOP).

I looked at 4 different AOP frameworks:

  • Castle
  • Unity
  • PostSharp
  • LinFu.AOP

Now as a WPF developer I use the INotifyPropertyChanged interface (INPC) an awful lot.

I have to say a lot of the time I am merely checking the new value does not equal current value and then calling the INotifyPropertyChanged interfaces PropertyChanged event. Not all the time mind, there are cases where something different happens in the setter….but 80% of it is bulk standard, check property and call PropertyChanged  changed event.

Which looks like this typically:

public class MainWindowViewModel : INotifyPropertyChanged
{

    private int someProperty;
    public int SomeProperty
    {
       get { return someProperty; }
       set
       {
         if (someProperty != value
         {
        someProperty=value;
        RaisePropertyChanged("SomeProperty");
         }
       }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
       if (PropertyChanged != null)
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

}

 

Now I got thinking if we could use AOP to come up with something like this, where we use some special attribute to mark standard auto properties as INPC, where the AOP framework would fire the INPC PropertyChanged event whenever a property marked up with one of these attributes was set.

public class MainWindowViewModel : INotifyPropertyChanged
{

    [INPCAttribute]
    public virtual string DummyProp1 { get; set; }

    [INPCAttribute]
    public virtual string DummyProp2 { get; set; }


    public event PropertyChangedEventHandler PropertyChanged;

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }Which got me thinking even more, perhaps if an AOP framework could do that, it may even be able to implement the entire INotifyPropertyChanged interface for me to, which would lead to classes like this:

public class DummyModel
{
    [AddINPCAttribute]
    public virtual string DummyModelProp1 { get; set; }

    [AddINPCAttribute]
    public virtual string DummyModelProp2 { get; set; }

    public virtual string DummyModelProp3 { get; set; }
}

 

The good news is that I did manage to achieve these results, and if you are interested you should read the entire article using this link:

http://www.codeproject.com/KB/miscctrl/Aspects.aspx

Please do not forget to vote…….thanks

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

Cinch + Latest Enhancements = I Am Finally Done

Ok everyone, this is hopefully it my last Cinch posting, then back to some other stuff for me.

I have this weekend made the following enhancements, and they were enhancements there was nothing wrong with codebase prior to this, but they were good ideas people gave me so I included them.

  • Altered Cinch V1 DataWrapper to take a Action in its constructor such that when the Cinch code generator is used the non auto generated part of the overall ViewModel class will be called back using the Action passed to the constructor of the DataWrapper when a property changes. Also got rid of ridiculous condtructors on the DataWrapper class, and also made it a partial class
  • Modified the Cinch code generator to support this, so when you next run the code generator you will see what it did. I basically added another callback call inside of DataWrapper<T> class
  • Altered Cinch V2 DataWrapper the same way as I did for V1 above.
  • Removed small issue in the WorkspaceData.ToString() override where I did not take into account a possible null dataValue. As you never know what this value could be (it could be any object) I have removed the ToString for the dataValue entirely. This is described at : http://cinch.codeplex.com/workitem/4917
  • Made the following classes partial
    • ValidatingObject (Cinch v1 and Cinch v2)
    • ValidatingViewModelBase (Cinch v1 and Cinch v2)
    • ViewModelBase (Cinch v1)
    • ValidatingViewModelBase (Cinch v1)
    • WorkspaceData (Cinch v2 WPF only)
  • Added a new ViewAwareStatusWindow service targeting Windows
  • Added a Non mandatory extra event to WorkSpaceData that can be used to cancel a closing of a workspace. Revised WPF demo to show this for ImageLoader workspace and left About workspace as it was to show it is not mandatory.
  • Resynced with MeffedMVVM release 58837

But that is my done with Cinch now, unless someone finds a bad bug that breaks loads of things in which case I will of course take notice, but until then Hasta La Vista Baby…..More new stuff to enjoy whoohoo

 

Enjoy

Cinch V2 Part 6 : Out Now (Also my 100th article at codeproject)

I have just released the 6th and final part in my Cinch V2 article series. This article covers Silverlight4 support using Cinch.

It can be read using this link :

http://www.codeproject.com/KB/WPF/CinchV2_6.aspx

celebrate

It is also my 100th article over at codeproject, which means a great deal to me, and if you like what I do, I would really appreciate some votes and comments for that article, so please do that, if you feel inclined.

I will be doing a few enhancements to Cinch based on some cool ideas people have suggested. But once I do that, I fully intend on making it to 200 codeproject articles or more. As such I have a massive list of stuff that I want to learn, and I will be cracking on with that, and shall also get back to properly blogging. Enough of this self promotional horse crap thing, that has been happening lately with Cinch, it just had to be done, and it has been done now, so thanks everyone and thanks for all the tuna….But me and Cinch are now done, as I have more interesting things to do.