• Microsoft LightSwitch – Multi Select Checklist

    Posted Dec 15th, 2011 By in LightSwitch With| No Comments | Microsoft LightSwitch – Multi Select Checklist
    Share on TwitterSubmit to StumbleUponSave on DeliciousDigg ThisSubmit to reddit

    Please, HELP!

    I have put together a prototype solution that solves a scenario that requires me to manage a one to many relationship using a checklist of items.  I am almost there, but I am having some problems trying to finish this off.

    First, here is the solution I come with so far…

    Here is a template project that you can take a look at and play with. Note that there is a requisite for having Telerik Silverlight controls installed, which you can download a trial from Telerik…. Template Project Download.

    The template project contains a screen where a default grid is used for adding child entities. As well, an additional element on the screen displays a custom checklist control.

    The overall solution is a health and safety management application that is used to keep track of, and report on, organizational health and safety information. A screen has been created to display the details of an injury incident. These details include master-detail type information such as; the parts of the body injured, the causes of the incident, causes of the injuries, and the natures of the injury.

    These master-detail type relationships can be easily managed via the out-of-the-box grids that can be applied to the screen. For example, the following screenshot shows where one or more causes of incident can be added to the incident….

    Simple grid of related causes of incident values.

    What I have been able to do is implement a checklist enabled custom control that I created using the Telerik Silverlight GridView control…

    The grid itself is bound to a screen data item of BodyPart entities…

    Binding the custom control to the BodyPart entities was the easy part. Here is the XAML used for the control itself…

    <UserControl x:Class="LightSwitchApplication.UserControls.BodyPartSelectionList"
        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:DesignHeight="300" d:DesignWidth="294"
                 xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation">
        <Grid x:Name="LayoutRoot" Background="White">
            <telerik:RadGridView Name="gvBodyParts" Margin="0,0,0,0"
                                 ItemsSource="{Binding Screen.BodyParts}"
                                 AutoGenerateColumns="False" SelectionMode="Multiple"
                                 ShowGroupPanel="False" ShowColumnHeaders="False"
                                 ShowInsertRow="False" RowIndicatorVisibility="Collapsed"
                                 IsReadOnly="True" SelectionChanged="gvBodyParts_SelectionChanged"
                                 CanUserDeleteRows="False" CanUserInsertRows="False"
                                 ActionOnLostFocus="None" EditTriggers="None"
                                 IsReadOnlyBinding="{Binding}" Height="300" IsScrolling="False">
                <telerik:RadGridView.Columns>
                    <telerik:GridViewSelectColumn />
                    <telerik:GridViewDataColumn
                        DataMemberBinding="{Binding Id}" Width="20" />
                    <telerik:GridViewDataColumn
                        DataMemberBinding="{Binding BodyPartName}"
                        Width="200" Header="Body Part" />
                </telerik:RadGridView.Columns>
            </telerik:RadGridView>
        </Grid>
    </UserControl>

    Then, in the code behind of the control, I added an event handler that I could later consume on the LightSwitch screen. For example…

    namespace LightSwitchApplication.UserControls
    {
        public partial class BodyPartSelectionList : UserControl
        {
    
           public event EventHandler SelectedBodyPartChanged;
    
           protected virtual void OnSelectedBodyPartChanged(EventArgs e)
            {
                if (SelectedBodyPartChanged != null)
                    SelectedBodyPartChanged(this, EventArgs.Empty);
            }
            private void gvBodyParts_SelectionChanged(object sender, Telerik.Windows.Controls.SelectionChangeEventArgs e)
            {
                if (!_initialLoad)
                {
                    if (e.AddedItems != null && e.AddedItems.Count > 0)
                    {
                        BodyPart bodyPart = e.AddedItems[0] as BodyPart;
                        if (bodyPart != null)
                        {
                            _selectedBodyPartId = bodyPart.Id;
                            _isSelected = true;
                        }
                    }
                    else
                    {
                        BodyPart bodyPart = e.RemovedItems[0] as BodyPart;
                        if (bodyPart != null)
                        {
                            _selectedBodyPartId = bodyPart.Id;
                            _isSelected = false;
                        }
                    }
                    OnSelectedBodyPartChanged(e);
                }
            }
        }
    }

    Back in the screen itself, I added some goodness to capture the event that gets fired in the custom control…

    namespace LightSwitchApplication
    {
        public partial class InjuryIncident
        {
    
            partial void InjuryIncident_Created()
            {
                _bodyPartsSelectionProxy = this.FindControl("BodyPartsSelectionGrid");
                _bodyPartsSelectionProxy.ControlAvailable += OnBodyPartsSelectionGrid_ControlAvailable;
                _bodyPartsSelectionProxy.ControlUnavailable += OnBodyPartsSelectionGrid_ControlUnavailable;
    
            }
    
            void OnBodyPartsSelectionGrid_ControlAvailable(object sender, ControlAvailableEventArgs e)
            {
                BodyPartSelectionList bodyPartSelectionList = e.Control as BodyPartSelectionList;
                bodyPartSelectionList.SelectedBodyPartChanged += BodyPartsSelectionGrid_SelectionChanged;
                bodyPartSelectionList.InjuryBodyPartsAssigned = InjuryBodyParts.ToArray();
            }
    
            void OnBodyPartsSelectionGrid_ControlUnavailable(object sender, ControlUnavailableEventArgs e)
            {
                BodyPartSelectionList bodyPartSelectionList = e.Control as BodyPartSelectionList;
                bodyPartSelectionList.SelectedBodyPartChanged += BodyPartsSelectionGrid_SelectionChanged;
            }
    
            void BodyPartsSelectionGrid_SelectionChanged(object sender, EventArgs e)
            {
                BodyPartSelectionList bodyPartSelectionList = sender as BodyPartSelectionList;
                int bodyPartId = bodyPartSelectionList.SelectedBodyPartId;
                bool isSelected = bodyPartSelectionList.IsSelected;
                if (_bodyPartSelectionOperation)
                {
                    _bodyPartSelectionOperation = false;
                    UpdateIncidentBodyParts(bodyPartId, isSelected);
                    _bodyPartSelectionOperation = true;
                }
            }
    
            private void UpdateIncidentBodyParts(int BodyPartId, bool IsSelected)
            {
    
                this.Details.Dispatcher.BeginInvoke(() =>
                    {
                        InjuryBodyPart injuryBodyPart;
                        if (IsSelected)
                        {
                            BodyPart bodyPart = (from bp in BodyParts where bp.Id == BodyPartId select bp).First();
                           // injuryBodyPart = DataWorkspace.ApplicationData.InjuryBodyParts.AddNew();
                            injuryBodyPart =  this.InjuryBodyParts.AddNew();
                            injuryBodyPart.Incident = this.IncidentProperty;
                            injuryBodyPart.BodyPart = bodyPart;
                        }
                        else
                        {
                            injuryBodyPart = (from ibp in InjuryBodyParts
                                              where (ibp.BodyPart.Id == BodyPartId)
                                              && (ibp.Incident.Id == this.IncidentProperty.Id)
                                              select ibp).FirstOrDefault();
    
                            InjuryBodyParts.SelectedItem = injuryBodyPart;
                            InjuryBodyParts.SelectedItem.Delete();
                            //InjuryBodyParts.SelectedItem.Delete();
    
                        }
                  });
             }
        }
    }

    Now I am at a point where I need to bind the body parts that are assigned to the incident, and have those show as checked in the grid.

    Any ideas?

    I tried creating a property on the custom control that accepted a collection of body part entities, and then checked each of the body parts found in the grid, but I ran into some problems. For example:

    public InjuryBodyPart[] InjuryBodyPartsAssigned
            {
                set
                {
                    _initialLoad = true;
                    gvBodyParts.SelectedItems.Clear();
                    foreach (InjuryBodyPart injuryBodyPart in value)
                    {
                        gvBodyParts.SelectedItems.Add(injuryBodyPart.BodyPart);
                    }
                    _initialLoad = false;
                }
            }

    Is there a better approach to this? I would prefer to do this via the checklist control I implemented, and not have to go back to the default grid.

    Any ideas would be appreciated. (I’ll update the blog with any solution/resolution that I find).

     


    • delicious
    • digg
    • reddit

    Paul
    My name is Paul Patterson and I am a software developer who has a keen interest in technology, including; open source, .Net, and anything Interweb. When not crafting some code, I can be found learning something new about photography. As well, I occasionally escape to the "music room" with my guitars to practice a few scales and then jam with my favourite FM radio stations.

Leave a Reply


No comments yet. Be the first!

© Copyright Paul S Patterson - Please, no touchie. :)