Monthly Archives: October 2012

Entity Framework Code-First in a “semi-production” context

Lately I used Entity Framework Code First in a “semi-production” context, not in an application, but for managing Load Tests. The scenario was I had a Load Test, based on a unit test (not a web test) and I had to manage a pool of users so that a single user wasn’t used at the same time by 2 instances of the unit test. Because the Load Test ran in a multi-agent scenario, this had to be accessible by all the agents running the unit test, thus a Database approach.

Preparing the Database in SQL Server

Entity Framework Code First will create and manage the Database for you. But in this context, I will be accessing the Database through a connection string using a SQL user, because not all the machines running agents are in the same domain, so going through a trusted connection isn’t an option. The SQL user will have access to the Database for the Load Test, but won’t have access to the master Database.

The first thing you need to do is to create the Database, because using the EF connection string would result in an authorization error when creating the Database.

After creating the Database setup the SQL user so that it can connect to it, read, write and manage the schema.

The Entity Framework Model and Context

The very first thing you need to do is add the Entity Framework NuGet package to your solution, this can be done either by going through the NuGet package manager:

blog12

Or just by opening the package manager console and typing in Install-Package EntityFramework

blog13

After that, create your model and your context. For our scenario we just needed an object User that has a UserName key, a static password that’s not going to the Database, a boolean InUse and a DateTime timestamp ReleasedOn so that we can ask for users that have been released by the unit test for the longest time.

namespace EFCodeFirstStart.Model
{
    using System;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;

    public class User
    {
        [Key]
        public string UserName { get; set; }

        [NotMapped]
        public string Password { get { return "myStaticPassword"; } }

        public bool InUse { get; set; }

        public DateTime ReleasedOn { get; set; }
    }
}

The context is really simple (we’ll get back to it later on in the post). You need to inherit from DbContext and you are implementing the default constructor to call the DbContext constructor that takes a connection string name so that you can point to the Database previously created.

namespace EFCodeFirstStart.Model
{
    using System.Data.Entity;

    public class LoadTestDataContext : DbContext
    {
        public LoadTestDataContext() : base("name=EFConnectionString") { }

        public DbSet<User> Users { get; set; }
   }
}

Creating the Database from the Model – Code First approach

Make sure that the connection string that you’re using on the DbContext contructor is configured in the app.config or web.config of your application:

<connectionStrings>
  <add name="EFConnectionString" providerName="System.Data.SqlClient" connectionString="Server=localhost; Database=LoadTestData; User=efcodefirst; Password=mypwd1234" />
</connectionStrings>

The first step is enabling Code First migrations for your application, this must be done for every project type with the following command Enable-Migrations:

blog14

When this step is executed a new folder Migrations and a Configuration.cs file will be created. The Configuration.cs file is one of the points where control is given to the developer in the Code First approach.

namespace EFCodeFirstStart.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<EFCodeFirstStart.Model.LoadTestDataContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(EFCodeFirstStart.Model.LoadTestDataContext context)
        {
            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data. E.g.
            //
            //    context.People.AddOrUpdate(
            //      p => p.FullName,
            //      new Person { FullName = "Andrew Peters" },
            //      new Person { FullName = "Brice Lambson" },
            //      new Person { FullName = "Rowan Miller" }
            //    );
            //
        }
    }
}

You then need to add migrations every time we want to snapshot the Database schema, so let’s do one now and call it InitialSetup by running the command Add-Migration InitialSetup:

blog15

This will create another file on the Migrations folder with a timestamp followed by _InitialSetup (the name you gave to the Migration):

namespace EFCodeFirstStart.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class InitialSetup : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Users",
                c => new
                    {
                        UserName = c.String(nullable: false, maxLength: 128),
                        InUse = c.Boolean(nullable: false),
                        ReleasedOn = c.DateTime(nullable: false),
                    })
                .PrimaryKey(t => t.UserName);
            
        }
        
        public override void Down()
        {
            DropTable("dbo.Users");
        }
    }
}

