CSLA.NET 5.4.2
CSLA .NET is a software development framework that helps you build a reusable, maintainable object-oriented business layer for your app.
CslaDataProvider.cs
Go to the documentation of this file.
1#if !XAMARIN && !WINDOWS_UWP
2//-----------------------------------------------------------------------
3// <copyright file="CslaDataProvider.cs" company="Marimer LLC">
4// Copyright (c) Marimer LLC. All rights reserved.
5// Website: https://cslanet.com
6// </copyright>
7// <summary>Wraps and creates a CSLA .NET-style object </summary>
8//-----------------------------------------------------------------------
9using System;
10using System.Collections;
11using System.Collections.Generic;
12using System.Collections.ObjectModel;
13using System.ComponentModel;
14using System.Windows.Data;
15using System.Reflection;
16using Csla.Reflection;
17using Csla.Properties;
18
19namespace Csla.Xaml
20{
25 public class CslaDataProvider : DataSourceProvider
26 {
27
32 {
33 _commandManager = new CslaDataProviderCommandManager(this);
34 _factoryParameters = new ObservableCollection<object>();
35 _factoryParameters.CollectionChanged +=
36 new System.Collections.Specialized.NotifyCollectionChangedEventHandler(_factoryParameters_CollectionChanged);
37 }
38
42 public event EventHandler<Csla.Core.SavedEventArgs> Saved;
51 protected virtual void OnSaved(object newObject, Exception error, object userState)
52 {
53 if (Saved != null)
54 Saved(this, new Csla.Core.SavedEventArgs(newObject, error, userState));
55 }
56
57 void _factoryParameters_CollectionChanged(
58 object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
59 {
60 BeginQuery();
61 }
62
63#region Properties
64
65 private Type _objectType = null;
66 private bool _manageLifetime;
67 private string _factoryMethod = string.Empty;
68 private ObservableCollection<object> _factoryParameters;
69 private bool _isAsynchronous;
70 private CslaDataProviderCommandManager _commandManager;
71 private bool _isBusy;
72
79 {
80 get
81 {
82 return _commandManager;
83 }
84 }
85
90 public Type ObjectType
91 {
92 get
93 {
94 return _objectType;
95 }
96 set
97 {
98 _objectType = value;
99 OnPropertyChanged(new PropertyChangedEventArgs("ObjectType"));
100 }
101 }
102
110 {
111 get
112 {
113 return _manageLifetime;
114 }
115 set
116 {
117 _manageLifetime = value;
118 OnPropertyChanged(new PropertyChangedEventArgs("ManageObjectLifetime"));
119 }
120 }
121
122 private object _dataChangedHandler;
123
133 public object DataChangedHandler
134 {
135 get
136 {
137 return _dataChangedHandler;
138 }
139 set
140 {
141 _dataChangedHandler = value;
142 var dialog = value as IErrorDialog;
143 if (dialog != null)
144 dialog.Register(this);
145 OnPropertyChanged(new PropertyChangedEventArgs("DataChangedHandler"));
146 }
147 }
148
155 public string FactoryMethod
156 {
157 get
158 {
159 return _factoryMethod;
160 }
161 set
162 {
163 _factoryMethod = value;
164 OnPropertyChanged(new PropertyChangedEventArgs("FactoryMethod"));
165 }
166 }
167
172 public IList FactoryParameters
173 {
174 get
175 {
176 return _factoryParameters;
177 }
178 }
179
185 public bool IsAsynchronous
186 {
187 get { return _isAsynchronous; }
188 set { _isAsynchronous = value; }
189 }
190
195 public object ObjectInstance
196 {
197 get { return Data; }
198 set
199 {
200 OnQueryFinished(value, null, null, null);
201 OnPropertyChanged(new PropertyChangedEventArgs("ObjectInstance"));
202 }
203 }
204
208 public bool IsBusy
209 {
210 get { return _isBusy; }
211 protected set
212 {
213 _isBusy = value;
214 OnPropertyChanged(new PropertyChangedEventArgs("IsBusy"));
215 }
216 }
217
222 public void Rebind()
223 {
224 object tmp = ObjectInstance;
225 ObjectInstance = null;
226 ObjectInstance = tmp;
227 }
228
229#endregion
230
231#region Query
232
233 private bool _firstRun = true;
234 private bool _init = false;
235 private bool _endInitCompete = false;
236 private bool _endInitError = false;
237
241 protected override void BeginInit()
242 {
243 _init = true;
244 base.BeginInit();
245 }
246
250 protected override void EndInit()
251 {
252 _init = false;
253 base.EndInit();
254 _endInitCompete = true;
255 }
256
262 protected override void BeginQuery()
263 {
264 if (_init)
265 return;
266
267 if (_firstRun)
268 {
269 _firstRun = false;
270 if (!IsInitialLoadEnabled)
271 return;
272 }
273
274 if (_endInitError)
275 {
276 // this handles a case where the WPF form initilizer
277 // invokes the data provider twice when an exception
278 // occurs - we really don't want to try the query twice
279 // or report the error twice
280 _endInitError = false;
281 OnQueryFinished(null);
282 return;
283 }
284
285 if (this.IsRefreshDeferred)
286 return;
287
288 QueryRequest request = new QueryRequest();
289 request.ObjectType = _objectType;
290 request.FactoryMethod = _factoryMethod;
291 request.FactoryParameters = _factoryParameters;
292 request.ManageObjectLifetime = _manageLifetime;
293
294 IsBusy = true;
295
296 if (IsAsynchronous)
297 System.Threading.ThreadPool.QueueUserWorkItem(DoQuery, request);
298 else
299 DoQuery(request);
300 }
301
302 private void DoQuery(object state)
303 {
304 QueryRequest request = (QueryRequest)state;
305 object result = null;
306 Exception exceptionResult = null;
307 object[] parameters = new List<object>(request.FactoryParameters).ToArray();
308
309 try
310 {
311 // get factory method info
312 BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy;
313 System.Reflection.MethodInfo factory = request.ObjectType.GetMethod(
314 request.FactoryMethod, flags, null,
315 MethodCaller.GetParameterTypes(parameters), null);
316
317 if (factory == null)
318 {
319 // strongly typed factory couldn't be found
320 // so find one with the correct number of
321 // parameters
322 int parameterCount = parameters.Length;
323 System.Reflection.MethodInfo[] methods = request.ObjectType.GetMethods(flags);
324 foreach (System.Reflection.MethodInfo method in methods)
325 if (method.Name == request.FactoryMethod && method.GetParameters().Length == parameterCount)
326 {
327 factory = method;
328 break;
329 }
330 }
331
332 if (factory == null)
333 {
334 // no matching factory could be found
335 // so throw exception
336 throw new InvalidOperationException(
337 string.Format(Resources.NoSuchFactoryMethod, request.FactoryMethod));
338 }
339
340 // invoke factory method
341 try
342 {
343 result = factory.Invoke(null, parameters);
344 }
345 catch (Csla.DataPortalException ex)
346 {
347 exceptionResult = ex.BusinessException;
348 }
349 catch (System.Reflection.TargetInvocationException ex)
350 {
351 if (ex.InnerException != null)
352 {
353 exceptionResult = ex.InnerException;
354 var dpe = exceptionResult as Csla.DataPortalException;
355 if (dpe != null && dpe.BusinessException != null)
356 exceptionResult = dpe.BusinessException;
357 }
358 else
359 exceptionResult = ex;
360 }
361 catch (Exception ex)
362 {
363 exceptionResult = ex;
364 }
365 }
366 catch (Exception ex)
367 {
368 exceptionResult = ex;
369 }
370
371 if (request.ManageObjectLifetime && result != null)
372 {
373 Csla.Core.ISupportUndo undo = result as Csla.Core.ISupportUndo;
374 if (undo != null)
375 undo.BeginEdit();
376 }
377
378 //if (!System.Windows.Application.Current.Dispatcher.CheckAccess())
379 // System.Windows.Application.Current.Dispatcher.Invoke(
380 // new Action(() => { IsBusy = false; }),
381 // new object[] { });
382
383 if (!_endInitCompete && exceptionResult != null)
384 _endInitError = true;
385
386 // return result to base class
387 OnQueryFinished(result, exceptionResult, (o) => { IsBusy = false; return null; }, null);
388 }
389
390#region QueryRequest Class
391
392 private class QueryRequest
393 {
394 private Type _objectType;
395
396 public Type ObjectType
397 {
398 get { return _objectType; }
399 set { _objectType = value; }
400 }
401
402 private string _factoryMethod;
403
404 public string FactoryMethod
405 {
406 get { return _factoryMethod; }
407 set { _factoryMethod = value; }
408 }
409
410 private ObservableCollection<object> _factoryParameters;
411
412 public ObservableCollection<object> FactoryParameters
413 {
414 get { return _factoryParameters; }
415 set { _factoryParameters =
416 new ObservableCollection<object>(new List<object>(value)); }
417 }
418 private bool _manageLifetime;
419
420 public bool ManageObjectLifetime
421 {
422 get { return _manageLifetime; }
423 set { _manageLifetime = value; }
424 }
425
426 }
427
428#endregion
429
430#endregion
431
432#region Cancel/Update/New/Remove
433
442 public void Cancel()
443 {
444 Csla.Core.ISupportUndo undo = this.Data as Csla.Core.ISupportUndo;
445 if (undo != null && _manageLifetime)
446 {
447 IsBusy = true;
448 undo.CancelEdit();
449 undo.BeginEdit();
450 IsBusy = false;
451 }
452 }
453
474 public void Save()
475 {
476 // only do something if the object implements
477 // ISavable
478 Csla.Core.ISavable savable = this.Data as Csla.Core.ISavable;
479 if (savable != null)
480 {
481 object result = savable;
482 Exception exceptionResult = null;
483 try
484 {
485 IsBusy = true;
486
487 // clone the object if possible
488 ICloneable clonable = savable as ICloneable;
489 if (clonable != null)
490 savable = (Csla.Core.ISavable)clonable.Clone();
491
492 // apply edits in memory
493 Csla.Core.ISupportUndo undo = savable as Csla.Core.ISupportUndo;
494 if (undo != null && _manageLifetime)
495 undo.ApplyEdit();
496
497
498 // save the clone
499 result = savable.Save();
500
501 if (!ReferenceEquals(savable, this.Data) && !Csla.ApplicationContext.AutoCloneOnUpdate)
502 {
503 // raise Saved event from original object
504 Core.ISavable original = this.Data as Core.ISavable;
505 if (original != null)
506 original.SaveComplete(result);
507 }
508
509 // start editing the resulting object
510 undo = result as Csla.Core.ISupportUndo;
511 if (undo != null && _manageLifetime)
512 undo.BeginEdit();
513 }
514 catch (Exception ex)
515 {
516 exceptionResult = ex;
517 }
518 // clear previous object
519 OnQueryFinished(null, exceptionResult, null, null);
520 // return result to base class
521 OnQueryFinished(result, null, null, null);
522 IsBusy = false;
523 OnSaved(result, exceptionResult, null);
524 }
525 }
526
527
532 public object AddNew()
533 {
534 // only do something if the object implements
535 // IBindingList
536 IBindingList list = this.Data as IBindingList;
537 if (list != null && list.AllowNew)
538 return list.AddNew();
539 else
540 return null;
541
542 }
543
553 public void RemoveItem(object sender, ExecuteEventArgs e)
554 {
555 var item = e.MethodParameter;
556 // only do something if the object implements
557 // IBindingList
558 IBindingList list;
560 if (bb != null)
561 list = bb.Parent as IBindingList;
562 else
563 list = this.Data as IBindingList;
564 if (list != null && list.AllowRemove)
565 list.Remove(item);
566 }
567
568#endregion
569
570 }
571}
572#endif
This is the non-generic base class from which most business objects will be derived.
Core.IParent Parent
Provide access to the parent reference for use in child object code.
Event arguments containing a reference to the new object that was returned as a result of the Save() ...
This exception is returned for any errors occurring during the server-side DataPortal invocation.
Exception BusinessException
Gets the original server-side exception.
A strongly-typed resource class, for looking up localized strings, etc.
static string NoSuchFactoryMethod
Looks up a localized string similar to No such factory method:{0}.
Implements support for RoutedCommands that can be executed by the CslaDataProvider control.
Wraps and creates a CSLA .NET-style object that you can use as a binding source.
object AddNew()
Adds a new item to the object if the object implements IBindingList and AllowNew is true.
override void BeginQuery()
Overridden.
object ObjectInstance
Gets or sets a reference to the data object.
bool ManageObjectLifetime
Gets or sets a value indicating whether the data control should manage the lifetime of the business o...
bool IsAsynchronous
Gets or sets a value that indicates whether to perform object creation in a worker thread or in the a...
void Rebind()
Triggers WPF data binding to rebind to the data object.
IList FactoryParameters
Get the list of parameters to pass to the factory method.
override void BeginInit()
Indicates that the control is about to initialize.
Type ObjectType
Gets or sets the type of object to create an instance of.
string FactoryMethod
Gets or sets the name of the static (Shared in Visual Basic) factory method that should be called to ...
CslaDataProviderCommandManager CommandManager
Gets an object that can be used to execute Save and Undo commands on this CslaDataProvider through XA...
void Cancel()
Cancels changes to the business object, returning it to its previous state.
virtual void OnSaved(object newObject, Exception error, object userState)
Raise the Saved event when the object has been saved.
override void EndInit()
Indicates that the control has initialized.
CslaDataProvider()
Creates an instance of the object.
void RemoveItem(object sender, ExecuteEventArgs e)
Removes an item from the list if the object implements IBindingList and AllowRemove is true.
object DataChangedHandler
Gets or sets a reference to an object that will handle the DataChanged event raised by this data prov...
void Save()
Accepts changes to the business object, and commits them by calling the object's Save() method.
EventHandler< Csla.Core.SavedEventArgs > Saved
Event raised when the object has been saved.
bool IsBusy
Gets a value indicating if this object is busy.
Arguments passed to a method invoked by the Execute trigger action.
Specifies that the object can save itself.
Definition: ISavableT.cs:19
Define the common methods used by the UI to interact with n-level undo.
Definition: ISupportUndo.cs:25
void ApplyEdit()
Commits the current edit process.
void BeginEdit()
Starts a nested edit on the object.
Interface defining the interaction between a CslaDataSource and an error dialog control.
Definition: IErrorDialog.cs:21
void Register(object source)
Method called by the CslaDataProvider when the error dialog should register any events it wishes to h...