0

I know this is a very specific question, but I'm trying to get a grasp on the CSLA framework. I've successfully loaded up the "Sample N-Tier" application that can be found here:

http://lhotka.net/files/csla40/CslaSamples-4.3.13.zip

The Sample N-Tier silverlight application allows you to add LineItem objects to a collection LineItems, which, along with a Customer Name and Customer ID field make up the Order object.

I'm trying to expand the functionality of the app as an exercise making the line items deletable. The code below is from the OrderVM.cs file and defines the functionality of the "Add" button click event. It invokes the Model.LineItems.AddNew() method, which doesn't take any parameters. I want to delete the selected LineItem, rather than just the first item, as I've got it coded write now. My code works, but I cannot figure out how to retrieve a LineItem object or an index/id of the line that I have currently selected.

namespace SilverlightUI
{
  public class OrderVm : ViewModel<BusinessLibrary.Order>
  {
    public OrderVm()
    {
      //BeginRefresh(BusinessLibrary.Order.NewOrder);
      BeginRefresh(callback => BusinessLibrary.Order.GetOrder(231, callback));
    }

    protected override void OnError(Exception error)
    {
      Bxf.Shell.Instance.ShowError(error.Message, "Error");
    }

    public override void AddNew(object sender, ExecuteEventArgs e)
    {
      Model.LineItems.AddNew();
    }
    public override void Remove(object sender, ExecuteEventArgs e)
    {
        //Bxf.Shell.Instance.ShowError(Model.LineItems.AllowRemove.ToString(), "Delete");
        if(Model.LineItems.Count>0)
            Model.LineItems.RemoveAt(0);        
    }
  }
}

Could someone explain how to go about retrieving a LineItem Object from the selected DataGrid Row?

Thanks!

EDIT: Posted below is the XAML for the OrderEdit.xaml file.

    <UserControl
        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:csla="clr-namespace:Csla.Xaml;assembly=Csla.Xaml"
        xmlns:cslaRules="clr-namespace:Csla.Rules;assembly=Csla"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" 
        xmlns:my="clr-namespace:SilverlightUI" 
        xmlns:System="clr-namespace:System;assembly=mscorlib"
        xmlns:c="clr-namespace:System.Windows.Controls;assembly=System.Windows"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
        x:Class="SilverlightUI.OrderEdit"    
        mc:Ignorable="d"
        d:DesignHeight="410" d:DesignWidth="667" 
        Loaded="UserControl_Loaded">

      <UserControl.Resources>
        <ResourceDictionary>
          <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="./Themes/CslaSampleResources.xaml" />
          </ResourceDictionary.MergedDictionaries>

          <CollectionViewSource x:Key="orderVmViewSource" d:DesignSource="{d:DesignInstance my:OrderVm, CreateList=True}" />
          <CollectionViewSource x:Key="orderVmLineItemsViewSource" Source="{Binding LineItems, Source={StaticResource orderVmViewSource}}" />
        </ResourceDictionary>
      </UserControl.Resources>

      <Border Padding="0,10,0,0" CornerRadius="10,10,0,0">
        <Border.Background>
          <LinearGradientBrush EndPoint="1.005,0.5" StartPoint="0,0.5">
            <GradientStop Color="#7FFFFFFF" Offset="0"/>
            <GradientStop Color="#99FFFFFF" Offset="1"/>
          </LinearGradientBrush>
        </Border.Background>

        <Grid x:Name="LayoutRoot" DataContext="{Binding Source={StaticResource orderVmViewSource}}">
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>

          <TextBlock Text="Customer Id:" Grid.Column="0" Grid.Row="0" Style="{StaticResource LabelTextStyle}" />
          <TextBox Grid.Column="1" Grid.Row="0" x:Name="idTextBox" Text="{Binding Model.Id, Mode=OneWay}" Style="{StaticResource TextBoxStyle}" />

          <TextBlock Text="Customer Name:" Grid.Column="0" Grid.Row="1" Style="{StaticResource LabelTextStyle}" />
          <TextBox Grid.Column="1" Grid.Row="1" x:Name="customerNameTextBox" Text="{Binding Model.CustomerName, Mode=TwoWay, ValidatesOnNotifyDataErrors=False}" Style="{StaticResource TextBoxStyle}" />
          <!--<csla:PropertyInfo Property="{Binding Path=Model.CustomerName}" x:Name="pi" />-->

          <TextBlock Grid.Row="2" Grid.ColumnSpan="2" Text="orders" Style="{StaticResource SubHeadingTextStyle}" Margin="10,15,0,0" />

          <sdk:DataGrid Grid.Row="3" Grid.ColumnSpan="2" 
                        AutoGenerateColumns="False" 
                        ItemsSource="{Binding Model.LineItems}"
                        x:Name="lineItemsDataGrid" 
                        RowDetailsVisibilityMode="VisibleWhenSelected" 
                        RowBackground="{x:Null}" 
                        BorderBrush="{x:Null}" 
                        HorizontalGridLinesBrush="{x:Null}" 
                        VerticalGridLinesBrush="{x:Null}" 
                        GridLinesVisibility="None" 
                        Background="White" 
                        ColumnHeaderHeight="35"
                        ColumnHeaderStyle="{StaticResource DataGridHeaderStyle}"
                        RowStyle="{StaticResource DataGridRowStyle}"
                        CellStyle="{StaticResource DataGridCellStyle}">
            <sdk:DataGrid.Columns>
              <sdk:DataGridTextColumn x:Name="idColumn" Binding="{Binding Id}" Header="ID" Width="Auto" />
              <sdk:DataGridTextColumn x:Name="nameColumn" Binding="{Binding Name}" Header="NAME" Width="*" />
            </sdk:DataGrid.Columns>
          </sdk:DataGrid>

          <Button Grid.Row="3" Grid.Column="1" x:Name="AddNewButton" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,10,5" Style="{StaticResource AddButtonStyle}" />
          <csla:TriggerAction TargetControl="{Binding ElementName=AddNewButton}" MethodName="AddNew" DataContext="{Binding CurrentItem}" />