In a normal application scenario we would be done, as Entity Framework will handle the Database updates on every run, extra commands are only needed if we need to revert or do other extra work on the migrations. However, because I had to run this from a LoadTest project, the Database update has to be done manually, by calling Update-Database on the package manager console

blog16

Where did the EDMX go?

If you’re like me, you do a lot of code generation based on the ADO.NET EDMX model. So far Code First looked really nice and I was liking it a lot, but without the EDMX I don’t have a good source for writing templates against.

The folks at the Entity Framework team created the ability to Save the EDMX file in the framework, so we just need to call that every time we are changing the model (calling Update-Database). This is done by overriding the OnModelCreating method:

namespace EFCodeFirstStart.Model
{
    using System.Data.Entity;
    using System.Data.Entity.Infrastructure;
    using System.Text;
    using System.Xml;

    public class LoadTestDataContext : DbContext
    {
        public LoadTestDataContext() : base("name=EFConnectionString") { }

        public DbSet<User> Users { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            var provider = new DbProviderInfo("System.Data.SqlClient", "2008");
            var model = modelBuilder.Build(provider);

            var writer = new XmlTextWriter(@"D:\TmpEdmx\my.edmx", Encoding.UTF8);
            EdmxWriter.WriteEdmx(model, writer);
        }
    }
}

Code First thoughts

So far I liked using Code First, seemed smooth, flexible and lean, making model and schema change iterations a breeze. With the added support to generate the EDMX everything is in place to do code generation like we used to do with Model First approaches.

Playing around with the Ribbon and RichTextBox–4 of 4: Adding Hyperlink support to the RichTextBox

For my work, one of the things I had to support was Hyperlinks. I could do this the traditional way, where I would create a button in the Ribbon

blog10

And follow it up with a MessageDialogBox asking the user additional Hyperlink details

blog11

However, because my hyperlinks will always list the URI and never a user typed name, detecting hyperlinks as the user types and creating them is a lot better then specifically forcing the user to press a button and fill in the details.

Adding Hyperlink detection to the RichTextBox

I found a very good article on MSDN about this, written by Prajakta Joshi that I modified to suit my needs. It all starts with detecting the preceding word in a FlowDocument Paragraph object

private static string GetPreceedingWordInParagraph(TextPointer position, out TextPointer wordStartPosition)
{
    wordStartPosition = null;
    var word = String.Empty;
    var paragraph = position.Paragraph;

    if (paragraph != null)
    {
        var navigator = position;
        while (navigator != null && navigator.CompareTo(paragraph.ContentStart) > 0)
        {
            var runText = navigator.GetTextInRun(LogicalDirection.Backward);

            if (runText.Contains(" "))
            {
                var index = runText.LastIndexOf(" ", StringComparison.Ordinal);
                word = runText.Substring(index + 1, runText.Length - index - 1) + word;
                wordStartPosition = navigator.GetPositionAtOffset(-1 * (runText.Length - index - 1));
                break;
            }

            wordStartPosition = navigator;
            word = runText + word;
            navigator = navigator.GetNextContextPosition(LogicalDirection.Backward);
        }
    }

    return word;
}

I then hooked an Event Handler on the KeyDown Event of the RichTextBox on the constructor of my UserControl

public RibbonRichTextBox()
{
    InitializeComponent();
    _richTextBox.KeyDown += RibbonRichTextBoxKeyDown;
}

With the following implementation

private static void RibbonRichTextBoxKeyDown(object sender, KeyEventArgs e)
{
    var rtb = (RichTextBox) sender;
    if (e.Key != Key.Space && e.Key != Key.Return) return;

    var caretPosition = rtb.Selection.Start;
    TextPointer wordStartPosition;

    var word = GetPreceedingWordInParagraph(caretPosition, out wordStartPosition);
    if (!Uri.IsWellFormedUriString(word, UriKind.Absolute)) return;

    if (wordStartPosition == null || caretPosition == null) return;

    var tpStart = wordStartPosition.GetPositionAtOffset(0, LogicalDirection.Backward);
    var tpEnd = caretPosition.GetPositionAtOffset(0, LogicalDirection.Forward);

    if(tpStart != null && tpEnd != null)
    {
        var link = new Hyperlink(tpStart, tpEnd)
                        {
                            NavigateUri = new Uri(word)
                        };

        link.MouseLeftButtonDown += FollowHyperlink;
    }
}

