I commonly have the situation in my Silverlight 3 Line-of-business (LOB) applications of having a screen with the left side being a EditableRootList (such as CustomerList) and the right side being the EditableRoot (such as Customer) that is being edited. As a note, you may want to use the “stretch” button at the top right of this blog to make the code more readable. What I want is a UI where I can:
· Add or Delete items from the list on the left
· Modify items on the right
· Have my Apply button save ALL the changes in the list.
Here are some of the key points in the XAML file, note the “emphasized” sections:
Defining the resources and CslaDataProviders:
<UserControl.Resources>
<csla:CslaDataProvider x:Key="Customer"
ManageObjectLifetime="False"
IsInitialLoadEnabled="False"
ObjectType="Entities.Customer"
DataChanged="Customer_DataChanged" />
<csla:CslaDataProvider x:Key="CustomerList"
ManageObjectLifetime="True"
IsInitialLoadEnabled="True"
ObjectType="Entities.CustomerList "
FactoryMethod="GetAll"
Saved="CustomerList_Saved"/>
<core:NullToBooleanConverter x:Key="NullToBooleanConverter" />
<core:VisibilityConverter x:Key="VisibilityConverter" />
<core:DeletedToOpacityConverter x:Key="DeletedToOpacityConverter" />
</UserControl.Resources>
Defining the left side ListBox:
<ListBox x:Name="listCustomers" ItemsSource="{Binding Source={StaticResource CustomerList}, Path=Data}"
SelectionChanged="listCustomers_SelectionChanged" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}"
Opacity="{Binding IsDeleted, Converter={StaticResource DeletedToOpacityConverter}}" />
<TextBlock Text="(Deleted)" Foreground="Red" Margin="2,0,0,0"
Visibility="{Binding IsDeleted, Converter={StaticResource VisibilityConverter}}" />
<TextBlock Text="(New)" Foreground="Red" Margin="2,0,0,0"
Visibility="{Binding IsNew, Converter={StaticResource VisibilityConverter}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And in your code behind, I put these helpers
private CslaDataProvider CustomerProvider
{
get { return ((CslaDataProvider)this.Resources["Customer"]); }
}
private Customer Customer
{
get { return CustomerProvider.ObjectInstance as Customer; }
}
private CslaDataProvider CustomerListProvider
{
get { return ((CslaDataProvider)this.Resources["CustomerList"]); }
}
private CustomerList CustomerList
{
get { return CustomerListProvider.ObjectInstance as CustomerList; }
}
And the general event handlers look like this:
private void listCustomers_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
CustomerProvider.ObjectInstance = listCustomers.SelectedItem;
}
private void btnApply_Click(object sender, RoutedEventArgs e)
{
CustomerListProvider.Save();
}
private void btnNewCustomer_Click(object sender, RoutedEventArgs e)
{
CustomerProvider.FactoryMethod = "NewCustomer";
CustomerProvider.FactoryParameters.Clear();
CustomerProvider.Refresh();
}
private void btnDeleteCustomer_Click(object sender, RoutedEventArgs e)
{
this.CustomerProvider.Delete();
}
private void Customer_DataChanged(object sender, EventArgs e)
{
var ThisItem = Customer as Customer;
if (ThisItem != null && ThisItem.IsNew)
if (CustomerList.Contains(ThisItem) == false)
this.CustomerList.Add(ThisItem);
}
private void CustomerList_Saved(object sender, Csla.Core.SavedEventArgs e)
{
CustomerListProvider.Refresh();
}
And the “converters” required to make this work:
public class VisibilityConverter : IValueConverter
{
public object Convert(object value,Type targetType,object parameter,CultureInfo culture)
{
bool visibility = (bool)value;
return visibility ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value,Type targetType,object parameter,CultureInfo culture)
{
Visibility visibility = (Visibility)value;
return (visibility == Visibility.Visible);
}
}
public class DeletedToOpacityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool IsDeleted = (bool)value;
return IsDeleted ? (Double)0.3 : (Double)1.0;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
And finally you need to make sure you EditableRootList implementations have a DataPortal_Update() implementation. Here is a simple one:
protected void DataPortal_Update()
{
foreach (var Item in this)
{
Item.Save();
}
}
If you found this useful, please leave a comment. If you find a way to do it better, PLEASE leave a comment.