DragDrop part2

This is similar to the dragdrop we did in this post but instead of dragging listbox items we use datagrid rows

you can see a demo here and source is here

Advertisements

DataGridRow and Tooltip

We can use Popup to display a tooltip at the row level in the datagrid

Here is sample code

<UserControl x:Class=”slapp1a.Page”
    xmlns=”http://schemas.microsoft.com/client/2007
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml
             xmlns:data=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”
             Width=”600″ Height=”600″>
    <UserControl.Resources>
        <DataTemplate x:Key=”dt”>
            <StackPanel Orientation=”Horizontal”>
            <TextBlock Text=”This is a tooltip for the Row with content : “></TextBlock>
                <TextBlock Text=”{Binding}”></TextBlock>
            </StackPanel>
        </DataTemplate>
    </UserControl.Resources>
    <Grid x:Name=”LayoutRoot” Background=”White”>
        <data:DataGrid x:Name=”dataGrid1″
                       Height=”400″
                       Width=”450″
                       Margin=”0,5,0,10″
                       AutoGenerateColumns=”True” />
        <Popup x:Name=”myPopup”>
            <ContentControl x:Name=”PopupContent” ContentTemplate=”{StaticResource dt}”></ContentControl>
        </Popup>
    </Grid>
</UserControl>

and in codebehind. all we are doing is handling the PreparingRow event to attach evenhandlers for MouseEvents, where we position the popup and set the content for the contentcontrol in the popup.

Did not try it, but we could change it use storyboards to introduce some delay before showing the tooltip and ofcourse customize the appearance


public partial class Page : UserControl
    {
        public Page()
        {
            InitializeComponent();
            dataGrid1.ItemsSource = new string[] { “data 1”, “data 2” };
            dataGrid1.PreparingRow += new EventHandler<DataGridRowEventArgs>(dataGrid1_PreparingRow);           
        }        void dataGrid1_PreparingRow(object sender, DataGridRowEventArgs e)
        {
            e.Row.MouseEnter += new MouseEventHandler(Row_MouseEnter);
            e.Row.MouseLeave += new MouseEventHandler(Row_MouseLeave);
        }

        void Row_MouseLeave(object sender, MouseEventArgs e)
        {
            myPopup.IsOpen = false;
        }

        void Row_MouseEnter(object sender, MouseEventArgs e)
        {           
            PopupContent.Content = (sender as DataGridRow).DataContext;
            Point p = e.GetPosition(null);
            myPopup.HorizontalOffset = p.X;
            myPopup.VerticalOffset = p.Y;
            myPopup.IsOpen = true;
        }
      
    }

 

Storyboard and DataTemplate

This post shows animating Item(s) in datatemplate
<UserControl x:Class=”SilverlightApplication9.Page”
xmlns=”http://schemas.microsoft.com/client/2007
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml
xmlns:data=”clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data”
Width=”600″ Height=”600″>
<UserControl.Resources>
<Storyboard x:Key=”sbMouseEnter”
Storyboard.TargetProperty=”FontSize”>
<DoubleAnimation From=”10″ To=”12″ Duration=”0:0:1″ />
</Storyboard>
<Storyboard x:Key=”sbMouseLeave”
Storyboard.TargetProperty=”FontSize”>
<DoubleAnimation From=”12″ To=”10″ Duration=”0:0:1″ />
</Storyboard>
<DataTemplate x:Key=”dt”>
<TextBlock Padding=”5,0,5,0″ FontSize=”10″
MouseEnter=”TextBlock_MouseEnter”
MouseLeave=”TextBlock_MouseLeave”
Text=”{Binding FirstName}”/>
</DataTemplate>
</UserControl.Resources>
<Canvas Width=”500″ Height=”500″>
<data:DataGrid x:Name=”dataGrid5″
Height=”100″ Width=”450″ Margin=”0,5,0,10″ >
<data:DataGrid.Columns>
<data:DataGridTemplateColumn Header=”Name”
CellTemplate=”{StaticResource dt}”>
</data:DataGridTemplateColumn>
</data:DataGrid.Columns>
</data:DataGrid>
<ListBox Margin=”150″ Height=”100″ Width=”200″
x:Name=”list1″ ItemTemplate=”{StaticResource dt}”></ListBox>
</Canvas>
</UserControl>