<Button Grid.Row="3" Grid.Column="1" x:Name="DeleteButton" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="0,5,10,5" />
          <csla:TriggerAction TargetControl="{Binding ElementName=DeleteButton}" MethodName="Remove" DataContext="{Binding CurrentItem}" />

          <Border Grid.Row="4" Grid.ColumnSpan="2" Background="#FFE0E0E0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />

          <StackPanel Grid.Row="4" x:Name="stackPanel1" DataContext="{Binding CurrentItem}" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Right" Grid.Column="1">
            <Button Content="cancel" x:Name="CancelButton" IsEnabled="{Binding CanCancel}" Margin="3" Style="{StaticResource CslaButtonStyle}" />
            <Button Content="save" x:Name="SaveButton" IsEnabled="{Binding CanSave}" Margin="3" Style="{StaticResource CslaButtonStyle}" />
            <csla:TriggerAction TargetControl="{Binding ElementName=SaveButton}" MethodName="Save"/>
            <csla:TriggerAction TargetControl="{Binding ElementName=CancelButton}" MethodName="Cancel"/>
          </StackPanel>

          <StackPanel Grid.Row="4" Orientation="Horizontal">
            <Rectangle Style="{StaticResource DecoratorRectangle}"/>
            <Rectangle Style="{StaticResource DecoratorRectangle}"/>
            <Rectangle Style="{StaticResource DecoratorRectangle}"/>
            <Rectangle Style="{StaticResource DecoratorRectangle}"/>
          </StackPanel>

        </Grid>
      </Border>
    </UserControl>

I believe in order to access the ListItem that is selected in the DataGrid I have to somehow bind the SelectedItem property of the DataGrid to a property in my ViewModel, am I understanding this correctly?

I could add something like:

SelectedItem="{Binding ViewModel.SelectedListItem}",

to the XAML DataGrid element, but I'm still a little unclear what to put for the binding property to actually get it to set the property in my OrderVm.cs...

could someone help me with what to put for the Binding? Thanks!

casperOne
  • 73,706
  • 19
  • 184
  • 253
Josh
  • 451
  • 8
  • 22
  • If you post the xaml for your UI we can also point out how to make sure that your selected object is passed to the method in such a way as to use it within the event... – EtherDragon Jul 10 '12 at 21:20
  • I am not on my work computer but i posted the xaml from the demo, so the button appears on top of the other but that shouldn't matter for the purpose of the explanation. Thanks EtherDragon! – Josh Jul 11 '12 at 01:33

2 Answers2

0
public override void Remove(object sender, ExecuteEventArgs e) 
{ 
    //Bxf.Shell.Instance.ShowError(Model.LineItems.AllowRemove.ToString(), "Delete"); 
    if(Model.LineItems.Count>0) 
        Model.LineItems.RemoveAt(0);         
} 

Doesn't ExecuteEventArgs expose some sort of argument? Looking at the docs it looks like a 'CommandOption' is available (which contains an Arg member). Can you not bind the SelectedItem to the CommandOption for the TriggerAction? I've not actually used TriggerActions yet in CSLA so I might have a look myself. You must be able to bind the arguments for a command though so that the command handler has some sort of context

Edit:

Looking at one of Rocky's posts on his blog:

http://www.lhotka.net/weblog/UsingTheTriggerActionControl.aspx

Looks like there is a Parameter member on TriggerAction which must pass a param to the execution context

Edit 2:

So just bind YourControl.SelectedItem to TriggerAction.MethodParameter, then in your method the ExecuteEventArgs should contain a reference to the selected object.

Then you can use

Model.LineItems.Remove(e.???); 

Not sure what the members are on the event args but you can work that out :)

Charleh
  • 13,749
  • 3
  • 37
  • 57
0

We have a Silverlight app that uses CSLA. This is code code in our DataGrid to remove rows (it works if they have multiple rows selected also):

/// <summary>
/// Removes selected items from the IEditableCollection
/// </summary>
public void RemoveSelectedRows()
{
    var item = CurrentItem as IEditableBusinessObject;

    // if row is not valid, cancel rather than commit to avoid validation
    if (item != null)
    {
        item.CheckRules();

        if (!item.IsValid)
            this.CancelEdit();
        else
            this.CommitEdit();
    }
    else
    {
        this.CommitEdit();
    }

    //          _lastErrorRow = -1;

    if (SelectedItems.Count == 0)
    {
        MsgBox.ShowMsg(SharedResources._PleaseSelectRowFirst);
        return;
    }

    var col = ItemsSource as Csla.Core.IEditableCollection;
    if (col != null)
    {
        var deleteItems = SelectedItems.OfType<IEditableBusinessObject>().ToList();

        int i = 0;
        while (i < deleteItems.Count)
        {
            col.RemoveChild(deleteItems[i]);
        }
    }
}

Remember, the context here is that this code is in the DataGrid itself. So in your button click you would have something like:

lineItemsDataGrid.RemoveRows();