Posts Tagged ‘Image repositioning’
An Experiment In Caliburn Micro
In this blog I will explain my experiment with Caliburn Micro. The business logic of this app is
- It should display a list of images
- Add the image to the canvas when the user selected an image
- Drag the Image and Position the Image where ever the user required
- For dragging/rotation/resize the image I used an Adorner control. You can get more details about the control here.
I have to add Images displayed in a list box to a canvas. Pretty simple 🙂 and helped me a lot to learn Caliburn Micro. Before going further I wanted to say that the app may not be a full MVVM model, you will come to know as you proceed. I am working on it to make it completely MVVM complaint.
Below is the screen shot of the Silverlight app.
Two buttons are there on the top.
- Show Text: button will load User control that will have a UI with some text box and combo box.
- Image Controls: Button will load the user control displayed above.
Bare with my naming, I am very poor in it.
When the user clicks on any of these button we need to show the respective View in the left hand side. I used Caliburn Micro as my MVVM frame work.
My project structure is below
- Views: Contains my XAML files
- ViewModels: contains my view model of the views
- ValueObject: contains the value object class I used in this app
- Messages: I used EventAggregator provided by Caliburn Micro to enable messaging between ViewModels. This folder contains the Class I used for messaging between ViewModels.
- Controls: contains custom controls I used in this app.
- Adorner: contains the Adorner controls
- Let’s jump into the code
TabView
This is the main view which calls other other user controls- XAML
<navigation:Page x:Class="MVVMTracer.Views.TabView" 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" xmlns:tl="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Layout.Toolkit" xmlns:we="clr-namespace:MVVMTracer.Controls" mc:Ignorable="d" xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation" d:DesignWidth="640" d:DesignHeight="480" Title="TabView Page"> <UserControl.Resources> <DataTemplate x:Key="shapeTemplate"> <we:ControlBase Width="{Binding Width}" Height="{Binding Height}"/> </DataTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="40"></RowDefinition> <RowDefinition></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="200"></ColumnDefinition> <ColumnDefinition></ColumnDefinition> </Grid.ColumnDefinitions> <StackPanel Grid.Row="0" Orientation="Horizontal" Height="30"> <Button x:Name="ShowTextControls" Content="Show Text"></Button> <Button x:Name="ShowImageControls" Content="Image Controls"></Button> </StackPanel> <tl:TransitioningContentControl Grid.Row="1" Grid.Column="0" x:Name="ActiveScreen"></tl:TransitioningContentControl> <we:CustomItemsCollection x:Name="DisplayControls" Grid.Row="1" Grid.Column="1"> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas Background="AliceBlue"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> </we:CustomItemsCollection> </Grid> </navigation:Page>
In the above xaml you might notice that I used TransitioningContentControl. This is the control I am going to use to show different UserControl based on the user request. By the way TransitioningContentControl is part of Silverlight Tool kit,
Here I used a CustomItemsCollection to add my dynamically added controls. CustomItemsCollection is a control derived from ItemsControl. I will show the implementation of it later.
TabViewModel.cs
using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using Caliburn.Micro; using MVVMTracer.Adorners; using MVVMTracer.Controls; using MVVMTracer.Messages; namespace MVVMTracer.ViewModels { public class TabViewModel:PropertyChangedBase,IHandle<Messages.ImageSelectionChanged> { public TabViewModel() { EventAggregatorContainer.EventAggregator.Subscribe(this); } private object _activeScreen; private Adorner _adorner = new Adorner(); private Canvas _parentCanvas = new Canvas(); public object ActiveScreen { get { return _activeScreen; } set { _activeScreen = value; NotifyOfPropertyChange(() => ActiveScreen); } } public void ShowTextControls() { ActiveScreen = new ShowTextViewModel(); } public void ShowImageControls() { ShowImageControlViewModel imgViewModel = new ShowImageControlViewModel(); ActiveScreen = imgViewModel; } public void Handle(Messages.ImageSelectionChanged message) { ControlBase ctrl = ShapeFactory.GetShape(ShapeType.Image, _parentCanvas, _adorner); ctrl.Source = message.CurrentImage; this.AddToUICollection(ctrl); } private void AddToUICollection(ControlBase control) { if (_displayControls == null) { _displayControls = new System.Collections.ObjectModel.ObservableCollection<UIElement>(); _adorner.Height = 0; _adorner.Width = 0; _parentCanvas.Children.Add(_adorner); _displayControls.Add(_parentCanvas); } control.DrawControl(); control.Height = 100; control.Width = 100; _parentCanvas.Children.Add(control); NotifyOfPropertyChange(() => DisplayControls); } private System.Collections.ObjectModel.ObservableCollection<UIElement> _displayControls; public System.Collections.ObjectModel.ObservableCollection<UIElement> DisplayControls { get { return _displayControls; } private set { _displayControls = value; NotifyOfPropertyChange(() => DisplayControls); } } } }
The above code explains the ViewModel of TabView. As I mentioned in the beginning it may not completely satisfies MVVM pattern. I will explain the reason. As per my requirement I wanted to add Images to my Canvas and allow the user to reposition it.
To achieve the requirement I initially binded list of UIElement that consist of my Images to the CustomItemsCollection. But the issue I faced is I couldn’’t drag the image to different location. So I find out a work around. The work around is create a Canvas in Viewmodel and add the canvas to DisplayControls. Then add the images to the canvas object. By adding Canvas to DisplayControls will internally bind the Canvas object and its children to CustomItemsCollection in the View.
In this app I used EventAggregator to enable Messaging between ViewModels. To enable Messaging in CaliburnMicro the subscriber should Implement IHandle interface. You can see in the above code I implemented IHandle interface and subscribed to ImageSelectionChanged. Any publisher who publish ImageSelectionChanged message will be notified to TabViewModel.
The custom Control to display Image is not in MVVM structure.
You can find the Image listing control and other piece of codes in the uploaded source code.
You can download the code here