Blogs

Rachel Reese - DevExpress Scheduler & RichEdit Blog

  • WinForms RichEdit: Updating the Font

    I've had a couple questions lately on how to update paragraph styles after a document has been loaded, or when using our Document Server.

    I've discussed before how to update the default font for an empty document, but what if you just want to change the font on a pre-loaded document? Just as easy. If we have the following document:

    Original Font, before updating

    Then, to update the title and author, we first need to define the range of characters that contains this information:

    Document doc = richEditControl1.Document;
    DocumentRange range = doc.Paragraphs[1].Range;

    And then, update the range using the BeginUpdateCharacters and EndUpdateCharacters methods:

    CharacterProperties cp = doc.BeginUpdateCharacters(range);
    cp.FontName = "French Script MT";
    cp.FontSize = 24;
    cp.ForeColor = Color.DarkOliveGreen;
    cp.BackColor = Color.BlanchedAlmond;
    cp.Underline = UnderlineType.ThickLongDashed;
    cp.UnderlineColor = Color.DarkViolet;
    doc.EndUpdateCharacters(cp);

    When we run the project, we see the following: 

    With a new font, after updating

    Hope that helps!

  • Upcoming Webinar: ASP.NET Scheduler 101!

    Register and attend my ASP.NET Scheduler 101 webinar that'll teach you how to work with the DevExpress ASP.NET Scheduler.

    I'll cover how to:

    • Data bind the control;
    • Change the theme;
    • Customize themes;
    • Display multiple time zones; and
    • Set the default working hours.
    Register Now

    Click the register button below and attend the webinar on Monday, August 29th, 2011 at 10AM PST:

    Monday, August 29th, 2011 10:00am PDT | 1:00pm EDT | 5:00pm GMT
    Presenters

    antiqued
    Rachel Reese
    Technical Evangelist – Scheduler & RichEdit Team

    Amanda Christensen
    Amanda Christensen
    Host

    Register Soon

    What are you waiting for? Go register, now.

  • Rich Text Editor - Table of Contents (available now in v2011, volume 1)

    You can now automatically add, update, and manage a table of contents from within the RichEdit Control.  You can also import a document from Microsoft Word with a table of contents, and manage it in RichEdit. You can also generate a Table of Figures, or a Table of Equations. This feature is available for all our RichEdit products: WinForms, WPF, Silverlight, and ASP.NET.

    Why would I add a Table of Contents?

    Why would you want a Table of Contents? Tables of Contents help your readers quickly understand the content of your document; quickly navigate your document; and more effectively use your document and its content.

    How do I add a Table of Contents?

    There are several ways to do this. First, decide whether you would like the table of contents to be built from the heading styles in the document, or from the fields in the document structure. Then, ensure the headings or fields are in place, and finally, generate the table of contents.

    Using Headings

    First, you must ensure that all content that you want to appear in the table of contents. There are two ways to do this in the RichEdit control, either by using the references tab, or by using the paragraph dialog box from the Ribbon Control. The main difference in the two is that the levels on the references tab will add a new style to your entry, whereas the paragraph style will leave your text unchanged.

    Using the References tab:

    Click the text that you want to appear in the table of contents. On the References tab, in the Table of Contents group, click Add Text, and then select the desired outline level.

    image 

    Using the Paragraph dialog box:

    Click the text that you want to appear in the table of contents. Invoke the Paragraph dialog box via the context menu or by clicking the Paragraph Dialog Box Launcher on the Home tab. Then use the Outline level combo box to specify the outline level of the text.

    image 

    Once the information has been labeled, you are ready to create the table of contents.

    Using Fields

    If you choose to build your table of contents from the information defined in your SubDocument.Fields property, you will have to ensure that your fields are properly defined. On the Mailings tab, click Show All Field Codes, and you'll see something like the following. Note the {TC "Summary" \f bvz \1 1 } just below the Abstract heading. This adds a field to the Table of Contents at this location in the document which is titled "Summary" with an f switch, and a bvz identifier. BVZ can be anything at all – in this case BVZ are the initials of my coworker, who originally created the document. If you are creating more than one table of contents, all the fields marked with bvz will form one table of contents, just like in Microsoft Word. For more information on fields, see (the Table of Contents article), and the list of field codes.

    image

    Using field codes also gives you the ability to declare your figures and equations, for example, and to create a table of figures or table of equations, in addition to your table of contents. The following new switches are available to use with Table of Contents fields:

    \b Includes entries only from the portion of the document marked by the bookmark named by text in this switch's field-argument.
    \h Inserts table of contents entries as hyperlinks.
    \n "LEVELSTART-LEVELEND" Omits page numbers from the table of contents. Page numbers are omitted from all levels unless a range of entry levels is specified. For example, { TOC \n 1-1 } omits page numbers from level 1.
    \u Uses the applied paragraph outline level, rather than heading style.
    \o "LEVELSTART-LEVELEND" Builds a table of contents from paragraphs with specified outline levels. For example, { TOC \o "1-3" } lists only paragraphs with outline levels 1 through 3.
    \t STYLE,LEVEL, STYLE,LEVEL,..." Builds a table of contents from paragraphs formatted with specified styles. For example, {TOC \t"Title,1,subtitle,2,customtitle,3"} builds a table of contents from paragraphs formatted with the styles "Title", "subtitle" and "customtitle". The number after each style name indicates the entry level corresponding to that style.
    \c "SEQ FIELD IDENTIFIER" Builds a table of contents from items that are numbered by a SEQ field. The sequence identifier designated by text in this switch's field-argument shall match the identifier in the corresponding SEQ field.
    \s "SEQ FIELD IDENTIFIER" For entries numbered with a SEQ field, adds a prefix to the page number. The prefix depends on the type of entry.
    \d "SEPARATOR SYMBOL" When used with \s, defines the separator between sequence and page numbers. The default separator is a hyphen (-).
    \f "TC IDENTIFIER" Builds a table of contents from TC fields. TC field identifier must exactly match the text in this switch's field-argument.
    \l "LEVELSTART-LEVELEND"Used with \f key. Includes TC fields that assign entries to one of the specified levels.

     

    image

    Creating the Table of Contents

    Once you've labeled all your text, it's time to add your table of contents! Click where you want to insert the table of contents. Then, on the References tab, in the Table of Contents group, click Table of Contents.

    image

    And you're done! Your table of contents will appear.

    image

    If you have modified the entries in your document, and you need to update the table of contents, it is simple. On the References tab, in the Table of Contents group, click Update Table.

    image

     

    How do I add a Table of Contents at runtime?

    We've added the following commands in this release:

    DevExpress.XtraRichEdit.Commands.InsertTableOfContentsCommand 
    DevExpress.XtraRichEdit.Commands.UpdateTableOfContentsCommand 
    DevExpress.XtraRichEdit.Commands.InsertTableOfEquationsCommand 
    DevExpress.XtraRichEdit.Commands.InsertTableOfFiguresCommand 
    DevExpress.XtraRichEdit.Commands.InsertTableOfTablesCommand 
    DevExpress.XtraRichEdit.Commands.InsertFieldCommand 
    DevExpress.XtraRichEdit.Commands.UpdateFieldsCommand 

    For example, if you want to create a table of contents as part of a button's Click event, simply add the following :

    DevExpress.XtraRichEdit.Commands.InsertTableOfContentsCommand insertTOC = 
    	new DevExpress.XtraRichEdit.Commands.InsertTableOfContentsCommand(richEditControl1);
    insertTOC.Execute();

    Adding Table of Contents fields at runtime is the same as adding any other document field. For example, the following will insert a {TOC \h} field at the start of the second paragraph.  

    DevExpress.XtraRichEdit.API.Native.Field _field =
    	RichEditControl.Document.Fields.Add(RichEditControl.Document.Paragraphs[1].Range.Start,
    	"TOC \\h");

    Like so:

    image

    For more information, check out our documentation:

    http://documentation.devexpress.com/#WindowsForms/CustomDocument9561
    http://documentation.devexpress.com/#WPF/CustomDocument9562
    http://documentation.devexpress.com/#Silverlight/CustomDocument5661

    And my recent webinar:

    http://www.devexpress.com/Support/Webinars/details.xml?id=XtraRichEditTableContents

  • WinForms RichEdit Table of Contents In-Depth Upcoming Webinar!

    Register and attend my XtraRichEdit: Table of Contents In-Depth webinar that'll teach you how to work with the DevExpress XtraRichEdit Table of Contents.

    I'll cover:

    • How to set up and modify Table of Contents Entries, and the Table of Contents itself from a user perspective and at runtime
    • Fields and Switches
    • Tables of Figures, Equations, and Tables.

    Register Now

    Click the register button below and attend the webinar on Wednesday, August 24th, 2011 at 10AM PST:

    Friday August 24th, 2011 10:00am PDT | 1:00pm EDT | 5:00pm GMT

    • Title: XtraRichEdit: Table of Contents In-Depth 
    • Date: Friday, August 24th, 2011
    • Time: 10am PDT (GMT -07:00)
    • Length: 1 hour (ish)
    • Presenters: Rachel Reese 
    • Register here - https://www3.gotomeeting.com/register/685619982
    • Description:  
    • Level:  200

    Presenters

     antiqued
    Rachel Reese
    Technical Evangelist – Scheduler & RichEdit Team

    Amanda Christensen
    Amanda Christensen
    Host

    Register Soon

    What are you waiting for? Go register, now.

  • Rich Text Editor: Changing the Default Font

    I was chatting with a customer this afternoon who was having trouble setting the default font on his XtraRichEdit. Sure, changing it at runtime using the Font drop down on the Ribbon bar works completely fabulously ;) but he wanted his users to start just typing away in Century Gothic.

    Easy peasy, says I: we have a property for that.

    image

    This is also accomplishable via code:

    richEditControl1.Document.DefaultCharacterProperties.FontSize = 12;
    richEditControl1.Document.DefaultCharacterProperties.FontName = "Century Gothic";

    For more information, check out the documentation.

    Hope this helps!

  • ASP.NET Scheduler: Getting Started - Binding to a Data Source

    Since I'm just as new to our Scheduler control as some of you, I thought I'd start with a series of posts showing you just how easy it is to do some of the basics! I've gotten several questions already on how to bind the data to the ASP.NET Scheduler control, so we'll start here! :)

    First, if you need to create your database to work with our Scheduler, you will need the scripts from this article.

    We'll begin with a brand new ASP.NET application, and just drag the ASPxScheduler from the toolbox:

    image

    into the MainContent section, then click the arrow on the upper right corner of the ASP.NET Scheduler:

    image

    and you'll see the ASPxScheduler Tasks menu. We'll need to set the data source for both appointments and resources (what it is what we're scheduling: people, rooms, equipment, etc.). So, click the data source menu, and choose "<New Data Source>."

    image

    This will pop up the Data Source Configuration Wizard:

    image

    I'm going to use a SQL Server Compact file, so I click SQL Server, enter a name for the data source, and click OK. Next, I need to create the connection string. So, I click New Connection:

    image

    Then, enter the path to the file, and click OK:

    image

    Save the connection string to the application, and click Next:

    imageSpecify the columns that you will need for your appointments, then click Advanced:

    image

    and check "Generate INSERT, UPDATE, and DELETE statements," then click OK.

    image

    And click Next, and then Finish. Next, the Mappings Wizard will pop up, and let you verify that the columns that the Scheduler requires are mapped to the columns in your database properly. Required fields are ID, Start, and End. Verify these, and click Next:

    image

    Now, you can set the Custom Fields. Choose the additional fields you'd like to include, move them to the right column and, finally, click Finish:

    image

    Once that is done, reopen the Tasks menu on the ASPxScheduler, and repeat for the resource data source. If you need to modify the data source at any time, there is an available Tasks menu with a "Configure Data Source…" option which will bring back up the Data Source Configuration Wizard:

    image

    One final step to be able to post data back into the database. We need to determine (using SELECT @@IDENTITY), and then assign, the correctly calculated ID value in the INSERT statement. To do this, highlight the data source, then click the InsertQuery property:

    image

    to invoke the Command and Parameter Editor:

    image

    Now, remove the ID parameter from the INSERT statement text and the parameter list. To generate the correct ID, we'll need to handle a couple events, like so:

    int lastInsertedAppointmentId;
    
    protected void ASPxScheduler1_AppointmentRowInserting(object sender,
    ASPxSchedulerDataInsertingEventArgs e)
    {
        // Remove unnecessary ID field. 
        e.NewValues.Remove("ID");
    }
    
    protected void appointmentDataSource_Inserted(object sender,
    SqlDataSourceStatusEventArgs e)
    {
        // Obtain the identity value. 
        SqlConnection connection = (SqlConnection)e.Command.Connection;
        using (SqlCommand cmd = new SqlCommand("SELECT @@IDENTITY", connection))
        {
            lastInsertedAppointmentId = (int)cmd.ExecuteScalar();
        }
    }
    
    protected void ASPxScheduler1_AppointmentRowInserted(object sender,
    ASPxSchedulerDataInsertedEventArgs e)
    {
        // Specify new ID field value. 
        e.KeyFieldValue = lastInsertedAppointmentId;
    }
    
    protected void ASPxScheduler1_OnAppointmentsInserted(object sender,
    PersistentObjectsEventArgs e)
    {
        // Store the new appointment. 
        int count = e.Objects.Count;
        System.Diagnostics.Debug.Assert(count == 1);
        Appointment apt = (Appointment)e.Objects[0];
        ASPxSchedulerStorage storage = (ASPxSchedulerStorage)sender;
        storage.SetAppointmentId(apt, lastInsertedAppointmentId);
    }

    For more information, see Step 13-14 in How to: Bind an ASPxScheduler to Data at Design Time.

    And when we run the project, we're good to go! 

    image

    Hope this helps!

    For other data sources and additional examples:

    How to bind ASPxScheduler to SQL Server database
    How to bind ASPxScheduler to ObjectDataSource
    How to bind ASPxScheduler to SyBase ASE 15 database
    How to bind ASPxScheduler to LINQ Data Source
    How to bind ASPxScheduler with multi-resource appointments to SQL Server database
    How to bind ASPxScheduler to XPO via the Unit of Work

    For additional documentation:

    http://documentation.devexpress.com/#AspNet/CustomDocument3685
    http://documentation.devexpress.com/#AspNet/CustomDocument3844

  • WinForms Rich Editor: New Feature Videos!

    We've been busy here at DevExpress – cracking out new videos on all our new version 2011, volume 1 features!

    image

    Table of Contents videoblog
    The WinForms Rich Text Editor now supports Table of Contents features. You may load a document from Word with a pre-existing Table of Contents, or we've enabled you to set up your own table of contents using new field types.

    Document Server videoblog
    Our XtraRichEdit Suite exposes a server-side non-visual equivalent of our text editor, which can be used to automate common tasks. It's possible to convert files, as well as load, save, and modify documents. It’s also possible to add tables; update sections; reformat the text or the paragraphs; add/change permissions or protection on the document; or even perform a mail-merge.

    Support for Microsoft Word 1997-2003 .doc Format videoblog
    We now support .doc format files. It's possible to load, save, convert to and from DOC format.

    image

    Progress Bar and Mail Merge Events videomerge events blog, progress bar blog
    We've added new mail merge events and a progress service, to enable you to include a progress bar in your project. 

    New Page Setup Dialog videoblog
    XtraRichEdit now offers a page setup dialog. It's now even easier to configure margins, orientation, columns, and paper size for your document, or a section of your document.

    Paste Special videoblog
    Now added to our clipboard menu! Now you are able to paste unformatted text right from the clipboard! It's also possible to paste in RTF and HTML.

  • WinForms XtraRichEdit – A History of Undo and Redo

    I've been learning a little about the history of the XtraRichEdit control this week, and I wanted to share a development story with you all. :-)

    Undo and redo are such simple and familiar features in any text and graphics editor that you'd think they'd be easy to implement. We thought so, too, when we first set out to develop the feature for our XtraRichEdit control. So, what's the approach we took?

    Well, first, it's obvious that there needs to be an object that holds a history of the changes. It should contain a list of the actions, with enough information to undo or redo each action. Since actions can be very different (inserting text, changing fonts) we decided right away that our object should not only hold all the data necessary to undo and redo, but actually be responsible for implementing them:

    public abstract class HistoryItem {
        public abstract void Undo (Document document);
        public abstract void Redo (Document document);
    }

    Our first basic prototype of the code looked like this:

    public class History {
        ReadOnly <HistoryItem> List items = new List <HistoryItem> ();
    
        public History (Document document) {
            this.document = document;}
    
        public void Undo() {}
        public void Redo() {}
        public void Add(HistoryItem item) {items.Add (item);}
    }

    Diving in first to the Undo method:

    public void Undo () {
    	items[items.Count - 1 ].Undo(document);
    }

    Looks good, right? Succinct and elegant… and wrong. For starters, when you call the Undo method for an empty list, we get an exception. So we fix that:

    public bool CanUndo { get { return items.Count > 0 ;}}
    public void Undo() {
    	if (!CanUndo) return ; 
    	items[items.Count - 1 ].Undo(document);
    }

    Now, the issue is that if we call the Undo method several times in a row, it'll repeatedly try to Undo the last item in the list. So we remove the most recent item, and we're good to go:

    public void Undo () {
    	if (!CanUndo) return ;
    	items[items.Count - 1 ].Undo(document);
    	items.RemoveAt(items.Count - 1 );
    }

    So, let's consider Redo:

    public void Redo () {
        if (!CanRedo) return ;
        // ???
    }

    Oops! Our implementation of Undo means that we've lost the change we now need to redo. Instead, we need an index indicating the current item in the clipboard. So, we rewrite again:

    int currentIndex = -1 ;
    public bool CanUndo { get { return currentIndex> = 0 ;}}
    public bool CanRedo { get { return items.Count> 0 && currentIndex < items.Count - 1 ;}}
    
    public void Undo() {
        if (!CanUndo) return; 
        items[currentIndex].Undo(document);
        this.currentIndex--;
    }
    
    public void Redo() {
        if (!CanRedo) return ;
        this.currentIndex++; 
        items[currentIndex].Redo(document); 
    }
    
    public void Add (HistoryItem item) {items.Add (item);
        this.currentIndex++;}

    That's much better. Note that now, for an Undo, the index changes *after* the rollback; and for a Redo, it changes *before* the roll forward. We also correctly increment the index when we add an item in the history.

    Now, let's take a closer look at the Add method. What if we perform 5 actions, roll back 3 of them, and then perform a new action? Looking around, we determine that the Undo/Redo standard here is to drop everything that has happened after the current index, and to instead begin a new history.

    Public void Add (HistoryItem item) {
        CutOffHistory(); 
        items.Add(item);
        this.currentIndex++;
    }
    
    void CutOffHistory() {
        int index = currentIndex + 1 ;
        if (index < Count) 
            items.RemoveRange(index, Count - index);
    }

    Now, we have our Undo/Redo implementation. The original intention was:

    1. Perform an action;
    2. Record said action into the history, so that we're able to undo/redo later;

    However, we decided we wanted our undo history not only to store what was undone, but actually to be able to redo the operation independently. In other words:

    1. Create an undo element, and add it to the history for potential undoing and redoing later;
    2. Perform redo for the history item, like so:
    	void DoAction() {
    	    HistoryItem item = CreateActionHistoryItem();
    	    document.History.Add(item);
    	    item.Redo(document);
    	}

    This works fabulously. We can redo an action from the current state, or undo an action from the current state, and it is possible to step through the history in either direction to affect the current state. By "state". I mean that the information recorded in the history is correct when it's saved, but it may change a moment later. For example, if we have "Hello World!":

    undo1

    Now, let's insert DevExpress in the middle; which means we record "insert DevExpress at position 6" into the history:

    undo2

    Next, we'll insert "We say:" at the beginning:

    undo3

    But, now our previous information about inserting DevExpress is incorrect. If we call undo at this point in the history, we'd invalidate the document. We have to recalculate the index to get the correct undo information. However, it's not necessary to recalculate. We can avoid it, by assuming that cancelling every operation before the relevant one leads the document to the state that it had at the beginning of the operation. We'd make the same assumption for redo, also. The information in the undo history will automatically become correct when the document arrives at the initial state (where the information was saved). As the redo operation occurs in the reverse order, we cannot use the information before the document is presented in the necessary state. Thus, we automatically handle the undo and redo correctly.

    These were just our initial observations here at DevExpress. In the real world, things might be a little different. ;)

    As a side note: While writing this, I wondered who first implemented undo and redo (and when). Apparently, it was between 1971 and 1976. Modern manuals of ed argue that it supports undo; the first manuals for UNIX (1971) do not include undo; but vi (first published 1976) contains it from the start. The term itself was first mentioned in 1976: "It would be quite useful, to permit users to ‘take back’ at least the immediately preceding command (by issuing some special ‘undo’ command).” (Lance A. Miller and John C. Thomas of I.B.M., “Behavioral Issues in the Use of Interactive Systems.”) See related article in the NY Times.

  • MADExpo

    Take a look at some pictures from my recent trip down to MADExpo in Hampton, VA last week:

    Me at the DevEx booth, chatting to Kendall Miller

    Sitting with (half of) Kendall Miller, chatting about DX.

     

    Rachel Appel, Chris Love, Rachel Reese

    Rachel Appel, Chris Love, and me. If only Rachel Hawley could have been there, we'd have had a trio of Rachii! ;)

     

    Duthie controls a robot with his mind

    And, G. Andrew Duthie taking time away from the HTML 5 Camp to power robots with his brain.

     

    This was the first year for this conference, and was a great start! In addition to the several (really great) session tracks, they had an HTML5 Camp alongside, a hardware hackerspace (with robots!! Check out: http://www.youtube.com/watch?v=UV-J_hy9XDA) and a separate room for kids to play with coding, robotics, electronics. DevExpress was there both days, and it was great to chat to everyone who came over to say hi, or show their support for us. All-in-all, it was a great time. Hope to see you all there next year!

  • WinForms Rich Text Editor – New Page Setup Dialog! (available now in v2011, volume 1)

    We've introduced a whole new page setup dialog for you in 2011, volume 1! To get there, click the button on the bottom of the Page Setup section:

    image

    which will give you:

    image

    image

    and

    image

    You can configure a huge list of things! Margins, orientation, paper size, which can be configured for the whole document, or by section, as well as options for sections, headers, and footers of your document.

    There's also a new columns dialog, reachable by clicking the "more columns" option under "Columns" in the Page Setup section:

    image

    Again, columns can be configured by section, or for the whole document.

    We also now support line-numbering documents from the UI! Simply choose from the line numbers drop down, and voila!

    image

    All of these features are still available at run time, too, from the DevExpress.XtraRichEdit.API.Native namespace. For example, to set up three columns (like our example): 

    // Specify a measurement unit
    richEditControl1.Document.Unit = DocumentUnit.Inch;
    // Get the first section in a document
    Section sectionDoc = richEditControl1.Document.Sections[0];
    // Create columns and apply them to the document
    SectionColumnCollection sectionColumnsLayout = 
        sectionDoc.Columns.CreateUniformColumns(sectionDoc.Page, 0.2f, 3);
    sectionDoc.Columns.SetColumns(sectionColumnsLayout);

    Check out the full list of supported properties:

    Page Setup:
    ShowPageSetupFormCommand
    Section.Margins
    SectionMargins
    Section.Page
    SectionPage
    SectionPage.Landscape
    SectionPage.PaperKind
    SectionPage.Width
    SectionPage.Height
    Section.StartType
    Document.DifferentOddAndEvenPages
    Section.DifferentFirstPage

    Columns Setup:
    ShowColumnsSetupFormCommand
    Section.Columns
    SectionColumns
    SectionColumn

    Line Numbering:
    ShowLineNumberingFormCommand
    Section.LineNumbering
    SectionLineNumbering
    SectionLineNumbering.Start
    SectionLineNumbering.CountBy
    SectionLineNumbering.Distance
    SectionLineNumbering.RestartType

    For more information, see the following samples:
    How to: Configure the Page Layout Programmatically
    How to: Create a Three-Column Layout with Uniform Columns
    Demo Module: Line Numbering

Next page »
LIVE CHAT

Chat is one of the many ways you can contact members of the DevExpress Team.
We are available Monday-Friday between 7:30am and 4:30pm Pacific Time.

If you need additional product information, write to us at info@devexpress.com or call us at +1 (818) 844-3383

FOLLOW US

DevExpress engineers feature-complete Presentation Controls, IDE Productivity Tools, Business Application Frameworks, and Reporting Systems for Visual Studio, along with high-performance HTML JS Mobile Frameworks for developers targeting iOS, Android and Windows Phone. Whether using WPF, Silverlight, ASP.NET, WinForms, HTML5 or Windows 8, DevExpress tools help you build and deliver your best in the shortest time possible.

Your Privacy - Legal Statements

Copyright © 1998-2013 Developer Express Inc.
ALL RIGHTS RESERVED
All trademarks or registered trademarks
are property of their respective owners