Notice that I’m using the Uri class to check if the word is an URI or not, this could be changed for a Regex or other forms of checking this out

if (!Uri.IsWellFormedUriString(word, UriKind.Absolute)) return;

Adding the ability to Ctrl+Click Hyperlinks and open them in IE

If you notice the RibbonRichTextBoxKeyDown imlpementation, there’s a line there, after creating the Hyperlink, where I add an event handler for the MouseLeftButtonDown Event

link.MouseLeftButtonDown += FollowHyperlink;

In the Handler implementation, I check for Ctrl (left or right) is down, then just start IE with the URI present on the Link and make sure the event’s Handled is set to true to stop the routing

private static void FollowHyperlink(object sender, MouseButtonEventArgs e)
{
    if (!Keyboard.IsKeyDown(Key.LeftCtrl) && !Keyboard.IsKeyDown(Key.RightCtrl)) return;

    var link = (Hyperlink) sender;
    Process.Start(new ProcessStartInfo(link.NavigateUri.ToString()));
    e.Handled = true;
}

The Full Series

The full solution can be downloaded from here.

This is the third article in the series Playing around with the Ribbon and RichTextBox.

Playing around with the Ribbon and RichTextBox–3 of 4: Creating an Insert Picture button in the Ribbon

For the work I was doing I had to design and create special buttons that extended the EditingCommands Class like special text formatting for special text blocks, an Insert Image command and an insert Video command. The special text formatting was very specific to my work and the Video command is a lot more tricky to implement and the implementation is bound to a transformation that is performed later where I convert the RichTextBox’s document XAML to XML.

So I choose to demonstrate the Insert Picture command.

blog9

The button is a normal RibbonButton that’s defined inside a RibbonControlGroup inside a RibbonGroup

<ribbon:RibbonGroup Header="Media" x:Name="_mediaHeader">
    <ribbon:RibbonControlGroup>
        <ribbon:RibbonButton x:Name="_btnImage" Label="Image" LargeImageSource="/PlayingWithRibbon;component/Images/picture.png" Click="ButtonImageClick">
            <ribbon:RibbonButton.ControlSizeDefinition>
                <ribbon:RibbonControlSizeDefinition ImageSize="Large" />
            </ribbon:RibbonButton.ControlSizeDefinition>
        </ribbon:RibbonButton>
    </ribbon:RibbonControlGroup>
</ribbon:RibbonGroup>

Once the button is clicked an OpenFileDialog is shown for the user to select the image, since in my work I can only support JPG and PNG file formats, these are the ones that are being filtered

private static Image SelectImage()
{
    var dlg = new OpenFileDialog
    {
        Filter = "Image Files|*.png;*.jpg;*.gif"
    };

    var result = dlg.ShowDialog();
    if (result.Value)
    {
        var bitmap = new BitmapImage(new Uri(dlg.FileName));
        return new Image
        {
            Source = bitmap,
            Height = bitmap.Height,
            Width = bitmap.Width
        };
    }

    return null;
}

The Click Event Handler implementation, that inserts the actual picture in the Document

private void ButtonImageClick(object sender, RoutedEventArgs e)
{
    var image = SelectImage();
    if (image == null) return;

    var tp = _richTextBox.CaretPosition.GetInsertionPosition(LogicalDirection.Forward);
    new InlineUIContainer(image, tp);
}

Extra work could be done to create text flow around the image or other fancy tricks that the System.Windows.Document namespace offers, but since my final output is XML, none of those were going to be supported anyways.

The Full Series

The full solution can be downloaded from here.

This is the third article in the series Playing around with the Ribbon and RichTextBox.

Playing around with the Ribbon and RichTextBox–2 of 4: Creating a good User Experience with Reveal

The Ribbon provides for an overall good User Experience, however it takes a big chunk of screen space. The Ribbon design doesn’t allow for it to be minimalist, and if it was it wouldn’t be the same Ribbon we are used to from all those Microsoft applications.

