by Joche Ojeda | Feb 18, 2019 | Web, XAF
Sometimes we need to have clientside events and handle them on the server side code behind, that in a simple asp.net web page is really easy, you just have to execute a javascript that executes an HTTP request to the server. Now the question is, how do we do that in XAF?
Well, the concept is basically the same but you need to know XAF architecture the problem is that most of the code needed is not documented, but after a while, I manage to figure it out, so let’s get started.
1) Create a XAF web application
2) On your web module add a view controller
3) Implement the interface IXafCallbackHandler on the controller you just added in step 2, this is the method that will be called as a callback from javascript. This interface is not documented on the DevExpress website
4) In your view controller add a property to access XafCallbackManager
5) Override the OnViewControlsCreated method and register your callback, in this example, the name of the callback is “MyScript”
6) Now add a simple action and wire the execute event, on the execute event cast the frame as a web window and register a startup script. The code surrounded with the blue line is the javascript that triggers the callback in the callback manager, the code surrounded with red is the id if the script that we are listening for, it should match the name of the script registered on the handler in the previous step.
To execute the callback somewhere in your javascript you have to execute the following function RaiseXafCallback, this function is not documented on the DevExpress website
RaiseXafCallback(globalCallbackControl, 'TheIdOfYourHandler', 'AnyStringThatRepresentsTheValuesYouWantToPassToTheCallBack', '', false);
7) Run your application and execute the simple action added in step 6, when the javascript finish executing, the method you implemented on step 3 will be executed.
The code for this article is here the full example is in GitHub
by Joche Ojeda | Jan 26, 2019 | Forms, UAP/UWP, Xamarin
For a long time now, I have wanted to access the file system when I create a Xamarin Forms UAP/UWP application but that was actually impossible … till now. After the Windows 10 build 17134 update its possible to access the broad file system, the approach is not straight forward.
To gain access to the file system in your Xamarin Forms UAP/UWP application follow these steps
1) Go the properties of your UAP/UWP application and check the targeting, the minimum should be at least 16299, what I recommend is 171344
You can also change the targets unloading the project and editing the csproj file
2) In your solution explorer edit your Package.appxmanifest by selecting it and press F7, looking the file from the top should look like the image below
Add this namespace xmlns:rescap=”http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities and update the IgnorableNamesSpaces like this IgnorableNamespaces=”uap mp rescap” after the changes your file should look like the image below
3) Lookup for the capabilities node in the manifest and add a new capability <rescap:Capability Name=”broadFileSystemAccess” /> your capabilities section should look like the image below
4) Rebuild your application, then select it on the solution explorer, right click over it and click on deploy, this will register the application in your OS
5) on your Windows OS go to settings>File system privacy settings and you will see all the UAP/UWP applications that are registered in your OS and have access to the file system, here you can allow/deny the access to the file system in general or by application
6) now everything is ready for your app to access the file system, but there is a little catch, in most cases, you cannot use the classes in system.io to access the file system you have to use Windows.Storage.Storagefolder below is a code snippet that illustrates how to use such class
public async void GetDirectories(string sDir)
{
var folder = await StorageFolder.GetFolderFromPathAsync(sDir);
foreach (var file in await folder.GetFilesAsync())
{
Debug.WriteLine(file.Name);
}
}
I have created a sample app using these steps, you can download the source from GitHub
by Joche Ojeda | Jan 11, 2019 | Code Rush, Custom Templates, Entity Framework Core
Don’t waste your time writing boilerplate code, just use Code Rush from DevExpress
Entity Framework Class (shortcut efc)
Entity Framework Property (shortcut efpr)
Entity Framework Property (shortcut efnp)
Entity Framework Collection (shortcut efcol)
Entity Framework extensions (shortcut efext)
Entity Framework ModelBuilder Association (shortcut efrom)
You can download all these amazing code templates here [download id=”241″]
by Joche Ojeda | Dec 8, 2018 | Application Framework, Brevitas Application Framework
Let’s try to define what is an application framework, for that we will check how famous website defines the term “Application Framework”
In computer programming, an application framework[1] consists of a software framework used by software developers to implement the standard structure of application software.[2]
From techopedia
An application framework is a software library that provides a fundamental structure to support the development of applications for a specific environment. An application framework acts as the skeletal support to build an application.
Now my own definition of an application framework
An application framework is a set of tools, components and design patterns that allow the programmer to develop an application for a well define pourpose (like a business application, a game etc..). The main pourpse of an application framework should be reduce the development time and allow the developer to focus on the main pourpouse of the application instead of the application infrastructure
That is all for now, as you can see the concept is really simple but as they say “devil lies on the details”. In the upcoming post, we will define the parts of an application framework.
by Joche Ojeda | Dec 2, 2018 | Code Rush, Custom Templates, DevExpress, Xamarin, Xamarin Forms
From time to time I realize that a lot of the stuff I’m writing is repetitive and complex, so that is the perfect time to create a new code rush custom template, behold the new template xfbp (xamarin forms bindable property). Download the template here [download id=”211″]
Do you want to see it in action?
by Joche Ojeda | Dec 1, 2018 | Custom Controllers, XAF
Sometimes you are asked by a customer to implement a functionality that you have already created in the past from someone else.
In this case, a customer and dear friend from Italy asked me “Jose, can we make the XAF filter case insensitive?”
And my answer was yes, I have done in the past for a customer in El Salvador. At that time the approach we used was to save everything in uppercases and do all the searches in uppercases also
I didn’t like that approach at all, so it was time get creative again.
As always I start my research by spending some time reading tickets at https://www.devexpress.com/Support/Center/ which is the greatest source of information for all things related to DevExpress
Here is what I found
- https://www.devexpress.com/Support/Center/Question/Details/Q356778/how-can-i-activate-case-insensitive-search-in-lookup-views this approach actually works but the problem is that the name of the fields are hardcoded
- https://www.devexpress.com/Support/Center/Question/Details/Q343797/root-listview-filterbytext-include-the-collection-propertys this second approach just append extra nodes to the criteria so its also not good but what I have learned with this example is when is the right moment to alter the criteria.
My first idea was to edit the criteria that were sent to the collection source that means that I need a way to get the values of each node on the criteria, so I can edit them one by one. After some more research, this is what I have found
https://www.devexpress.com/Support/Center/Question/Details/Q539396/criteriaoperator-how-to-get-list-of-parameters-and-their-values
this approach seems perfect to get the properties and values of each node till test it and find out this
Michael (DevExpress Support)6 years ago
It is possible to write a hierarchy walker or visitor, but only for a specific subset of criteria operators.
What Michael means is that only you can only get the values of simple criteria and by simple, I mean the ones that do not involve functions. So, I was set back to step one again.
So, I’m back to step one but let’s see what I’ve learned from the other tickets
- I know the exact moment when the criteria are evaluated
- I know the criteria that are evaluated and how many nodes it contains
- I know which the possible properties are involved in the creation of the criteria
Now this is the flow that I will use to make the search case insensitive
- Locate the controller where the search action lives, for that, I can use the property frame and the method get controller
- Interrupt the search action, for that, I will wire the event execute of the FilterController FullTextFilterAction action
- Find out what are the possible properties that I can use to build the search criteria for that I will use GetFullTextSearchProperties
- Build the new criteria, this is somehow tricky because the properties shown in the list view might represent complex objects and that is shown in the column is either the object default property or any other property that can be deep inside the properties tree. Also this step involve find out what is the type of the value being displayed on the list view, if the value is a string I will evaluate its value converted to upper cases using the function upper from the criteria language, if the search value is not a string but a number I will try to cast it to the type of the display column, if the cast is not invalid I will evaluate the search value as a number
- Set the new filter to the list view
You can cross reference the points above with the sample code below
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using DevExpress.Data.Filtering;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Actions;
using DevExpress.ExpressApp.Editors;
using DevExpress.ExpressApp.Layout;
using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Model.NodeGenerators;
using DevExpress.ExpressApp.SystemModule;
using DevExpress.ExpressApp.Templates;
using DevExpress.ExpressApp.Utils;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.Validation;
public class FilterControllerCaseInsensitive : ViewController<ListView>
{
public FilterControllerCaseInsensitive()
{
}
FilterController standardFilterController;
protected override void OnActivated()
{
standardFilterController = Frame.GetController<FilterController>();
if (standardFilterController == null)
return;
//we should wire the execution of the filter
standardFilterController.FullTextFilterAction.Execute += FullTextFilterAction_Execute;
}
protected override void OnDeactivated()
{
base.OnDeactivated();
if (standardFilterController == null)
return;
//we should unwire the execution of the filter
standardFilterController.FullTextFilterAction.Execute -= FullTextFilterAction_Execute;
}
private void FullTextFilterAction_Execute(object sender, ParametrizedActionExecuteEventArgs e)
{
//we locate filter with the key FilterController.FullTextSearchCriteriaName then we convert it to case insensitive
if (!string.IsNullOrEmpty(e.ParameterCurrentValue as string) && View.CollectionSource.Criteria.ContainsKey(FilterController.FullTextSearchCriteriaName))
View.CollectionSource.Criteria[FilterController.FullTextSearchCriteriaName] = GetCaseInsensitiveCriteria(e.ParameterCurrentValue, View.CollectionSource.Criteria[FilterController.FullTextSearchCriteriaName]);
}
private CriteriaOperator GetCaseInsensitiveCriteria(object searchValue, CriteriaOperator initialCriteria)
{
//we get a list of all the properties that can be involved in the filter
var SearchProperties = standardFilterController.GetFullTextSearchProperties();
//we declare a model class and a property name,the values on this variables will change if we property involve is a navigation property (another persistent object)
IModelClass ModelClass = null;
string PropertyName = string.Empty;
//we declare a list of operators to contains new operators we are going to create
List<CriteriaOperator> Operator = new List<CriteriaOperator>();
//we iterate all the properties
foreach (var CurrentProperty in SearchProperties)
{
//here we split the name with a dot, if length is greater than 1 it means its a navigation properties, beware that this may fail with a deep tree of properties like category.subcategory.categoryname
var Split = CurrentProperty.Split('.');
if (Split.Length > 1)
{
Debug.WriteLine(string.Format("{0}","its a complex property"));
var CurrentClass = this.View.Model.ModelClass;
for (int i = 0; i < Split.Length; i++)
{
//if its a navigation property we locate the type in the BOModel
IModelMember member = CurrentClass.OwnMembers.Where(m => m.Name == Split[i]).FirstOrDefault();
//then we set the model class and property name to the values of the navigation property like category.name where category is the model class and name is the property
CurrentClass = this.Application.Model.BOModel.GetClass(member.Type);
if (CurrentClass == null)
continue;
ModelClass = CurrentClass;
PropertyName = Split[i + 1];
}
Debug.WriteLine(string.Format("{0}:{1}", "ModelClass", ModelClass.Name));
Debug.WriteLine(string.Format("{0}:{1}", "PropertyName", PropertyName));
}
else
{
//else the model class will be the current class where the filter is executing, and the property will be the current property we are evaluating
ModelClass = this.View.Model.ModelClass;
PropertyName = CurrentProperty;
}
//we look for the property on the class model own member
var Property = ModelClass.OwnMembers.Where(m => m.Name == PropertyName).FirstOrDefault();
if (Property != null)
{
//if the property is a string it means that we can set it to upper case
if (Property.Type == typeof(string))
{
searchValue = searchValue.ToString().ToUpper();
//we create an operator where we set the value of the property to upper before we compare it, also we change the comparison value to upper
CriteriaOperator Operand = CriteriaOperator.Parse("Contains(Upper(" + CurrentProperty + "), ?)", searchValue);
//we added to the list of operators that will concatenate with OR
Operator.Add(Operand);
}
else
{
//if the property is not a string we need to try to cast the value to the correct type so we do a catch try, if we manage to cast the value it will be added to the operators list
try
{
var ConvertedType = Convert.ChangeType(searchValue, Property.Type);
CriteriaOperator operand = new BinaryOperator(CurrentProperty, ConvertedType, BinaryOperatorType.Equal);
Operator.Add(operand);
}
catch (Exception)
{
//silent exception, this will happen if the casting was not successful so we won't add the operand on this case
}
}
}
}
//we concatenate everything with an OR
var alloperators = CriteriaOperator.Or(Operator.ToArray());
Debug.WriteLine(string.Format("{0}:{1}", "alloperators", alloperators));
return alloperators;
}
}
by Joche Ojeda | Oct 8, 2018 | Nuget, Xamarin, XPO
After 15 years, DevExpress has finally made XPO available free-of-charge. If you’re not familiar with XPO, you can learn more about its feature set here. If you’ve used XPO in the past or are familiar with capabilities, you will love this.
As we already know a Xamarin ListView is populated with data using the ItemsSource property, which can accept any collection implementing IEnumerable but if we want the ListView to automatically update as items are added, removed or changed in the underlying list, you’ll need to use an ObservableCollection. Here is where XpoObservableCollection becomes the best friend for all the XPO fans out there.
XpoObservableCollection inherit from an XPCollection so to use, it is exactly as you would use an XPCollection, the only difference is that the XpoObservableCollection refresh the state of ListViews on Xamarin Forms.
XamarinXpoPageSelector takes it a step further by internally implementing XPPageSelector and presenting the XpoObservableCollection as a pageable collection. With this in mind, on the constructor of the XamarinXpoPageSelector you need to pass the following parameters:
SortingCollection sorting = new SortingCollection();
sorting.Add(new SortProperty("Your Property", SortingDirection.Ascending));
XPCollection <Your Class> Collection = new XPCollection <YourClass>(UnitOfWork);
Collection.Sorting = sorting;
XamarinXpoPageSelector <YourClass> selector = new XamarinXpoPageSelector <YourClass> (Collection,10, XpoObservablePageSelectorBehavior.AppendPage);
this.listView.ItemsSource = selector.ObservableData;
- Collection = An instance of XPCollection.
- 10 = Page Size by default.
- XpoObservablePageSelectorBehavior = AppendPage or SinglePage.
Use Append in case you want to add the results of the new page to the collection or Single page to clear the last page results before showing the new page.
And that’s it. The same awesome ObservableRangeCollection (from MVVM Helpers) that adds important methods such as AddRange, RemoveRange, Replace, and ReplaceRange, it is now available in XPO and of course, it is open source so go and take a look behind the curtains.
https://github.com/egarim/BIT.Xpo.Observables
https://www.nuget.org/packages/BIT.Xpo.Observables/
Until next time. Xpo out!
by Joche Ojeda | Oct 7, 2018 | XPO, XPO Database Replication
After 15 years of working with XPO, I have seen many tickets asking if XPO is capable of doing data replication and all the time DevExpress team answer those tickets saying that replication its out of the scope of XPO and that it’s actually true.
So, to start talking about database replication lets try to define what “replication” means. Here is the definition of replication according to Wikipedia
“A computational task is typically replicated in space, i.e. executed on separate devices, or it could be replicated in time, if it is executed repeatedly on a single device. Replication in space or in time is often linked to scheduling algorithms”
The keywords on the above statement are task, space and time, so to replicate a database operation we need to know the following information
- What was the task?
- Who performed the task?
- When was the task performed?
- Who needs to know about the task what was performed?
Now let’s think what are the steps that any traditional database does, in order to replicate the data between instances
- It shares a copy of the database schema to the other instances/locations/devices
- It logs the DML statements that happened to a main instance/location/device
- It broadcast the statements on this log to the other instances/locations/devices
- it processes the statements on the target instance/locations/devices
Now the question is, can we do the same with XPO?
thanks to the great architecture develop by the XPO Team, the answer is a big YES!!!
so, let’s compare how you can match traditional database replication with XPO
|
Traditional database replication |
XPO database replication |
1 |
Share a copy of the database schema. |
In XPO we can re-create a database schema using the method UpdateSchema from the Session class. |
2 |
Logs the DML statements. |
In XPO we can keep track of the BaseStatement at the DataLayer level. |
3 |
Broadcast the statements
|
We can transport the log of statements using any of the dot net network technologies like WCF, remoting or Web API. |
4 |
Process the statements on the target instance, device or location
|
To process any kind of BaseStatement we can use the XPO DataLayer on the target instance, device or location |
So, it looks like DotNet and XPO provide us of all the necessary infrastructure to do a database replication so why not give it a try right?
by Joche Ojeda | Oct 1, 2018 | DevExpress XPO from step 1 to N, XPO
There is nothing than inspire me more to write a blog post that a regular Saint Petersburg day and by regular, I mean windy, cold, dark and rainy, but don’t get me wrong I love this city but when the weather is too nice as it was this past summer is hard to focus on writing.
So, let’s get started with the post number 5, today we are going to talk about the architecture of XPO.
If you are new to XPO you might find that the documentation is sometimes overwhelming especially because most of the articles blogs and tickets are written in totally different times and versions of XPO, so you might find some really old blog post where the WCF scenario is not supported and the XpoProviders are tightly coupled with the DotNet ADO Providers and some other cases where is the opposite case.
XPO is now 15 years old and its architecture has changed since the early versions, most of the time when you find documentation about XPO layer architecture you won’t be able to see all the layers at once.
After spending 1 month and Gilbert Arizona, developing software side by side with my dear friend and student Jose Javier Columbie and having endless technical conversations about XPO, I realize that it is not easy to explain how the XPO architecture works, so I decided to draw the XPO architecture in a formal document. Javier also drew the first version of this diagram on his notepad and as always half in Spanish and half in English as we tend to do as Latin Americans.
So, without further due, here I present you the XPO architecture diagram
If you want to get a copy of the diagram with clickable links, you can download it here [download id=”172″]
Now let’s start explaining from left to right.
Persistent Classes: this layer is basically defined by you as the programmer and is nothing more than the persistent classes you write to abstract business objects. Usually, this layer is your starting point as an XPO user, so I won’t go into deeper detail since if you are reading this post you already know how this layer works.
Data Access, Data Cache and Data Filtering: in this layer, the most basic object is the session also is the base class for all the other objects in this layer. A session is basically a cache of all the persistent objects that have been instantiated since you start manipulating your DataStore or the objects that you have queried in your DAL (Data Access Layer).
Most of the behaviours from the session are passed to its child classes, won’t explain the difference on the child classes in this article but for sure it will be on my list of topics for the following weeks.
Object Access Layer: this layer is the bridge between the session and the actual DataStore. So basically, it works as a translator for the CRUD operations done in an object-oriented manner to statement objects that will be processed in the data access layer level.
Data Access Layer: is the bridge between the object access layer and the data stores (classes that implements IDataStore) and its basically in charge of pass the statement objects to the data store so it can translate it to the proper SQL statements for a specific database like MS SQL Server, Postgres, Mysql, etc.
Data Store Layer: is the lowest layer of all and it’s in charge to translate the statement objects to DDL and DML SQL statements and execute them at the database level using ADO.
Also, as you can see in the diagram this layer can be transferred over the wire using WCF to extend the functionality on the communication with the database. Using WCF is really useful if you don’t want to expose the connection string on the application config or if you want to transport the communication to the database in any of WCF supported network protocols.
by Joche Ojeda | Sep 27, 2018 | DevExpress XPO from step 1 to N, XPO
When XPO was first released it supported MSSQL Server and MS Access as the main database systems, most of the examples and documentation did not specify how XPO connected to the database, at that time it looks like the connection to the database happened like magic.
There was little to none information about how to connect to a DBRMS that were not MSSQL Server or MS Access
So I decided to post a ticket to developer express asking how can I create the correct connection string for each of the supported database, and that is the origen of this ticket that I use on all my presentations lectures about XPO.
Here is a sample of each of the supported connection strings
AccessConnectionProvider: MSAccess XpoProvider=MSAccess;Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\mydatabase.mdb;User Id=admin;Password=;
DataSetDataStore: XmlDataSet
XpoProvider=XmlDataSet;Data Source=C:\mydatabase.xml;Read Only=false
InMemoryDataStore: InMemoryDataStore
XpoProvider=InMemoryDataStore;Data Source=C:\mydatabase.xml;Read Only=false
MSSqlConnectionProvider: MSSqlServer
XpoProvider=MSSqlServer;Data Source=(local);User ID=username;Password=password;Initial Catalog=database;Persist Security Info=true
AdvantageConnectionProvider: Advantage
XpoProvider=Advantage;Data Source=\\myserver\myvolume\mypat\mydd.add;ServerType=local;User ID=ASSSYS;TrimTrailingSpaces=true
AsaConnectionProvider: Asa
XpoProvider=Asa;Uid=MyUsername;PWD=MyPassword;DBF=c:\mydatabase.db;Persist Security Info=true
AseConnectionPrvider: Ase
XpoProvider=Ase;Port=5000;Data Source=MyAseServer;User ID=MyUserName;Password=MyPassword;Initial Catalog=MyDatabase;Persist Security Info=true
DB2ConnectionProvider: DB2
XpoProvider=DB2;Server=MyAddress:MyPortNumber;User ID=MyUserName;Password=MyPassword;Database=MyDatabase;Persist Security Info=true
FirebirdConnectionProvider: Firebird
XpoProvider=Firebird;DataSource=localhost;User=SYSDBA;Password=masterkey;Database=MyDatabase.fdb;ServerType=0;Charset=NONE
MSSqlCEConnectionProvider: MSSqlServerCE
XpoProvider=MSSqlServerCE;Data Source=MyDatabase.sdf;Password=MyPassword
MySqlConnectionProvider: MySql
XpoProvider=MySql;Server=MyServerAddress;User ID=MyUserName;Password=MyPassword;Database=MyDatabase;Persist Security Info= true;Charset=utf8
ODPConnectionProvider: ODP
XpoProvider=ODP;Data Source=TORCL;User ID=MyUserName;Password=MyPassword
ODPManagedConnectionProvider: ODPManaged
XpoProvider=ODPManaged;Data Source=TORCL;User ID=MyUserName;Password=MyPassword
OracleConnectionProvider: Oracle
XpoProvider=Oracle;Data Source=TORCL;User ID=MyUserName;Password=MyPassword
PervasiveSqlConnectionProvider: Pervasive
XpoProvider=Pervasive;Server=MyServerAddress;UID=MyUserName;PWD=MyPassword;ServerDSN=MyDatabase
PostgreSqlConnectionProvider: Postgres
XpoProvider=Postgres;Server=127.0.0.1;User ID=MyUserName;Password=MyPassword;Database=MyDatabase;Encoding=UNICODE
SQLiteConnectionProvider: SQLite
XpoProvider=SQLite;Data Source=filename
VistaDBConnectionProvider: VistaDB
XpoProvider=VistaDB;Data Source=C:\mydatabase.vdb4
VistaDB5ConnectionProvider: VistaDB5
XpoProvider=VistaDB5;Data Source=C:\mydatabase.vdb5
By default, when you start using XPO without specifying a connection string it will connect by to MSAccess.
The XPO connection string is a special type of connection string, it is somehow the same as your regular .net connection string, but it includes the parameter “XpoProvider”, you can learn more about this on my post about the XpoProviders. The need of having the parameter XpoProvider is the connection string is because otherwise, it will be impossible to identify the database engine that you want to use with XPO as you can see on the following screenshot from DevExpress website.
There are 2 special cases that XPO can use a regular connection string
- When you are using an MSSQL Server as your RDBMS, you can just use a regular connection string without the need to specify an XpoProvider.
- When you are using MS Access with OleDb you can also use a just regular connection string
You can see a real-life example when you create an XAF application and you check the app or web config, here is a screenshot of the possible connection strings
Besides the connection string as literal strings, you can also ask the XpoProvider to generate the correct connection string for you on runtime using the static method of “GetConnectionString”. You can see an example of how to use PostgreSqlConnectionProvider to generate the correct connection string, in DevExpress official documentation here. The same goes for all of the XpoProviers, you can information about each provider in the documentation for the DevExpress.Xpo.DB namespace.