Quantcast
Channel: DevExpress Support Center (Examples)
Viewing all 7205 articles
Browse latest View live

How to preserve the Legend checkbox item state when the Series Template approach is used to generate the Series collection

$
0
0
NOTE. Starting with v17.1, you can optionally save legend checkbox state for the chart's Series collection on callbacks. To activate this feature, enable the WebChartControl.SaveStateOnCallbacks option. If you prefer to use the manual Legend state initialization approach, set the SaveStateOnCallbacks property to False.

WebChartControl does not cache information about auto-generated Series when the Series Template approach is used to initialize the chart layout. In this situation, it is required to handle the WebChartControl.BoundDataChanged event to restore the Legend item checkbox state. This example illustrates how to save the Legend state into a Session variable using the WebChartControl.LegendItemChecked event and then restore it on subsequent page requests.

See also:

How to preserve the Legend checkbox item state when the Series collection is initialized programmatically
How to preserve the Legend checkbox item state in an ASP.NET MVC application.

How to preserve the Legend checkbox item state when the Series collection is initialized programmatically

$
0
0

NOTE. Starting with v17.1, you can optionally save legend checkbox state for the chart's Series collection on callbacks. To activate this feature, enable the WebChartcontrol.SaveStateOnCallbacks option. If you prefer to use the manual Legend state initialization approach, set the SaveStateOnCallbacks property to False.

WebChartControl does not cache information about Series items and data source initialized at runtime. As a result, the Legend item checkbox state cannot be applied correctly. This example illustrates how to save the Legend state into a Session variable and restore it using the Page_Load event handler. The WebChartControl.LegendItemChecked event is used to obtain the current Legend panel state. Note that it is also required to disable the internal viewstate management using the WebChartControl.EnableViewState and WebChartControl.SaveStateOnCallbacks properties.

See also:

How to preserve the Legend checkbox item state when the Series Template approach is used to generate the Series collection;
How to preserve the Legend checkbox item state in an ASP.NET MVC application.

How to preserve the Legend checkbox item state in an ASP.NET MVC application

$
0
0
NOTE. Starting with v17.1, you can optionally save legend checkbox state for the chart's Series collection on callbacks. To activate this feature, enable the SaveStateOnCallbacks option.

Chart extension does not cache information about the Series item state when the Legend checkbox feature is enabled. In this situation, it is required to handle the ChartControlSettings.BoundDataChanged event to restore the Legend item checkbox state. This example illustrates how to save the Legend state into a Session variable using the ChartControlSettings.LegendItemChecked event and then restore it on subsequent page requests.

See also:

How to preserve the Legend checkbox item state when the Series collection is initialized programmatically;
How to preserve the Legend checkbox item state when the Series Template approach is used to generate the Series collection.

DiagramControl - How to create custom shapes with connection points

$
0
0
The Diagram control supports a special language for defining shapes. The main element that contains shape description is ShapeTemplate. This element describes a shape contour and may contain several segments:
- Start. Specifies the start point
- Line. Defines a line with start and end points
- Arc. Defines an arc with start and end points

To specify connection points, use the ShapeTemplate.ConnectionPoints property.
Shapes may contain parameters. Parameters may be used to dynamically calculate an end point, row height, and other properties. To specify parameters, use the ShapeTemplate.Parameters property.
To register custom shapes, create a stencil with the DiagramStencil.Create method and pass it to the DiagramToolboxRegistrator.RegisterStencil method.


Note:Starting with version 16.1, it is recommended to use XML to describe custom shapes. If you prefer to use XAML instead, take a look at the following example: T381372 - DiagramControl - How to create custom shapes with connection points using XAML markup.
Question Comments

Added By: Piotr Migdalski 1 at: 1/15/2016 7:12:33 AM    

Hello,

Is possible to use in templates images (from resources)?

Added By: Alexander Ch (DevExpress Support) at: 1/18/2016 4:45:20 AM    Hi Piotr,

ShapeTemplates allow you to describe a shape using primitives like Line and Arc. Displaying an image in a shape is a separate feature, which we plan to introduce in future versions.

Thanks,
AlexAdded By: Craig Dunstan at: 4/3/2016 7:05:49 AM    Is there any ability to leverage Visio stencils - either by converting them directly or via an intermediary like SVG?Added By: Alexander Rus (DevExpress Support) at: 4/4/2016 3:00:41 AM    

Hi Craig,
To process your recent post more efficiently, I created a separate ticket on your behalf: T363463: How to use shapes from Visio in DiagramControl

Thanks,
Alexander

Added By: Lavande at: 5/12/2016 11:16:13 PM    Hi,

Would you please explain further on how to build the xaml like yours? I am wondering this file is created by hand or I can use some funtions to generate the file automatically?
Added By: Alexander Rus (DevExpress Support) at: 5/13/2016 12:41:05 AM    

Hi Shuang,
I've created a separate ticket on your behalf (T378595: Is there a tool to generate shape descriptions for DiagramControl ). It has been placed in our processing queue and will be answered shortly.

Thanks,
Alexander

Added By: FreSoft at: 5/8/2017 4:23:54 AM    Hi

Can't find any reference to xml files properties. For example I can't undertand where or if possible add Content or BorderColor

OBSOLETE - How to update an ASPxGridView DataSource if the initial values are set programmatically in the HtmlRowCreated event

$
0
0

It is an often situation when the ASPxGridView's EditForm layout is defined using the EditFormTemplate. In this case, there are two solutions to initialize editor values

- first one is to use binding
- and the second one is to do it programmatically.

This example is devoted to the case where values need to be initialized programmatically.
(Using binding does not require any additional code)

If you are setting initial editor values programmatically, you should fetch modified editor values within the RowUpdating (RowInserting) event handlers and pass them to the Update (Insert) command of your DataSourceControl.
The problem comes because the ASPxGridView is rendered before the RowUpdating event is fired and thus newly input values are overriden with default ones.
This event is triggered because the ASPxGridView, as any other ASP.NET control, recreates its hierarchy (at a minimum) twice during a single request to the server:

- first time when the control's to be restored to a it's previous state...
- second time when all the required modifications are applied...

To work around this problem, it is possible to preserve editor values in a page's local variable. This should be done before setting default editor values. A sample project attached shows this approach in action.