This is where Reveal from Bag of Tricks comes in handy. By placing the Ribbon inside a Reveal and controlling it’s appearance we can make good use of screen space in scenarios where the User’s screen is already filled with other things, or even more Ribbon’s!

The Reveal that I use in my solution has added features to it besides the one from BoT, as described in a previous post.

Binding the Reveal’s IsExpanded

What I found that worked best, in terms of User Experience, and after responding to some user feedback, was to hook the Reveal to the Focus handlers on the top Grid inside the UserControl. I hooked it to IsReadOnly on the RichTextBox and control that property directly on the Focus hooks.

First I declared the reveal around the Ribbon declaration

<PlayingWithRibbon:Reveal VerticalReveal="FromTopToBottom"
                    HorizontalReveal="None"
                    Duration="200"
                    IsExpanded="{Binding ElementName=_richTextBox, Path=IsReadOnly, Converter={StaticResource ResourceKey=InverseBooleanConverter}}"
                    Stretch="HorizontalAndVertical"
                    Grid.Row="0"
                    >

    <ribbon:Ribbon Name="_ribbon">

    (...)

    </ribbon:Ribbon>
</PlayingWithRibbon:Reveal>

Because I want the Reveal.IsExpanded to be true when RichTextBox.IsReadOnly is false, I had to put in a simple InverseBooleanConverter that’s declared on the code behind of the RibbonRichTextBox.

/// <summary>
/// Inverse Boolean Converter - Inverts the value of a boolean bind.
/// </summary>
[ValueConversion(typeof(bool), typeof(bool))]
public class InverseBooleanConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        return !(bool)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(bool))
            throw new InvalidOperationException("The target must be a boolean");

        return !(bool)value;
    }
}
<UserControl.Resources>
    <PlayingWithRibbon:InverseBooleanConverter x:Key="InverseBooleanConverter" />
</UserControl.Resources>

Then I went and setup the event handlers for the GotFocus and LostFocus on the top Grid of the UserControl

<Grid GotFocus="GridGotFocus" LostFocus="GridLostFocus">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition />
    </Grid.RowDefinitions>

    (...)

</Grid>

With a very simple implementation on the code behind file

private void GridGotFocus(object sender, RoutedEventArgs e)
{
    _richTextBox.IsReadOnly = false;
}

private void GridLostFocus(object sender, RoutedEventArgs e)
{
    _richTextBox.IsReadOnly = true;
}

In the end what you get is the Reveal to show the Ribbon on Focus and closing it when losing Focus. This makes a very smooth and cool effect while keeping the screen space to a minimum.

blog7

The Full Series

The full solution can be downloaded from here.

This is the second article in the series Playing around with the Ribbon and RichTextBox.

Playing around with the Ribbon and RichTextBox–1 of 4: Putting it all together, the Ribbon and the RichTextBox

The Ribbon for WPF is a very cool control, with a lot of customization options. In terms of User Experience it’s something everyone is used to these days from all the Microsoft Tools that have been using it, including Office since 2007 and all the way up to 2013.

To show off the Ribbon, I present a use of it with just a few commands, most of them are out-of-the box from the RichTextBox and one of them (Insert Picture) is custom.

The application itself is very simple, it’s a set of 2 controls (RichTextBox + Ribbon: RibbonRichTextBox) one on top of the other. I chose to place two of them, so that the focus changing hiding and showing of the Ribbon could be easily demonstrated.

blog7

The solution has a very flat structure, the main functionality is inside the RibbonRichTextBox UserControl. The MainWindow is very simple and just hosts the two RibbonRichTextBoxes:

<Window x:Class="PlayingWithRibbon.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:PlayingWithRibbon="clr-namespace:PlayingWithRibbon"
        Title="MainWindow" Height="620" Width="600">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>

        <PlayingWithRibbon:RibbonRichTextBox Grid.Row="0" Margin="10" />
        <PlayingWithRibbon:RibbonRichTextBox Grid.Row="1" Margin="10" />
    </Grid>

</Window>

blog8

Besides the Reveal, which I will talk about later in the series, there’s the Images Folder, with all the images required by the several controls inside the Ribbon.

