Friday, March 26, 2010

Container-Child Relation for Windows.Forms with no MdiContainer

In a Windows.Forms application, it’s fairly easy to make use of a MdiContainer in a Parent form and create new forms inside it’s container. However, the same result can be obtained with no MdiContainer at all.

You just create a new Form, set it’s TopLevel property to false and add it to the Controls collection of another Form.

ChildForm form = new ChildForm();
form.TopLevel = false;

ParentForm.Controls.Add( form );
form.Show();



As a result, you get a fully draggable child form which can also be minimized and maximized. The only difference between this and MdiContainer would be the lack of a scroller automatically added by the MdiContainer.






Wednesday, March 24, 2010

Individual DataTemplates for Programmatically Populated Silverlight TreeView

Silverlight TreeView can be populated both declaratively and programmatically. In complex scenarios, the latter is preferred. This simple tutorial demonstrates how individual DataTemplates can be selected for newly created items.

Let’s start with creating a business class we will use to create tree items:

public class Person
{
public string Name { get; set; }
public string Surname { get; set; }

public override string ToString()
{
return string.Format( "{0} {1}", Name, Surname );
}
}





Let’s also create the XAML containing a TreeView and two distinct DataTemplates for tree items. Note that both templates contain explicit bindings to model’s properties: first template will render a tree item as text while the second will render it as a button.



In the latter case we’d also like to be able to determine the business entity bound to the button the user clicks.




<UserControl 
xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
x:Class="SilverlightTutorial1.MainPage"
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"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<UserControl.Resources>
<DataTemplate x:Key="TreeViewItemTemplate1">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
<DataTemplate x:Key="TreeViewItemTemplate2">
<Button Content="{Binding}" Tag="{Binding}" Click="Button_Click" />
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot">
<controls:TreeView x:Name="TheTree">

</controls:TreeView>
</Grid>
</UserControl>





Items will be created programmatically and the trick is to set an instance of the business entity as TreeViewItem’s Header and in the same time set TreeViewItem’s HeaderTemplate to point to a DataTemplate, picking one from resources.




public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();

TreeViewItem item = InitNodeFromTemplate1();
InitNodeFromTemplate2(item);
}

private TreeViewItem InitNodeFromTemplate1()
{
TreeViewItem item = new TreeViewItem();

item.Header = new Person() { Name = "John", Surname = "Kowalski" };
item.HeaderTemplate = (DataTemplate)this.Resources["TreeViewItemTemplate1"];

TheTree.Items.Add( item );

return item;
}

private void InitNodeFromTemplate2( TreeViewItem Parent )
{
TreeViewItem item = new TreeViewItem();

item.Header = new Person() { Name = "Tim", Surname = "Malinowski" };
item.HeaderTemplate = (DataTemplate)this.Resources["TreeViewItemTemplate2"];

Parent.Items.Add( item );
}

private void Button_Click( object sender, RoutedEventArgs e )
{
Button b = sender as Button;
Person p = b.Tag as Person;

MessageBox.Show( p.ToString() );
}





Note that the button’s click handler retrieves the business entity from the button’s Tag property and this is possible because of the binding inside the TreeViewItemTemplate2 DataTemplate.



The output of the above example looks like this:







Note that DataTemplates can be created programmatically. This is described in this blog note by Tamir Khason.

Friday, March 19, 2010

Silverlight Visual Tree Walker

Constrained by Silverlight’s FindName method and inspired by a blog note by Jim Baltzell-Gauthier and my own implementation of tree walker for ASP.NET, I came up with a corresponding code snippet for Silverlight.

What you get is two extension methods, Find to search for a single child component and FindAll to search for all children matching specified predicate.

Note that this way you have a complete freedom of what you would like to find. Controls of specific name, specific type, anything – is just a matter of correct predicate.

public static class VisualTreeWalker
{
public static FrameworkElement Find(
this DependencyObject Parent,
Predicate<FrameworkElement> Predicate )
{
if ( Parent is FrameworkElement )
if ( Predicate( (FrameworkElement)Parent ) )
return (FrameworkElement)Parent;

foreach ( DependencyObject child in GetChildren( Parent ) )
{
try
{
FrameworkElement childElement = child as FrameworkElement;
if ( childElement != null )
if ( Predicate( childElement ) )
return childElement;
}
catch { }
}
return null;
}

public static FrameworkElement[] FindAll(
this DependencyObject Parent,
Predicate<FrameworkElement> Predicate )
{
List<FrameworkElement> ret = new List<FrameworkElement>();

FindAllHelper( Parent, Predicate, ret );

return ret.ToArray();
}

private static void FindAllHelper(
DependencyObject Parent,
Predicate<FrameworkElement> Predicate,
List<FrameworkElement> results )
{
if ( Parent is FrameworkElement )
if ( Predicate( (FrameworkElement)Parent ) )
results.Add( (FrameworkElement)Parent );

// rekursja
foreach ( DependencyObject child in GetChildren( Parent ) )
{
FindAllHelper( child, Predicate, results );
}
}

private static IEnumerable<DependencyObject>
GetChildren( DependencyObject Parent )
{
int childCount = VisualTreeHelper.GetChildrenCount( Parent );

for ( int i = 0; i < childCount; i++ )
{
yield return VisualTreeHelper.GetChild( Parent, i );
}
}
}





As an example, suppose you have a complex Silverlight Grid, called TheGrid, and somewhere deeply inside it there are three ToggleButtons (that was an original case which motivated me to write the above snippet). Now I just iterate:




foreach ( ToggleButton toggleButton in
TheGrid /* parent control */
.FindAll( c => c is ToggleButton ) /* searching */
.Select( f => f as ToggleButton ) ) /* projection - casting */
{
/* now I got all my child controls I need */
}



Thursday, March 11, 2010

User Interface idea for Visual Studio 2012

Here’s a brilliant research idea for building GUI of integrated development environments:

http://www.cs.brown.edu/people/acb/codebubbles_site.htm

I hope to be able to work like this with Visual Studio 2012.