See also:
The general technique of using the Init/Load event handler

How to apply a custom template and handle the CustomizeVisualViewInfo event to modify the appearance of the Day View

$
0
0
This example demonstrates how to use styles and templates to customize the WPF Scheduler appearance. You can adjust the custom template to achieve the desired visual effect.

ASPxDashboard - How to save dashboards to a database

$
0
0

This example shows how to create a custom dashboard storage that allows storing dashboards in a data base. It uses the System.Data.SqlClient members to connect and operate an MS SQL server data base. 

A custom dashboard storage should implement one of the following interfaces: IDashboardStorage or IEditableDashboardStorage.

IDashboardStorage provides functionality to open and edit dashboards available in the storage. 
XDocument LoadDashboard(string dashboardID) - returns a dashboard by its ID in the XDocument format, which describes an object model of the dashboard.
IEnumerable<DashboardInfo> GetAvailableDashboardsInfo() - returns a list of IDs and Captions of dashboards available in the data storage.
void SaveDashboard(string dashboardID, XDocument dashboard) - updates the dashboard with new settings by its id.

IEditableDashboardStorage inherits the IDashboardStorage interface and contains one additional method that allows adding new dashboards to the storage.
string AddDashboard(XDocument dashboard, string dashboardName) - takes a dashboard definition with its caption, saves it to the data storage, and returns the ID of a new saved dashboard.

Additionally, this example contains an SQL query and data base backup file,  which can be used to recreate a data base used in this example on your side.

See also: 
How to save dashboards created in ASPxDashboard to a DataSet
MVCxDashboard - How to save dashboards to a data base

This example applies to the Web Dashboard Designer starting from v2016 vol 1. To learn how to achieve this goal in previous versions, refer to the OBSOLETE - ASPxDashboardDesigner - How to save dashboards to a data base example.

Question Comments

Added By: James Badenhorst 1 at: 7/4/2016 1:41:46 AM    Hi DevExpress,
Quote from above...
"Additionally, this example contains an SQL Server data base backup file and....."
Sorry, but there is no Database backup file that I can find. There is a script to create an empty database, but that is all.
Please would you be kind enough to rectify.
Regards
James
Added By: John (DevExpress Support) at: 7/4/2016 2:21:41 AM    Hi James,
I have attached this backup file to the initial post.Added By: James Badenhorst 1 at: 7/4/2016 8:32:39 AM    Many thanks John - Is there any chance at all we might see an MVC example in the near future.
Regards
James
Added By: James Badenhorst 1 at: 7/4/2016 8:50:40 AM    John,
Apologies - cant find it. The original script to build the table starts off as
"USE [T386418]
GO"
So I am assuming the backup file would be "T386418.bak". Please correct me if I am wrong.

POI - The example runner on this page does not seem to like or open the project in VS2010 (Our company default).
I have VS2015 installed, however the example runner always tries to open in VS2010 first, and fails with an incompatibility error. Have to close it down, navigate to folder and re-open with VS2015. Have not seen this behaviour before.
Regards
James
Added By: James Badenhorst 1 at: 7/4/2016 9:23:05 AM    John,
Having created my own SQL database called T386481, and created the Dashboards table for the dashboard storage, run the app and get the error in the bottom right of the screen "An error occured on an attempt to load the list of available data sources". Putting a breakpoint in the Application_Start method of the  Global.asax.cs file (where the Access97 connection string is set for the CustomerReports view), this is not being hit before the app errors.
Many Thanks
James


Added By: John (DevExpress Support) at: 7/5/2016 6:02:53 AM    >>Is there any chance at all we might see an MVC example in the near future.
Thank you for your suggestion. We will prepare this example in the future.

>>I have VS2015 installed, however the example runner always tries to open in VS2010 first, and fails with an incompatibility error. Have to close it down, navigate to folder and re-open with VS2015. Have not seen this behaviour before.
Give me some additional time to research this behavior.

>>run the app and get the error in the bottom right of the screen "An error occured on an attempt to load the list of available data sources". Putting a breakpoint in the Application_Start method of the  Global.asax.cs file (where the Access97 connection string is set for the CustomerReports view), this is not being hit before the app errors.

I have created a separate ticket for this question on your behalf: ASPxDashboardDesigner - save dashboards to a data base implementation. Let's continue our discussion there.Added By: James Badenhorst 1 at: 7/5/2016 6:25:59 AM    John,
Many thanks for your response.
Is there any news on the missing database with the report definitions?
Best regards
James
Added By: John (DevExpress Support) at: 7/6/2016 6:15:34 AM    Hi James,
I have updated this example projects.Added By: James Badenhorst 1 at: 7/6/2016 6:36:32 AM    John,
Works straight out the box.
Once again Many Thanks
James
Added By: Gregory Lange 1 at: 10/13/2016 8:23:25 AM    So if i am understanding correctly we need to make the class that implements the IEditableDashboardStorage like your example that then points to the database which will load or save the xml data to an xml column? Added By: John (DevExpress Support) at: 10/13/2016 8:34:00 AM    Yes Gregory. You are correct.

How to generate a sequential and user-friendly identifier field within an XPO business class

$
0
0

Scenario

Orders, articles or other business entities often require that you have user-friendly Id or Code fields that end-users can memorize and use during phone conversations. They are usually sequential, but some gaps can be allowed as well (e.g., when an order is deleted). Refer to this StackOverFlow thread for more information on this common scenario, and a possible implementation.

Steps to implement

1. Add a new business class to your platform-agnostic module, and  call the static DevExpress.Persistent.BaseImpl.DistributedIdGeneratorHelper.Generate method from the AfterConstruction, OnSaving or other appropriate places within your persistent class or even Controller as shown in the Solution2.Module\BusinessObjects\Order.xx file. Depending on your business requirements, you can implement a readonly persistent or editable property where the generated value will be stored as well as check various conditions before generating the next sequence (e.g., string.IsNullOrEmpty(currentSequenceProperty) - to avoid double assignments, Session.IsNewObject(this) - to check whether the object is new, !(Session is NestedUnitOfWork) - to check whether the object is being saved to the database and not to the parent session, security system checks as per this blog post, etc.)

