Splittable View

Dec 21, 2010 at 8:15 AM

Hi All,

I'm a completely newbie so... let's the question: I would like to implement a splittable view in that sense: the user can decide to split the view horizontal or vertical and, as a consequence, a new viewmodel needs to be created with a corresponding view to be displayed in some way. What is the best approach ? I suppose I have to create a custom screen conductor organizing the viewmodels in a sort of binary tree, but I'm guessing may be there is some simpler.

Thanks for any suggestion,

Felix

Dec 21, 2010 at 9:59 AM

Since the splitting orientation, as I understand your scenario, is purely an UI concern, you can avoid using different view-models just to pick up different views.
A simple solution is the following:

class SplittedScreenViewModel {
	
	public bool HasHorizontalOrientation { get {...} set {...} } //has to implement INPC notifications
	
	public void ToggleOrientation() {
		HasHorizontalOrientation = !HasHorizontalOrientation;
	}
	
	public MyViewModelA MyViewModelA { get {...} set {...} } 
	public MyViewModelB MyViewModelB { get {...} set {...} } 
	...
}
<!-- SplittedScreenView -->
<UserControl ...>
	
	<Button Name="ToggleOrientation">ToggleOrientation</Button>
	...
	<ContentControl ContentTemplate="{Binding HasHorizontalOrientation, Converter={StaticResource toLayout}}"
	
	<Grid Visibility="{Binding HasHorizontalOrientation, Converter={StaticResource boolToVisibility}}">
		...
		<ContentControl Grid.Row="0" cal:View.Model={Binding MyMyViewModelA} />
		<ContentControl Grid.Row="1" cal:View.Model={Binding MyMyViewModelB} />
	</Grid>
	<Grid Visibility="{Binding HasHorizontalOrientation, Converter={StaticResource boolToVisibilityNegate}}">
		...
		<ContentControl Grid.Column="0" cal:View.Model={Binding MyMyViewModelA} />
		<ContentControl Grid.Column="1" cal:View.Model={Binding MyMyViewModelB} />
	</Grid>
	...
</UserControl>

boolToVisibility and boolToVisibilityNegate are simple IValue converters turning a bool value into a Visibility value.

Another option is using a root Conductor to host the splitted screen and leverage View.Context attached property:

class HostingViewModel : Conductor<SplittedScreenViewModel> {
	
	public HostingViewModel(SplittedScreenViewModel child) {
		this.ActivateItem(child);
	}
	
	public bool HasHorizontalOrientation { get {...} set {...} } //has to implement INPC notifications
	
	public void ToggleOrientation() {
		HasHorizontalOrientation = !HasHorizontalOrientation;
	}
	
}
class SplittedScreenViewModel {
	public MyViewModelA MyViewModelA { get {...} set {...} } 
	public MyViewModelB MyViewModelB { get {...} set {...} } 
	...
}
<!-- HostingView -->
<UserControl ...>
	...
	<Button Name="ToggleOrientation">ToggleOrientation</Button>
	<ContentControl cal:View.Model="{Binding ActiveItem}" cal:View.Context="{Binding HasHorizontalOrientation, Converter={StaticResource toContextConverter}}"
	...
</UserControl>
 
<!-- SplittedScreenView.Horizontal -->
<UserControl ...>
	...
	<Grid>
		...
		<ContentControl Grid.Row="0" cal:View.Model={Binding MyMyViewModelA} />
		<ContentControl Grid.Row="1" cal:View.Model={Binding MyMyViewModelB} />
	</Grid>
	...
</UserControl>
 
<!-- SplittedScreenView.Vertical -->
<UserControl ...>
	...
	<Grid>
		...
		<ContentControl Grid.Column="0" cal:View.Model={Binding MyMyViewModelA} />
		<ContentControl Grid.Column="1" cal:View.Model={Binding MyMyViewModelB} />
	</Grid>
	...
</UserControl>

toContextConverter is a IValue converter turning a bool into "Vertical" or "Horizontal" string

Dec 21, 2010 at 2:09 PM
Edited Dec 21, 2010 at 3:39 PM

Thanks Marco for the reply,

Well, It is not just changing the splitting, but actually *divide* the view in two parts ( and possibly *recursively* for any new view born ), similar to what did the intellipad MS editor(*), not sure the view model can be the same ( even if the Model for sure is ), since each view can apply different filters on the real data behind.

 

(*) http://blogs.msdn.com/b/intellipad/archive/2008/10/29/intellipad-samples-october-ctp.aspx this prohect is no longer mantained by MS, AFAIK.

Felice.

 

Dec 21, 2010 at 5:06 PM
Edited Dec 21, 2010 at 5:25 PM

I would definitely go with the binary tree shape for the VM.

You can follow my second sample line. Each node could be a Conductor<>, in which you initially load a "content" VM.
When the user asks to split a content screen, you can replace it in the parent conductor with a new splitted screen, containing two nested conductors (and a content screen for each of them).
You may also provide some root level "macro" to simplify management of the structure.
Using the binding the views will follow the same structure without any hassle. 

Dec 21, 2010 at 7:40 PM

Thanks you Marco,

Knowing that there is no built in solution let me more confident in creating something.

 

Felice.