DataGrid not populating from CslaDataProvider

DataGrid not populating from CslaDataProvider

Old forum URL: forums.lhotka.net/forums/t/7085.aspx


decius posted on Thursday, June 11, 2009

I must be missing something, but I don't know what. I have my csla dataprovider:

<csla:CslaDataProvider x:Key="ProcCodeListDataProvider"

FactoryMethod="BeginGetMyList"

ObjectType="SlTest.Library.MyList, SlTest.Library"

IsInitialLoadEnabled="False" >

</csla:CslaDataProvider>

----------------------------------------------------------

On a button click, I do this (

private void btnSubmit_Click(object sender, RoutedEventArgs e)

{

CslaDataProvider procCodeListProvider = this.Resources["ProcCodeListDataProvider"] as CslaDataProvider;

procCodeListProvider.FactoryParameters.Clear();

procCodeListProvider.FactoryParameters.Add(this.DataContext as CodeListCrit);

procCodeListProvider.Refresh();

}

----------------------------------------------------------

Everything appears to be working properly, I can even break in the Server DataPortal_Fetch method to make sure my BO is actually being "Fetched".  However, my DataGrid is not populated or refreshed from the XAML binding(below)

<data:DataGrid x:Name="grdProcCodeList" Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="3"

ItemsSource="{Binding Source={StaticResource ProcCodesListDataSource}, Path=Data}">

</data:DataGrid>

----------------------------------------------------------

I'm new to XAML and this concept of databinding is quite awkward to me, because I don't know how to debug this kind of thing since it's totally handled by XAML.  What am I missing??

 

 

 

decius replied on Thursday, June 11, 2009

On thing has certainly helped me troubleshoot.  Let this be a lesson to any other Silverlight newbs:

I hadn't yet  subscribed to the CslaDataProvider DataChanged event like so:

private void CslaDataProvider_DataChanged(object sender, System.EventArgs e)

{

CslaDataProvider provider = (CslaDataProvider)(this.Resources["MyCslaDataProvider"]);

if (provider.Error != null)

System.Windows.Browser.HtmlPage.Window.Alert(provider.Error.Message);

}

Once the framework gets done with the async call for the BO fired from provider.Refresh() in the button click event is when it actually gets data in the provider.Data property (because of how Csla.Silverlight works with the wcf).

Now... I must figure out why I'm getting a "A parameterless constructor was not found for the object."  I thought I took care of this with my SILVERLIGHT comilation symbols. Must the constructor on the Server need to be public as well for Silverlight?? or is it something else.

 

esaulsberry replied on Thursday, June 11, 2009

decius:

procCodeListProvider.FactoryParameters.Add(this.DataContext as CodeListCrit);

Maybe I'm missing something but it seems odd to me you'd be passing the data context of the control as the factory criteria. 

You want to make sure any custom criteria classes have public parameterless constructors.

One way to debug binding is to include a value converter that doesn't do anything but give you a place to break. 

/// <summary>

/// This class exists to aid debugging. By attaching this converter to a binding, you can

/// set a break point as the object is bound and inspect it.

/// </summary>

public class DebugConverter : IValueConverter

{

#region IValueConverter Members

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{

Debug.WriteLine(value.ToString());

return value;

}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{

Debug.WriteLine(value.ToString());

return value;

}

#endregion

}

Text="{Binding Path=ExternalId, Mode=TwoWay, Converter={StaticResource DebugConverter}}"

 

decius replied on Friday, June 12, 2009

esaulsberry:
Maybe I'm missing something but it seems odd to me you'd be passing the data context of the control as the factory criteria. 

I'm a newb to Silverlight and XAML.  This seemed to make sense to me, but I don't doubt that it could be odd.  In the past with Csla, I've always made my own public criteria classes extended from BusinessBase to use as the factory method's parameters.  That way I can bind that one class to the UI and perform validation on it from Business base etc, which has made for easy maintenance.  So here, that's what I'm trying to do (I set the datacontext of the control as the criteria, then fetch the data with it and bind that result to the DataGrid).  Is there a better (or more conventional) way to do this in Silverlight/XAML?? I'm so used to working with BindingSources that I'm really out of my element now.

That debug converter trick will be extremely handy! Thanks so much for that tip

esaulsberry replied on Friday, June 12, 2009

A couple of things might help:

My CslaDataProviders are usually set to not load automatically (IsInitialLoadEnabled="False").  In code I load criteria parameters.  For example, this code is called when the form is loaded.

_siteListProvider.FactoryParameters.Clear();
_siteListProvider.FactoryParameters.Add(
App.ClientId);
_siteListProvider.FactoryParameters.Add(
"All Sites");
_siteListProvider.Refresh();

In my case, SingleCriteria frequently doesn't help for me.  I usually have to pass a client ID plus some other value.  I wrote a generic criteria class to support this.  The corresponding criteria class looks like this:

/// <summary>
/// A generic class to pass criteria containing the client id plus some other criteria value.
/// </summary>
/// <typeparam name="B">The type of the business class using the criteria.</typeparam>
/// <typeparam name="T">The type of the "other" criteria value.</typeparam>
/// <example>portal.BeginFetch(new ClientIdValueCriteria<ParentSiteNVL, string>(clientId, noSelectionLabel));</example>

[Serializable()]
public class ClientIdValueCriteria<B, T>:CriteriaBase
{
private int _clientId;
public int ClientId { get { return _clientId; } set { _clientId = value; } }

private T _value;
public T Value { get { return _value; } set { _value = value; } }

/// <summary>
/// Silverlight likes a empty public constructor.
/// </summary>

public ClientIdValueCriteria() : base(typeof(B)) { }

/// <summary>
/// Creates a new criteria class.
/// </summary>
/// <param name="clientId">The client id for this instance.</param>
/// <param name="value">The value of the non-clientid criteria.</param>

public ClientIdValueCriteria(int clientId, T value)
:
base(typeof(B))
{
_clientId = clientId;
_value = value;
}

protected override void OnGetState(Csla.Serialization.Mobile.SerializationInfo info, StateMode mode)
{
info.AddValue(
"_clientId", _clientId);
info.AddValue(
"_value", _value);
base.OnGetState(info, mode);
}

protected override void OnSetState(Csla.Serialization.Mobile.SerializationInfo info, StateMode mode)
{
_clientId = (
int)info.Values["_clientId"].Value;
_value = (T)info.Values[
"_value"].Value;
base.OnSetState(info, mode);
}

}

Here is the business class, in this case a name value list.

[Serializable()]
public class ParentSiteNVL:NameValueListBase<int, string>
{

#region Factory & Constructors
public static void BeginGetParentSiteNVL(int clientId, EventHandler<DataPortalResult<ParentSiteNVL>> handler)
{
DataPortal<ParentSiteNVL> portal = new DataPortal<ParentSiteNVL>();
portal.FetchCompleted += handler;
portal.BeginFetch(
new SingleCriteria<ParentSiteNVL, int>(clientId));
}

public static void BeginGetParentSiteNVL(int clientId, string noSelectionLabel, EventHandler<DataPortalResult<ParentSiteNVL>> handler)
{
DataPortal<ParentSiteNVL> portal = new DataPortal<ParentSiteNVL>();
portal.FetchCompleted += handler;
portal.BeginFetch(
new ClientIdValueCriteria<ParentSiteNVL, string>(clientId, noSelectionLabel));
}

#if SILVERLIGHT
public ParentSiteNVL() { }
#else
private ParentSiteNVL() { }
#endif

#endregion

#region Data Portal

#if !SILVERLIGHT
private void DataPortal_Fetch(SingleCriteria<ParentSiteNVL, int> criteria)
{
Fetch(criteria.Value,
"No Parent");
}
private void DataPortal_Fetch(ClientIdValueCriteria<ParentSiteNVL, string> criteria)
{
Fetch(criteria.ClientId, criteria.Value);
}

private void Fetch(int clientId, string noSelectionLabel)
{
Data.
OSMobileDataContext dc = new Data.OSMobileDataContext();
var parents = from s in dc.Sites
where s.ClientID == clientId
&& s.IsActive ==
true
orderby s.ParentSiteID, s.Description
select new { s.SiteID, s.Description };

RaiseListChangedEvents = false;
IsReadOnly =
false;

this.Add(new NameValueListBase<int, string>.NameValuePair(0, noSelectionLabel));

foreach (var p in parents)
{
this.Add(new NameValueListBase<int, string>.NameValuePair(p.SiteID, p.Description));
}

IsReadOnly = true;
RaiseListChangedEvents =
true;
}
#endif
#endregion
}

 

Fintanv replied on Friday, June 12, 2009

You may wish to look at Karl's great tool for debugging SilverLight: http://karlshifflett.wordpress.com/2009/06/08/glimpse-for-silverlight-viewing-exceptions-and-binding-errors/

Copyright (c) Marimer LLC