2. Build your platform-agnostic project and double-click on the Solution2.Module\Module.xx file to invoke the Module Designer;

3. Refer to the Exported Types section within the designer and expand the Referenced Assemblies | DevExpress.Persistent.BaseImpl node;

4. Select and press the space bar on the OidGenerator node to include this persistent type into the business model of your module:

 

IMPORTANT NOTES
1. The DistributedIdGeneratorHelper class demonstrated in this solution creates the IDGeneratorTable table to store the information about the last sequential number of a type. You can learn more on how this works from its source code at "C:\Program Files (x86)\DevExpress 1X.X\Components\Sources\DevExpress.Persistent\DevExpress.Persistent.BaseImpl\IDGenerator.cs".
Although this particular solution is simpler to implement and maintain (as it uses built-in XAF classes) than the How to generate and assign a sequential number for a business object within a database transaction, while being a part of a successful saving process (XAF) example, it is pretty safe and should also work in the most typical business scenarios.

2. If you have validation rules for your business class, the OnSaving method (and thus the sequence generation) is called only after all validation is passed. However, in rare cases, if a database related error is thrown during the first save and then the form is re-saved, the OnSaving method may be called again and a new sequence can be generated. This may lead to gaps in sequential numbers, which is not always allowed by business requirements (e.g., government regulations). To avoid this, you can use a more complicated solution from the How to generate and assign a sequential number for a business object within a database transaction, while being a part of a successful saving process (XAF) example or implement a database-level solution to handle such situations (e.g., using triggers).
3.  In the Integrated Mode and middle-tier Application Server scenario the newly generated sequence number will appear in the DetailView only after a manual refresh (i.e., it will be empty right away after saving a new record), because the sequence is generated on the server side only and is not passed to the client. You can download a ready test project for these configurations here.

4. You can find functional EasyTest scripts for this scenario in the Solution2.Module\FunctionalTests\E4904.ets file.

Question Comments

Added By: Gareth- at: 10/2/2013 5:58:17 AM    

Thanks, works perfectly - I've seeded the ID by manually changing the [Oid] in the IDGeneratorTable, do I need to worry about the [OptimisicLockField] or will this update automatically?

Added By: Dennis (DevExpress Support) at: 10/2/2013 7:10:50 AM    

@Gareth: No, you do not need to care about the OptimisticLockField.

Added By: MohammedFarooq at: 12/2/2013 1:07:31 AM    

Hi,

The code is really helpful but it increments the value of code even if the record is deleted! How can we stop the code to increase its value when a record is deleted?

Added By: MohammedFarooq at: 12/2/2013 1:25:16 AM    

I manage to figure out the solution. I have just added the IsDeleted checking and it worked like a charm!!!

    Protected Overrides Sub OnSaving()
        If (Not IsDeleted) Then
             Me.codeCore = String.Format("N{0:D6}", DistributedIdGeneratorHelper.Generate(Me.Session.DataLayer, Me.GetType().FullName, String.Empty))
        End If
        MyBase.OnSaving()
    End Sub

Added By: Dennis (DevExpress Support) at: 12/2/2013 1:26:50 AM    

@Mohammed: Yes, your solution is correct. I will consider updating this example accordingly. Thanks for your input in this regard.

Added By: rushdan . at: 11/6/2014 12:02:48 AM    

Hallo

I do not understand about explanation. What I know is, after I run the application, then save the data , it will execute Code number automatically.

Is it this example to show how to execute auto increase number ? Thanks

Added By: Dennis (DevExpress Support) at: 11/6/2014 2:00:43 AM    

@Rushdan: With the current implementation, the generation code is executed when the persistent object is being saved (OnSaving). I do not quite understand your last question. The functionality implemented in this example is well-detailed in the description and it can also be seen from simple code.

Added By: Andrew Bingham 2 at: 2/5/2015 12:40:25 AM    

"override its AfterConstruction method, as shown in the Solution2.Module\BusinessObjects\DomainObject1.xx file"

1. I cannot find the DomainObject1 file in the sample
2. The only BusinessObject is Order.cs which does not have an AfterConstruction method
3. What code need to go in AfterConstruction method?
4. What are the advantages / disadvantages compared to E2829?

Added By: Dennis (DevExpress Support) at: 2/5/2015 12:47:04 AM    @Andrew: Thanks for your feedback.
1-3. I've corrected this misprint in the description. 
3. This particular solution is simpler to implement than E2829.Added By: Vishwas Mokashi at: 4/21/2015 8:52:32 AM    

Is there any provision so that we can restart the Sequence Number after say an Year is completed?. Also, any way to give the start number for the sequence?.

Added By: Dennis (DevExpress Support) at: 4/21/2015 8:57:35 AM    

@Vishwas: Sure, you can do this. Technically, the information about the last sequence number is stored in the Oid column of the IDGeneratorTable table with the help of the OidGenerator persistent class. You can modify this data using either ADO.NET or XPO means.

Added By: Vishwas Mokashi at: 4/21/2015 9:02:11 AM    

Ok thanks Dennis...will try

Added By: MohammedFarooq at: 10/14/2015 2:37:53 AM    

Dear Dennis,

I have applied this logic in my project which also has validation enabled. Now the issue is, if the validation of the document fails while saving the new number is generated. And when the user saves the document again then a new number is generated as well.

Added By: Dennis (DevExpress Support) at: 10/14/2015 2:58:59 AM    @Mohammed: The original example has the if(string.IsNullOrEmpty(Code))  check that prevents multiple generations. Have you applied this code in your project? If this does not help, submit a separate ticket and attach your problematic sample so we can assist you further.Added By: MohammedFarooq at: 10/14/2015 5:03:57 AM    

You hit a bull's eye! I didn't have the  if(string.IsNullOrEmpty(Code)) in my code.

Was it added recently? Because i followed this example before and somehow i missed it.

Added By: Dennis (DevExpress Support) at: 10/14/2015 5:18:38 AM    You're always welcome. AFAIK, I added it a year ago or so.Added By: Paul Kubb at: 3/16/2016 2:14:58 AM    Would you please describe more in detail about serverprefix table? how and when to use it?
I cannot find any documentation about it also.Added By: Dennis (DevExpress Support) at: 3/17/2016 1:57:56 AM    