we create 2 storyboards without the target property set, and datatemplate, we use the same datatemplate in datagrid as well as listbox and when the mouseenter and mouseleave events we could do some animation, for this sample we will do fontsize

we bind the controls to some data and we handle the mouse events on the textbox to begin the storyboard after setting the targetproperty


List<Customer> customers = new List<Customer>();
customers.Add(new Customer { FirstName = “John”, LastName = “Doe” });
customers.Add(new Customer { FirstName = “Jane”, LastName = “Doe” });
list1.ItemsSource = dataGrid5.ItemsSource = customers;

private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
{
Storyboard sb = Resources[“sbMouseEnter”] as Storyboard;
Storyboard.SetTarget(sb.Children[0],(sender as TextBlock));
sb.Begin();
}
private void TextBlock_MouseLeave(object sender, MouseEventArgs e)
{
Storyboard sb = Resources[“sbMouseLeave”] as Storyboard;
Storyboard.SetTarget(sb.Children[0], (sender as TextBlock));
sb.Begin();
}

Drag and Drop in Silverlight

Let’s do some drag & drop of Items between listboxes. The same thing could be used for rearranging items in a control(say listbox).
we can even show what item is getting dragged around
you can see a demo here 

(Note: updated code if you drag and drop between listboxes it should be fine. Error checking is not there, it will blowup if you click in the empty space in the listbox and mouseup and down on a item without dragging, need to fix those issues)

In the sample, I am using 3 listboxes each having different Itemtemplates

for the HitTest to work the listboxes have to be given some Background otherwise HitTest wont work

we are going to use the same events MouseLeftButtonDown, MouseLeftButtonUp, and MouseMove events
the example here is using all listboxes, so the code is going to refer to listboxes

In XAML we drop a PopUp control with a ContentControl as child and set the opacity to .5, just to give it some effect

We start the DragDrop when the mouseleftbuttondown event is raised, we do a hittest and see if it is a listbox, If so start DragDrop

we are assuming that all the listboxes will have ItemTemplates defined

void StartDragDrop(ListBox sender,MouseEventArgs e)
{
DataTemplate dt = sender.ItemTemplate as DataTemplate;
dragSource = sender;
popupContent.Content = sender.SelectedItem;
popupContent.ContentTemplate = dt;
popup1.CaptureMouse();
captured = true;
mouseVerticalPosition = e.GetPosition(null).Y;
mouseHorizontalPosition = e.GetPosition(null).X;
popup1.HorizontalOffset = mouseHorizontalPosition;
popup1.VerticalOffset = mouseVerticalPosition;
}

We are getting the Datatemplate of the listbox and SelectedItem of the listbox we are interested in and setting the content of the ContentControl in the PopUp to the selectedItem of the ListBox.
Set the ContentTemplate property of the ContentControl to this DataTemplate.
Make sure we capture the mouse
For positioning the popup we set the HorizontalOffset and VerticalOffset properties of the Popup Control we added in the XAML

when the mouse moves we are going to adjust the same properties(HorizontalOffset and VerticalOffset) of the Popup Control to reflect mouse movement

when the MouseLeftButtonUp is raised we do a hitTest again to see the Destination(listBox)

void Page_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
List elements = (List)this.HitTest(e.GetPosition(null));
for(int i=0;i<elements.Count;i++){
ListBox lb = elements[i] as ListBox;
if (lb != null){
(lb.ItemsSource as ObservableCollection).Add(popupContent.Content as Customer);
(dragSource.ItemsSource as ObservableCollection).Remove(popupContent.Content as Customer);
break;
}
}
captured = false;
popupContent.Content = null;
popupContent.ContentTemplate = null;
popup1.ReleaseMouseCapture();
mouseVerticalPosition = -1;
mouseHorizontalPosition = -1;}  

 