The Ribbon

Using the Ribbon in .Net 4.0 or 4.5 just requires a reference to the assembly RibbonControlsLibrary.dll. In a very simplified description (it can do a lot more): The Ribbon control can host RibbonTab’s that can host RibbonControlGroups that can host all sorts of RibbonControls. The various controls in the Ribbon are mostly bound to the RichTextBox EditingCommands part of the System.Windows.Documents namespace.

<ribbon:Ribbon Name="_ribbon">
    <ribbon:RibbonTab Header="Home">
        <ribbon:RibbonGroup Header="Edit">
            <ribbon:RibbonButton x:Name="_btnPaste" Label="Paste" LargeImageSource="/PlayingWithRibbon;component/Images/Paste32.png"
                            Command="{x:Static ApplicationCommands.Paste}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Large" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnCut" Label="Cut" SmallImageSource="/PlayingWithRibbon;component/Images/Cut16.png"
                            Command="{x:Static ApplicationCommands.Cut}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnCopy" Label="Copy" SmallImageSource="/PlayingWithRibbon;component/Images/Copy16.png"
                            Command="{x:Static ApplicationCommands.Copy}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnClear" Label="Clear" SmallImageSource="/PlayingWithRibbon;component/Images/Delete16.png"
                            Command="{x:Static EditingCommands.Delete}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnUndo" Label="Undo" SmallImageSource="/PlayingWithRibbon;component/Images/Undo16.png"
                            Command="{x:Static ApplicationCommands.Undo}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_bntRedo" Label="Redo" SmallImageSource="/PlayingWithRibbon;component/Images/Redo16.png"
                            Command="{x:Static ApplicationCommands.Redo}" CommandTarget="{Binding ElementName=_richTextBox}">
                <ribbon:RibbonButton.ControlSizeDefinition>
                    <ribbon:RibbonControlSizeDefinition ImageSize="Small" />
                </ribbon:RibbonButton.ControlSizeDefinition>
            </ribbon:RibbonButton>
            <ribbon:RibbonButton x:Name="_btnSelectAll" Label="Select All"
                            Command="{x:Static ApplicationCommands.SelectAll}" CommandTarget="{Binding ElementName=_richTextBox}"/>
        </ribbon:RibbonGroup>
        <ribbon:RibbonGroup Header="Font">
            <ribbon:RibbonControlGroup>
                <ribbon:RibbonToggleButton x:Name="_btnBold" 
                                    SmallImageSource="/PlayingWithRibbon;component/Images/Bold16.png" 
                                    Command="{x:Static EditingCommands.ToggleBold}" CommandTarget="{Binding ElementName=_richTextBox}">
                    <ribbon:RibbonToggleButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonToggleButton.ControlSizeDefinition>
                </ribbon:RibbonToggleButton>
                <ribbon:RibbonToggleButton x:Name="_btnItalic" SmallImageSource="/PlayingWithRibbon;component/Images/Italic16.png"                                               
                                    Command="{x:Static EditingCommands.ToggleItalic}" CommandTarget="{Binding ElementName=_richTextBox}">
                    <ribbon:RibbonToggleButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonToggleButton.ControlSizeDefinition>
                </ribbon:RibbonToggleButton>
                <ribbon:RibbonToggleButton x:Name="_btnUnderline" SmallImageSource="/PlayingWithRibbon;component/Images/Underline16.png"
                                    Command="{x:Static EditingCommands.ToggleUnderline}" CommandTarget="{Binding ElementName=_richTextBox}">
                    <ribbon:RibbonToggleButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonToggleButton.ControlSizeDefinition>
                </ribbon:RibbonToggleButton>
            </ribbon:RibbonControlGroup>
        </ribbon:RibbonGroup>
        <ribbon:RibbonGroup Header="Paragraph">
            <ribbon:RibbonControlGroup>
                <ribbon:RibbonRadioButton x:Name="_btnBullets" Label="" SmallImageSource="/PlayingWithRibbon;component/Images/Bullets16.png"
                                    Command="{x:Static EditingCommands.ToggleBullets}" CommandTarget="{Binding ElementName=_richTextBox}">