@Paul: It was a mistake in the original description, because this table is actually unused by the DistributedIdGeneratorHelper class. Please accept my apologies for the confusion. As for the "string serverPrefix" parameter of the Generate method, it allows you to run several sequences in parallel. Refer to the "C:\Program Files (x86)\DevExpress 1X.X\Components\Sources\DevExpress.Persistent\DevExpress.Persistent.BaseImpl\IDGenerator.cs" source file for more details.

Added By: Paul Kubb at: 8/4/2016 9:44:09 AM    I have read a source file and have several questions aboud DistributedIdGeneratorHelper.Generate():

1.  it seems like you intend to create a separate new session, attempt to save it to the database separately until success and return its Oid. Why can't we use the bo's existing session here?

2. by this design, do you intend to avoid some multi-user problem or something? if so, please explain why having a separate session will overcome it

3. if the OidGenerator is saved successfully in a separate session but the main bo's save event is dead, will the OidGenerator's save event be rolled back? or will we have a jumpy running number instead?

thanks in advance

Added By: Dennis (DevExpress Support) at: 8/5/2016 7:12:09 AM    

@Paul:
A1-2: Your understanding of class design is correct. A separate session will help to avoid concurrency issues in a multi-user environment: if another user generated a new number while you were saving your own, the locking exception occurs and a new attempt to generate the next number for you starts in the loop.
A3:No, it will not. See my answer in the T304004 ticket for more details.

Added By: wang yu 4 at: 9/23/2016 12:59:54 AM    does it support middle tier ?Added By: Dennis (DevExpress Support) at: 9/23/2016 2:13:47 AM    

@Wang: As in the example's description, the DistributedIdGeneratorHelper class currently does not support the middle-tier Application Server scenario, because the Session.DataLayer property is not initialized in this case.