Add and remove Items as necessary and we have to make sure we set the Content and ContentTemplate properties of the ContentControl in the Popup to null, release the mousecapture

download the updated source here

GroupBox

Here is a sample template for groupbox in silverlight (mostly from groupbox in WPF)
you can download the source here

Silverlight wizard

This sample shows how we can use modal dialog to create a wizard in silverlight which helps user through a series of steps.
when the user goes through all the steps data is returned to the page

see a demo( you will have to click once on demo link and click again on the file, until I figure out a better way)

you specify the Content of the wizard using wizard steps, the following snippet shows how we create a wizard

<UserControl x:Class=”WizardApp.ModalPage”
    xmlns=”http://schemas.microsoft.com/client/2007
    xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml
    xmlns:local=”clr-namespace:WizardApp;assembly=WizardApp”
    Width=”400″ Height=”300″>
    <Border BorderBrush=”Beige” CornerRadius=”5″
            BorderThickness=”4″>
        <Grid x:Name=”LayoutRoot”
          Background=”AliceBlue”>
        <local:Wizard x:Name=”wz”
                       Margin=”5″>
            <local:Wizard.Steps>
            <local:WizardStep Header=”Personal”>
                    <Grid Margin=”10″>
                        <Grid.RowDefinitions>
                            <RowDefinition Height=”40″ />
                            <RowDefinition Height=”40″ />
                          
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width=”150″ />
                            <ColumnDefinition />
                        </Grid.ColumnDefinitions>
                        <TextBlock Text=”FirstName”
                                   Margin=”2″></TextBlock>
                        <TextBox Grid.Column=”1″
                                 Margin=”2″
                                 Text=”{Binding FirstName, Mode=TwoWay}”></TextBox>
                        <TextBlock Grid.Row=”1″
                                   Margin=”2″
                                   Grid.Column=”0″
                                   Text=”LastName”></TextBlock>
                        <TextBox Grid.Row=”1″
                                 Margin=”2″
                                 Grid.Column=”1″
                                 Text=”{Binding LastName, Mode=TwoWay}”></TextBox>
                      
                    </Grid>
                </local:WizardStep>
            …
          </local:Wizard.Steps>
        </local:Wizard>
    </Grid>
        </Border>
</UserControl>

In the sample we click the button to start the wizard

ws1.jpg

When the wizard opens first step if selected and content of the first step is displayed

ws2.jpg

we navigate between the steps using previous and next buttons and click finish in the last step

ws3.jpg

ws4.jpg

The Wizard step headers will be placed in a custom panel which spaces the headers of the steps to fill the width of the wizard

The data entered by the user in the wizard will be shown in the page

ws5.jpg

What this sample doesnt have

It doesnt do any validations
It doesnt have any styles
I did not add code to display the steps vertically
Wizard doesn’t have cancel button, to cancel the wizard and all the other user friendly features

You can download the sample
here

ModalDialog

Displaying a ModalDialog in Silverlight is simple, thanks to Karen Corby for providing a reusable class
you can download sample code for ModalDialog here

how to use it

copy the code for class into the project
Create a page(“ModalPage”) with the content we want to be displayed in ModalDialog
when it is time to display the dialog, all we need to do is add couple of lines of code

ModalDialog.Closed += new EventHandler<ModalDialogClosedEventArgs>(ModalDialog_Closed);
//”ModalPage” is the name of the page we created
ModalDialog.Show(new SolidColorBrush(Colors.LightGray), .5, new ModalPage());
 void ModalDialog_Closed(object sender, ModalDialogClosedEventArgs e)
 {
    if (e.Result == DialogResult.OK)
        //do something
    else
  //do something
 }