d                                <ribbon:RibbonRadioButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Small" IsLabelVisible="False" />
                    </ribbon:RibbonRadioButton.ControlSizeDefinition>
                </ribbon:RibbonRadioButton>
            </ribbon:RibbonControlGroup>
        </ribbon:RibbonGroup>
        <ribbon:RibbonGroup Header="Media" x:Name="_mediaHeader">
            <ribbon:RibbonControlGroup>
                <ribbon:RibbonButton x:Name="_btnImage" Label="Image" LargeImageSource="/PlayingWithRibbon;component/Images/picture.png" Click="ButtonImageClick">
                    <ribbon:RibbonButton.ControlSizeDefinition>
                        <ribbon:RibbonControlSizeDefinition ImageSize="Large" />
                    </ribbon:RibbonButton.ControlSizeDefinition>
                </ribbon:RibbonButton>
            </ribbon:RibbonControlGroup>
        </ribbon:RibbonGroup>
    </ribbon:RibbonTab>
</ribbon:Ribbon>

The RichTextBox

Connected with the Ribbon is a RichTextBox control. The control is simple, just has a Resource to force the Paragraph Margin to be 0 and is hooking the event SelectionChanged so that we can properly update the Ribbon’s ToggleButtons whenever we change the selection on the RichTextBox.

<RichTextBox x:Name="_richTextBox"
                Grid.Row="1"
                Height="200"
                BorderBrush="#3D5261"
                BorderThickness="2"
                IsReadOnly="True"
                SelectionChanged="RichTextBoxSelectionChanged">
    <RichTextBox.Resources>
        <Style TargetType="{x:Type Paragraph}">
            <Setter Property="Margin" Value="0"/>
        </Style>
    </RichTextBox.Resources>
</RichTextBox>

Updating ToggleButton state with SelectionChanged

Making sure that the ToggleButton’s in the Ribbon have their state updated with the current selection starts with the SelectionChanged Event Handler.

private void RichTextBoxSelectionChanged(object sender, RoutedEventArgs e)
{
    UpdateVisualState();
}

private void UpdateVisualState()
{
    UpdateToggleButtonState();
    UpdateSelectionListType();
}

This is then divided into two groups, the ToggleButton CheckedState and the ListType selection. For the ItemCheckedState we handle it like this:

private void UpdateToggleButtonState()
{
    UpdateItemCheckedState(_btnBold, TextElement.FontWeightProperty, FontWeights.Bold);
    UpdateItemCheckedState(_btnItalic, TextElement.FontStyleProperty, FontStyles.Italic);
    UpdateItemCheckedState(_btnUnderline, Inline.TextDecorationsProperty, TextDecorations.Underline);
}

private void UpdateItemCheckedState(ToggleButton button, DependencyProperty formattingProperty, object expectedValue)
{
    var currentValue = _richTextBox.Selection.GetPropertyValue(formattingProperty);
    button.IsChecked = (currentValue != DependencyProperty.UnsetValue) && (currentValue != null && currentValue.Equals(expectedValue));
}

While the ListType is handled like this:

private void UpdateSelectionListType()
{
    var startParagraph = _richTextBox.Selection.Start.Paragraph;
    var endParagraph = _richTextBox.Selection.End.Paragraph;

    if (startParagraph != null &&
        endParagraph != null &&
        (startParagraph.Parent is ListItem)
        && (endParagraph.Parent is ListItem) &&
        ReferenceEquals(((ListItem)startParagraph.Parent).List, ((ListItem)endParagraph.Parent).List))
    {
        var targetList = (startParagraph.Parent as ListItem).List;
        if (targetList == null) return;

        var markerStyle = targetList.MarkerStyle;

        switch (markerStyle)
        {
            case TextMarkerStyle.Disc:
                _btnBullets.IsChecked = true;
                break;
        }
    }
    else
    {
        _btnBullets.IsChecked = false;
    }
}

The Full Series

The full solution can be downloaded from here.

This is the first article in the series Playing around with the Ribbon and RichTextBox.