Added By: 13 chi at: 10/3/2016 2:21:46 AM    That fix for middle-tier doesn't work well.
[C#]
newSession(sourceSession.ObjectLayer).DataLayer;
still returns null.
Added By: Dennis (DevExpress Support) at: 10/4/2016 2:41:06 AM    @13 chi: Thanks for your report and please accept my apologies for the inconvenience here. I will update the article with a better solution as soon as it is available.Added By: Dennis (DevExpress Support) at: 10/4/2016 10:29:13 AM    @13 chi: I've updated the E4904 example classes for the middle-tier Application Server scenario (see additional checks in the OnSaving method). Note that in this scenario, the generated sequence number will appear in the WinForms DetailView only after a manual refresh (i.e., it will be empty right away after saving a record), because the sequence is generated on the server side only and is not passed to the client.

How to generate and assign a sequential number for an XPO business object within a database transaction, while being a part of a successful saving process (XAF)

$
0
0

Scenario
This is a variation of the How to generate and assign a sequential number for a business object within a database transaction, while being a part of a successful saving process XPO example, which was specially adapted for XAF applications.

In particular, for better reusability and more smooth integration with the standard XAF CRUD Controllers, all the required operations to generate sequences are managed within the base persistent class automatically when a persistent object is being saved. For more developer convenience, this solution is organized as a reusable XAF module - GenerateUserFriendlyId.Module. This module consists of several key parts:

    - Sequence and SequenceGenerator are auxiliary classes that take the main part in generating user-friendly identifiers. Take special note that the SequenceGenerator.Initialize method must be called during your XAF application startup for the correct operation.

    - UserFriendlyIdPersistentObject is a base persistent class that subscribes to XPO's Session events and delegates calls to the core classes above. Normally, you must inherit your own business classes from this base class to get the described functionality in your project.

    - IUserFriendlyIdDomainComponent is a base domain component that should be implemented by all domain components that require the described functionality.

Check the original example description first for more information on the demonstrated scenarios and functionality.




Steps to implement
1. Copy and include the GenerateUserFriendlyId.Module project into your solution and make sure it is built successfully.  Invoke the Module or Application Designer for the YourSolutionName.Module/Module.xx  or YourSolutionName.Wxx/WxxApplication.xx files by double-clicking it in Solution Explorer. Invoke the Toolbox (Alt+X+T) and then drag & drop the GenerateUserFriendlyIdModule component into the modules list on the left.

2. For apps with no security or with the Client-Side Security (XPObjectSpaceProvider or SecuredObjectSpaceProvider):
In the YourSolutionName.Wxx/WxxApplication.xx files, modify the CreateDefaultObjectSpaceProvider method to call the SequenceGenerator.Initialize method as shown in the Demo.Wxx\WxxApplication.xx files:

[C#]
...protectedoverridevoidCreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgsargs){GenerateUserFriendlyId.Module.Utils.SequenceGenerator.Initialize(this,args.ConnectionString);//!!!...}

For apps with the Middle Tier Security (DataServerObjectSpaceProvider):
In the YourSolutionName.ApplicationServer project, locate and modify the serverApplication_CreateCustomObjectSpaceProvider or CreateDefaultObjectSpaceProvider  methods to call the SequenceGenerator.Initialize method as shown below:

[C#]
privatestaticvoidserverApplication_CreateCustomObjectSpaceProvider(objectsender,CreateCustomObjectSpaceProviderEventArgse){GenerateUserFriendlyId.Module.SequenceGenerator.Initialize((XafApplication)sender,e.ConnectionString);

In the same code file, locate the serverApplication.Dispose(); line and move to the end of the Main or OnStop methods in the Console or Windows Service applications respectively (in the latter case, the "serverApplication" variable must also be declared in the higher scope).


3.
 If you are using pure XPO classes, then inherit your required business classes from the module's UserFriendlyIdPersistentObject one and use the derived SequenceNumber property as required:

[C#]
publicclassContact:GenerateUserFriendlyId.Module.BusinessObjects.UserFriendlyIdPersistentObject{[PersistentAlias("concat('C', ToStr(SequentialNumber))")]publicstringContactId{get{returnConvert.ToString(EvaluateAlias("ContactId"));}}

If you are using DC interfaces, then implement the IUserFriendlyIdDomainComponent interface by your custom domain component:

[C#]
publicinterfaceIDocument:GenerateUserFriendlyId.Module.BusinessObjects.IUserFriendlyIdDomainComponent{[Calculated("concat('D', ToStr(SequentialNumber))")]stringDocumentId{get;}

Additionally for DC, use the UserFriendlyIdPersistentObject as a base class during your custom domain component registration, e.g.:

[C#]
XafTypesInfo.Instance.RegisterEntity("Document",typeof(IDocument),typeof(GenerateUserFriendlyId.Module.BusinessObjects.UserFriendlyIdPersistentObject));

Note that the sequential number functionality shown in this example does not work with DC shared parts , because it requires a custom base class, which is not allowed for shared parts.

4. For more information, download and review the Address, Contact, and IDocument types within the Demo.Module project. These are test business objects that demonstrate the use of the described functionality for XPO and DC respectively. A required format for the user-friendly identifier property in these end classes is defined within an aliased property (ContactId in the example above) by concatenation of a required constant or dynamic value with the SequentialNumber property provided by the base UserFriendlyIdPersistentObject class. So, if you need to have a different format, modify the PersistentAliasAttribute expression as your business needs dictate.

 

IMPORTANT NOTES

1. As an alternative, you can use a more simple solution that is using the DistributedIdGeneratorHelper.Generate method as shown in the FeatureCenter demo ("%Public%\Documents\DXperience 13.X Demos\eXpressApp Framework\FeatureCenter\CS\FeatureCenter.Module\KeyProperty\GuidKeyPropertyObject.cs" ) or at How to generate a sequential and user-friendly identifier field within a business class 
2.  In the Integrated Mode and middle-tier Application Server scenario the newly generated sequence number will appear in the DetailView only after a manual refresh (i.e., it will be empty right away after saving a new record), because the sequence is generated on the server side only and is not passed to the client. You can download a ready test project for these configurations here.

Question Comments

Added By: Mr. Murat YILMAZ at: 10/7/2012 9:15:18 AM    

Thanks for the example. I developed ISequentialNumber domain component which based on this article and code. Now this sequential number functonatility shon in this example work with domain components and shared parts.

using System;
using System.Collections.Generic;
using System.ComponentModel;

using DevExpress.ExpressApp.DC;
using DevExpress.Persistent.Base;
using DevExpress.Xpo;
using DevExpress.Xpo.Metadata;
using DevExpress.ExpressApp;
using DevExpress.Persistent.Base;
using DevExpress.Persistent.BaseImpl;
using DevExpress.Persistent.Validation;

using MyWay.Xaf.Module;
using MyWay.Xaf.Utils.Sequence;

namespace MyWay.Xaf.Module
{
    [DomainComponent]
    [NavigationItem]
    public interface ISequentialNumber
    {
        #region PROPERTIES

        #region SequentialNo

        [Persistent]
        string SequentialNo
        {
            get;
        }

        #endregion SequentialNo

        #region SequentialNumber
        
        [System.ComponentModel.Browsable(false)]
        [Indexed(Unique = false)]
        long SequentialNumber
        {
            get ;
            set;
        }

        #endregion SequentialNumber

        #endregion PROPERTIES
    }

    [DomainLogic(typeof(ISequentialNumber))]
    public class ISequentialNumberLogic
    {

            public static string Get_SequentialNo(ISequentialNumber instance)
            {
                return "asd" + instance.SequentialNumber.ToString();
            }

            

        private static object syncRoot = new object();
        private static SequenceGenerator sequenceGenerator;

        #region METHODS

        #region PUBLIC METHODS

        #region GenerateSequence

        public static void GenerateSequence(ISequentialNumber instance)
        {
            lock (syncRoot)
            {
                Dictionary<string, bool> typeToExistsMap = new Dictionary<string, bool>();

                foreach (object item in ((XPBaseObject)instance).Session.GetObjectsToSave())
                {
                    typeToExistsMap[((XPBaseObject)instance).Session.GetClassInfo(item).FullName] = true;
                }

                if (sequenceGenerator == null)
                {
                    sequenceGenerator = new SequenceGenerator(typeToExistsMap);
                }

                SubscribeToEvents(((XPBaseObject)instance).Session);
                OnSequenceGenerated(sequenceGenerator.GetNextSequence(((XPBaseObject)instance).ClassInfo), instance);
            }
        }

        #endregion GenerateSequence

        #endregion PUBLIC METHODS

        #region PROTECTED METHODS

        #region OnSaving

        public static void OnSaving(ISequentialNumber instance)
        {
            try
            {
                //base.OnSaving();
                if (((XPBaseObject)instance).Session.IsNewObject(instance) && !typeof(NestedUnitOfWork).IsInstanceOfType(((XPBaseObject)instance).Session))
                {
                    GenerateSequence(instance);
                }
            }
            catch
            {
                CancelSequence(((XPBaseObject)instance).Session);
                throw;
            }
        }

        #endregion OnSaving

        #endregion PROTECTED METHODS

        #region INTERNAL METHODS

        #endregion INTERNAL METHODS

        #region PRIVATE METHODS

        #region AcceptSequence

        private static void AcceptSequence(Session session)
        {
            lock (syncRoot)
            {
                if (sequenceGenerator != null)
                {
                    try
                    {
                        sequenceGenerator.Accept();
                    }
                    finally
                    {
                        CancelSequence(session);
                    }
                }
            }
        }

        #endregion AcceptSequence

        #region CancelSequence

        private static void CancelSequence(Session session)
        {
            lock (syncRoot)
            {
                UnSubscribeFromEvents(session);
                if (sequenceGenerator != null)
                {
                    sequenceGenerator.Close();
                    sequenceGenerator = null;
                }
            }
        }

        #endregion CancelSequence

        #region Session_AfterCommitTransaction

        private static void Session_AfterCommitTransaction(object sender, SessionManipulationEventArgs e)
        {
            
            AcceptSequence(e.Session);
        }

        #endregion Session_AfterCommitTransaction

        #region Session_AfterRollBack

        private static void Session_AfterRollBack(object sender, SessionManipulationEventArgs e)
        {
            CancelSequence(e.Session);
        }

        #endregion Session_AfterRollBack

        #region Session_FailedCommitTransaction

        private static void Session_FailedCommitTransaction(object sender, SessionOperationFailEventArgs e)
        {
            CancelSequence((Session)sender);
        }

        #endregion Session_FailedCommitTransaction

        #region SubscribeToEvents

        private static void SubscribeToEvents(Session session)
        {
            if (!(session is NestedUnitOfWork))
            {
                session.AfterCommitTransaction += Session_AfterCommitTransaction;
                session.AfterRollbackTransaction += Session_AfterRollBack;
                session.FailedCommitTransaction += Session_FailedCommitTransaction;
            }
        }

        #endregion SubscribeToEvents

        #region UnSubscribeFromEvents

        private static void UnSubscribeFromEvents(Session session)
        {
            if (!(session is NestedUnitOfWork))
            {
                session.AfterCommitTransaction -= Session_AfterCommitTransaction;
                session.AfterRollbackTransaction -= Session_AfterRollBack;
                session.FailedCommitTransaction -= Session_FailedCommitTransaction;
            }
        }

        #endregion UnSubscribeFromEvents

        #region OnSequenceGenerated

        private static void OnSequenceGenerated(long newId, ISequentialNumber instance)
        {
            instance.SequentialNumber = newId;
        }

        #endregion OnSequenceGenerated

        #endregion PRIVATE METHODS

        #endregion METHODS
    }
}

Added By: Luis Alberto Santiago at: 2/25/2013 8:06:36 PM    

Hi Mr. Murat YILMAZ, Can yo provide some example to use the class. I am looking it for shared parts

Added By: Andrew Bingham 2 at: 7/8/2013 3:38:51 AM    

I implemented this OK in a Solution

When I eimplmented it in a different solution I got an Exception
"Message: Value cannot be null.
Parameter name: Application"

thrown at:

    public static void Initialize() {
            Guard.ArgumentNotNull(Application, "Application");

Added By: Dennis (DevExpress Support) at: 7/11/2013 3:11:06 AM    

@Andrew: You forgot to add the following code:

public override void Setup(XafApplication application) {
            base.Setup(application);
            SequenceGeneratorInitializer.Register(application);
        }

You will not experience this and similar difficulties if you simply add the reusable module into your solution as per instructions above.

Added By: Carlitos at: 8/23/2014 6:46:05 PM    

Hi,
Is this now supported in Middle-Tier XAF applications?

Thanks,

Carlitos

Added By: Dennis (DevExpress Support) at: 8/25/2014 4:38:12 AM    

We have not performed additional R&D and testing of this particular example in a middle-tier scenario. Moreover, I see technical problems using this particular solution in this configuration, because here we use ExplicitUnitOfWork, which implies that it will be a sole owner of the database connection. Probably, for this configuration, it is better to stick to a standard solution, e.g. using database triggers. 

Added By: Carlitos at: 8/25/2014 9:34:23 AM    

Hi Dennis,
But how does the Middle-tier handle database connections? I thought it would do some sort of connection pooling and manage all client connections?

Why do you think that Triggers are a good alternative?

Carlos

Added By: Dennis (DevExpress Support) at: 8/26/2014 6:14:27 AM    

By default, the middle-tier app server uses ThreadSafeDataLayer to effectively handle requests from multiple clients at the same time. Connection pooling may be used here, but this is not managed by us by default and is rather controller by ADO.NET transparently for a consumer. My main concern here was that in such a multi-user environment it will not be possible to exclusively lock the connection by one user.
A solution at the database level looks more universal as it works at the database level and is irrelevant to whether the app server is used or not. 

Added By: Vishwas Mokashi at: 4/14/2015 11:21:58 AM    

In XAF application I have about 25 various business objects that need to generate unique user friendly sequence numbers in when saved. For example Customer Number, Invoice Number, Order Number, etc. Many users are going to work concurrently and everything should work in transaction.

Which approach should I use, the one in E2620 or E2829?.

I felt E2620 a bit better as I need not to inherit my classes (25 of them) from  UserFriendlyIdPersistentObject as shown in E2829.  

But approach in E2829 is said to be primarily for XAF applications

Added By: Dennis (DevExpress Support) at: 4/15/2015 4:47:25 AM    

@Vishwas: Both E2620  and E2829 demonstrate the same solution using ExplicitUnitOfWork. E2829 is just a bit better integrated with the XAF infrastructure.
If you do not want to inherit from a common base class, I suggest you consider using How to generate a sequential and user-friendly identifier field within a business class, which is simpler to implement and provides similar capabilities without using ExplicitUnitOfWork.

Added By: Vishwas Mokashi at: 4/17/2015 6:54:45 AM    

OK thanks Dennis.

Will simpler approach in "How to generate a sequential and user-friendly identifier field within a business class" handle concurrent users creating same business objects properly?. We can assume about 25 Concurrent users for same business object, with SQL Server DB.

Some users will be accessing system over low banddwidth VPN internet connection. (for Sale Invoice object which needs to generate sequencial Invoice Numbers)

Added By: Dennis (DevExpress Support) at: 4/20/2015 7:58:16 AM    

@Vishwas: Yes, it will. The DistributedIdGeneratorHelper class tries to save a record and repeats its attempts several times until it reaches the maximum number or saves data completely. Check out the corresponding source code for more details on how this works.

    public static class DistributedIdGeneratorHelper {
        public const int MaxIdGenerationAttemptsCounter = 7;
        public static int Generate(IDataLayer idGeneratorDataLayer, string seqType, string serverPrefix) {
            for(int attempt = 1; ; ++attempt) {
                try {
                    using(Session generatorSession = new Session(idGeneratorDataLayer)) {
                        CriteriaOperator serverPrefixCriteria;
                        if(serverPrefix == null) {
                            serverPrefixCriteria = new NullOperator("Prefix");
                        }
                        else {
                            serverPrefixCriteria = new BinaryOperator("Prefix", serverPrefix);
                        }
                        OidGenerator generator = generatorSession.FindObject<OidGenerator>(
                            new GroupOperator(new BinaryOperator("Type", seqType), serverPrefixCriteria));
                        if(generator == null) {
                            generator = new OidGenerator(generatorSession);
                            generator.Type = seqType;
                            generator.Prefix = serverPrefix;
                        }
                        generator.Oid++;
                        generator.Save();
                        return generator.Oid;
                    }
                }
                catch(LockingException) {
                    if(attempt >= MaxIdGenerationAttemptsCounter)
                        throw;
                }
            }
        }Added By: Vishwas Mokashi at: 4/21/2015 6:03:28 AM    

Thanks Dennis

DXRichEdit Getting Started - Lesson 1 - Create a Simple Rich Text Editor

$
0
0

This example demonstrates how to create a simple WPF application with RichEditControl. It can be useful for you in solving this task if you are a first-time user of the DXRichEdit suite.

You can replicate the same project by performing steps from the following tutorial: DXRichEdit - Create a Simple Rich Text Editor.

All Getting Started Examples: Lesson 1Lesson 2Lesson 3Lesson 4

DXRichEdit Getting Started - Lesson 3 - Provide Ribbon UI for a RichEditControl

ASPxGridView - How to filter data by using the Header Filter when a cell contains text separated with a comma

$
0
0

This example illustrates how to customize the Header Filter to allow filtering text separated with a comma in the grid column.

Question Comments

Added By: Jan Šotola at: 5/12/2017 4:15:45 AM    Thank you for the example. It is clear, short and useful.

However, be aware that it would not work well, it there are two (or more cities) in the list where one is a substring of another (like "York" and "New York").Added By: Vova (DevExpress Support) at: 5/12/2017 5:01:26 AM    

Hello,

I've created a separate ticket on your behalf (T514189: ASPxGridView - How to filter data by using the Header Filter when a cell contains values separated with a comma and one of these values is a substring of another ). It has been placed in our processing queue and will be answered shortly.

How to use GridView in Batch Edit mode in another grid Edit Form

$
0
0

This example demonstrates how to edit a detail grid with Batch Edit mode enabled in the master grid edit form. The main point is that it is impossible to update both grids simultaneously. So, we need to send two consequent callbacks to update the detail and master grids:

[JavaScript]
function onUpdateButton (s, e){if(detail.batchEditApi.HasChanges()) detail.UpdateEdit();else master.UpdateEdit();}function onDetailEndCallback(s, e){ master.UpdateEdit();}

This code describes the basic principle, while the example shows a more complex and thorough implementation. Also, this approach requires additional actions when a new row is created in the master grid. As the detail grid is saved before the master grid, when a new row is created, the detail grid doesn't have the master key which is used to save the details. In this case, you will have to save the detail grid data to a temporary field and then write changes when the master row is created.

How to use a single ASPxPopupControl for the entire application

WinForms Dashboard Designer - How to customize the Data Source wizard for the OLAP data source


Spreadsheet Mail Merge - Getting Started

$
0
0

This example demonstrates how to use the Spreadsheet Mail Merge functionality to automatically generate a document based on data retrieved from a specified data source (the Categories table of the Northwind database). The nwind.mdb database file is included in the project. This file ships with the XtraSpreadsheet Suite installation.

The application includes the following controls.

1. SpreadsheetControl

A ready-to-use mail merge template (the MailMergeTemplate.xlsx file) is automatically loaded into the SpreadsheetControl when invoking the application. This template is bound to the Categories table of the Northwind database via the IWorkbook.MailMergeDataSource and IWorkbook.MailMergeDataMember properties in code.

2. Field List

The Field List panel shows the structure of the mail merge data source at runtime. You can add mail merge fields to template cells by drag-and-drop or by double-clicking the corresponding items in this panel.

3. RibbonControl with the Mail Merge tab
The Mail Merge page contains various command buttons that you can use to modify the mail merge template. For example, you can do the following.
- Enable the Mail Merge Design View. This is a specific mode to display worksheets intended for preparing mail merge templates. It is recommended that you activate this view before creating or modifying a template.
- Select one of the available modes to specify whether data records should be merged into separate workbooks, separate worksheets in a single workbook, or a single worksheet. By default, the Single Sheet mode is used.
- Set the vertical or horizontal orientation for the resulting worksheet.
- Specify the Detail, Header and Footer ranges in the template.
- Sortgroup and filter the data to appear in the resulting document.
- Preview the merged document.
In this example, the Result button is added to the Mail Merge page. It calls the IWorkbook.GenerateMailMergeDocuments method, which returns the resulting workbook and saves it to a file. If the mail merge mode is set to Multiple Documents, each workbook returned by the GenerateMailMergeDocuments method is saved to a separate file.

Spreadsheet Mail Merge - Group Data

$
0
0
When performing a mail merge with the SpreadsheetControl, you can sort data to be merged and split it into groups based on identical values in the specified data field.
This example contains the mail merge template to generate invoices using data from the Invoices view of the Northwind database. The nwind.mdb database file is included in the project. This file ships with the XtraSpreadsheet Suite installation. The template is bound to the data source via the IWorkbook.MailMergeDataSource and IWorkbook.MailMergeDataMember properties in code.

Run the application and review the prepared template (the MailMergeTemplate_GroupData.xlsx file) that is automatically loaded into the SpreadsheetControl.
On the Mail Merge tab, enable the Mail Merge Design View to highlight the template structure. The template consists of the following ranges.
- Header
The Header range contains the current date to be displayed above each invoice.
- Detail
The Detail range contains fields for merging order data (general order information, products ordered and order totals). In this range, the OrderID data field is set as a criterion for sorting data. To make sure of this, check that the OrderID field is displayed in the Sort Fields dialog (to invoke this dialog, select any cell within the Detail range and click the Sort Fields button on the Mail Merge tab), and the SORTFIELD0 defined name for the OrderID field is added to the worksheet's collection of defined names (you can see this defined name in the Name Manager dialog when you click the corresponding button on the Formulas tab).
- GroupHeader
All general information for a group of records is located within the GroupHeader0 range. In this example, each group is an order. Thus, the group header contains information about the order, customer, salesperson, dates, delivery, etc. The existing OrderID(Ascending) sort field is used as a criterion for creating groups in the merged document (this sort field was selected when the GroupHeader range was created). In the Name Manager dialog, you can see the GROUPHEADER0 defined name that corresponds to this group header range.
- GroupFooter
The GroupFooter0 range displays totals at the end of a group of records (in other words, at the end of an order). It is also created based on the OrderID(Ascending) sort field and saved in the template document as a defined name (GROUPFOOTER0).
In this template, the mail merge mode is set to Multiple Sheets. Thus, each order will be inserted in a separate worksheet. To review the result, click the Mail Merge Preview button on the Mail Merge tab.

How to import HTML files containing images referenced using custom prefix

$
0
0

By default, RichEditControl can import HTML files containing embedded images or links to external images with the src attribute specified as an image URL. Occasionally, you may have a web file where images are referenced in a custom manner (e.g. using the prefix 'cid' in the img src attribute, as in email files). In this scenario, you should implement and register a custom IUriStreamProvider to import these files into a RichEditControl correctly. This example illustrates the technique used to get an image referenced with the "cid" prefix from an external file in "bmp" format.

This approach is similar to the technique mentioned in the Business Letters and Mail Merge with Rich Text Edit (Part 1) blog post. The reverse approach (i.e. modifying image references when exporting) implies using a custom IUriProvider, as described in the Business Letters and Mail Merge with Rich Text Edit (Part 2) blog post.

See Also:
Building a mail application with the RichEditControl

Question Comments

Added By: Jaap van der Have at: 5/16/2017 11:38:27 PM    Thanks for the great example, i made the following changes to it so it detects errors and imageformat. Also a very important thing is to set the RicheditControl to async if you want to wait for the loading to finish before continueing (and have not all images loaded yet). 
RicheditControlName.Options.Import.Html.AsyncImageLoading = false;

Also see https://www.devexpress.com/Support/Center/Question/Details/T515172 (also for a bigger example based on html import and outlook embedded mail

[C#]
// HTMLImport (https://www.devexpress.com/Support/Center/Example/Details/E3123)privateclassCustomUriStreamProvider:IUriStreamProvider{privatestringbasePath;//private string imageExtension;publicstringBasePath{get{returnbasePath;}set{basePath=value;}}publicCustomUriStreamProvider(stringbasePath){BasePath=basePath;}privatestaticSystem.Drawing.Imaging.ImageFormatGetImageFormat(System.Drawing.Imageimg){if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Jpeg))returnSystem.Drawing.Imaging.ImageFormat.Jpeg;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Bmp))returnSystem.Drawing.Imaging.ImageFormat.Bmp;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Png))returnSystem.Drawing.Imaging.ImageFormat.Png;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Emf))returnSystem.Drawing.Imaging.ImageFormat.Emf;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Exif))returnSystem.Drawing.Imaging.ImageFormat.Exif;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Gif))returnSystem.Drawing.Imaging.ImageFormat.Gif;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Icon))returnSystem.Drawing.Imaging.ImageFormat.Icon;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.MemoryBmp))returnSystem.Drawing.Imaging.ImageFormat.MemoryBmp;if(img.RawFormat.Equals(System.Drawing.Imaging.ImageFormat.Tiff))returnSystem.Drawing.Imaging.ImageFormat.Tiff;else{System.Diagnostics.Debug.Print("Cannot find type use it as a WMF image");returnSystem.Drawing.Imaging.ImageFormat.Wmf;}}publicStreamGetStream(stringurl){//string fileName = string.Format("{0}", url.Replace("cid:", string.Empty));stringfileName=string.Format("{0}",url.Replace("cid:",string.Empty));try{if(File.Exists(BasePath+fileName)){MemoryStreammemoryStream=newMemoryStream();Imageimage=Image.FromFile(BasePath+fileName);System.Diagnostics.Debug.Print("Loading Image: "+BasePath+fileName);image.Save(memoryStream,GetImageFormat(image));memoryStream.Seek(0,SeekOrigin.Begin);returnmemoryStream;}else{thrownewFileNotFoundException(@"File "+BasePath+fileName+" is not found");}}catch(Exceptionex){XtraMessageBox.Show("Error loading image "+BasePath+fileName+" from html template possible corrupt file?\r\n\r\n"+ex);returnnull;}}}// ExportprivateclassRichEditMailMessageExporter:IUriProvider{readonlyRichEditControlcontrol;readonlyOutlook._MailItemmailItem;intimageId;stringtempFiles=Path.Combine(Directory.GetCurrentDirectory(),"TempFiles");publicRichEditMailMessageExporter(RichEditControlcontrol,Outlook._MailItemmailItem){Guard.ArgumentNotNull(control,"control");Guard.ArgumentNotNull(mailItem,"mailItem");this.control=control;this.mailItem=mailItem;}publicvirtualvoidExport(){if(!Directory.Exists(tempFiles))Directory.CreateDirectory(tempFiles);control.BeforeExport+=OnBeforeExport;stringhtmlBody=control.Document.GetHtmlText(control.Document.Range,this);control.BeforeExport-=OnBeforeExport;mailItem.BodyFormat=Outlook.OlBodyFormat.olFormatHTML;mailItem.HTMLBody=htmlBody;}privatevoidOnBeforeExport(objectsender,BeforeExportEventArgse){HtmlDocumentExporterOptionsoptions=e.OptionsasHtmlDocumentExporterOptions;if(options!=null){options.Encoding=Encoding.UTF8;}}#regionIUriProviderMemberspublicstringCreateCssUri(stringrootUri,stringstyleText,stringrelativeUri){returnString.Empty;}publicstringCreateImageUri(stringrootUri,OfficeImageimage,stringrelativeUri){stringimageName=String.Format("image{0}.png",imageId);imageId++;stringimagePath=Path.Combine(tempFiles,imageName);image.NativeImage.Save(imagePath,ImageFormat.Png);mailItem.Attachments.Add(imagePath,Outlook.OlAttachmentType.olByValue, 0,Type.Missing);return""+imageName;//using cid: breaks images in my webmail (squirrelmail)}#endregion}



Workbook - How to create a spreadsheet template in code and perform mail merge

$
0
0
This example demonstrates how to use the Spreadsheet Mail Merge functionality to automatically generate a document based on data retrieved from an object data source. 
The mail merge template is created in code when the application starts. The data source is specified using the Workbook.MailMergeDataSource property. The Workbook.GenerateMailMergeDocuments method accomplishes mail merge and returns the resulting workbook. Since the mail merge mode is set to Multiple Sheets, all worksheet created by the GenerateMailMergeDocuments method are contained in a single workbook.

DXRichEdit Getting Started - Lesson 2 - Provide Bars UI for a RichEditControl

Viewing all 7205 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>