0

I have a WPF app. In this app, I have a ComboBox. The ComboBox display a list of algabra formulas. I want my students to be able to choose a formula. The formulas include superscripts. For that reason, I think I need to use a TextBlock like this:

<TextBlock>
    <Run>x</Run>
    <Run Typography.Variants="Superscript">2</Run>
    <Run>+ 2xy </Run>
</TextBlock>

I am putting those formulas in

public class Formula
{
    public string Text { get; set; }
    public Formula(string text) 
    {
        this.Text = text;
    }
}

public class MyViewModel
{
    public MyViewModel() 
    {
        this.Formulas = new List<Formula>
        {
            new Formula("<TextBlock><Run>x</Run><Run Typography.Variants=\"Superscript\">2</Run><Run>+ 2xy </Run></TextBlock>"),
            new Formula("<TextBlock><Run>x</Run><Run Typography.Variants=\"Superscript\">3</Run><Run>+ 3xy </Run></TextBlock>")
        };
    }  
}

I am then trying to display those formulas, formatted, as ComboBoxItems. Currently, I have the following:

<ComboBox ItemsSource="{Binding Path=Formulas}" DisplayMemberPath="Text" />

This approach does not show the formulas formatted. Is there a way to bind ComboBoxItems to show formatted values? If so, how?

Thanks!

Szabolcs Dézsi
  • 8,743
  • 21
  • 29
user70192
  • 13,786
  • 51
  • 160
  • 240
  • You would need to set the `Inlines` property of a TextBlock in the `ItemTemplate` of the ComboBox. Unfortunately that property isn't bindable, but there are workarounds explained here on StackOverflow. Search for "wpf bind textblock inlines". – Clemens Jan 19 '16 at 21:56

1 Answers1

3

I would suggest to look into libraries that offer proper display of formulas (a similar answer here)

Although if you want to make this approach work you can do it the following way.

<Window x:Class="BindFormulas.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BindFormulas"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:XamlTextToObjectConverter x:Key="XamlTextToObjectConverter" />
    </Window.Resources>

    <StackPanel>
        <ComboBox ItemsSource="{Binding Path=Formulas}">
            <ComboBox.ItemTemplate>
                <DataTemplate DataType="local:Formula">
                    <ContentControl Content="{Binding Text, Converter={StaticResource XamlTextToObjectConverter}}" />
                </DataTemplate>
            </ComboBox.ItemTemplate>
        </ComboBox>
    </StackPanel>
</Window>

The converter that will convert the XAML text to actual objects:

public class XamlTextToObjectConverter : IValueConverter
{
    private static readonly Regex Regex = new Regex("(<.*?)>(.*)(</.*?>)", RegexOptions.Compiled);

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var xamlText = value as string;

        if (xamlText != null)
        {
            var xamlTextWithNamespace = Regex.Replace(xamlText, "$1 xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\">$2$3");
            try
            {
                return XamlReader.Parse(xamlTextWithNamespace);
            }
            catch (Exception) // catch proper exceptions here, not just Exception
            {
                return value;
            }
        }
        else
        {
            return value;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

end result

Again, probably you'd be better off with a library that does this properly :)

This approach is wrong for multiple reasons:

The Formula class probably shouldn't know about things like TextBlock and Run. That's not a model class's concern. Also I'm sure you can provide a XAML string that will trip this converter up.

That said, if this will be a very simple app, where you will be a 100% sure that the XAML strings can be properly converted, then maybe this approach is OK as well.

Community
  • 1
  • 1
Szabolcs Dézsi
  • 8,743
  • 21
  • 29
  • I tried to integrate this approach. Unfortunately, I just got XAML strings. I didn't get actual superscripts etc. – user70192 Jan 19 '16 at 21:49
  • There must be something strange going on then, because it works on my end. If you set a breakpoint in the `catch` of the converter, does it stop there? – Szabolcs Dézsi Jan 19 '16 at 21:50