Search code examples
c#xmlwindows-store-apps

Change text Style of XML in Windows Store App


I am creating an app where I have in it a table of content. I created an XML file to extract the data from it. In my XML, I want to change in the style of some text however i couldn't do it from the XML code. i tried putting the tags <b>, <bold> , <strong> but they didn't work

Please find below the XML code:

<book>
    <item type="Module">
      <title>My family and I</title>
    </item>
    <item type="Unit">
      <title>World Friends</title>
    </item>
    <item type="Unit">
      <title>Sport and activities</title>
    </item>
    <item type="Module">
      <title>
        <b>School days</b></title>
    </item>
    <item type="Unit">
      <title>My routine</title>
    </item>
    <item type="Unit">
      <title>School life</title>
    </item>
</book>

this is my XML. As you see I have 2 types: Module and Unit. I want to make the text bold in type module and to indent the text in Unit type.

I also created a class to call the title. I will show u the codes below:

this is my class

public class ContentTable
{
    string itemTitle;
    public string ItemTitle
    {
        get { return itemTitle; }
        set { itemTitle = value; }
    }
}

this is the code to retrieve data.

string XMLPath = Path.Combine(
   Package.Current.InstalledLocation.Path, "Assets/tableOfContent.xml");
XDocument loadedData = XDocument.Load(XMLPath);

//retrieving data from xml using LINQ     
var data = from query in loadedData.Descendants("item")
    select new ContentTable
    {
        ItemTitle = (string)query.Element("title")
    };

//assigning source to GridView Control     
AllItemsView.ItemsSource = data;

this is my XAML

<ListBox x:Name="AllItemsView" Width="200" Margin="45,20,5,-604" Height="665" VerticalAlignment="Top" Foreground="Black" Background="White" Grid.RowSpan="2" SelectionChanged="AllItemsView_SelectionChanged">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Margin="10" >
                <TextBlock Text="{Binding ItemTitle}"/>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Solution

  • An easy way to address this, were you writing a WPF program, would be to declare a Style for the TextBlock in which you use DataTrigger instances to apply specific formatting to the TextBlock properties based on the data. Unfortunately, this feature (like a number of other very useful features) isn't in WinRT. As I understand it, the common alternative is to implement IValueConverter, mapping some input value to the appropriate property value for your formatting. It's not as broadly useful as triggers, but for simple scenarios it works about the same.

    Note that whatever you wind up doing, the criteria on which you want to base formatting changes has to flow from the original data to the rendered output. There are a variety of ways to accomplish this, but given your example, it seems to me the simplest is to just add a property to your ContentTable class:

    public class ContentTable
    {
        public string ItemTitle { get; set; }
        public string ItemType { get; set; }
    }
    

    To your original ItemTitle property, I've added ItemType which will take the type property value from your XML.

    Of course, having added this property, it needs to be populated along with ItemTitle:

    var data = from query in loadedData.Descendants("item")
               select new ContentTable
               {
                   ItemTitle = query.Element("title").Value,
                   ItemType = query.Attribute("type").Value
               };
    

    Before we can bind this new property to a relevant TextBlock property (e.g. FontWeight or Margin), we need the converters that will map the specific string values in the type attribute to the appropriate property values for TextBlock:

    class ItemTypeToBoldConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            string text = value as string;
    
            if (text != null)
            {
                return text == "Module" ?
                    Windows.UI.Text.FontWeights.Bold :
                    Windows.UI.Text.FontWeights.Normal;
            }
    
            return Windows.UI.Xaml.DependencyProperty.UnsetValue;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
    
    class ItemTypeToMarginConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, string language)
        {
            string text = value as string;
    
            if (text != null)
            {
                return text == "Unit" ?
                    new Windows.UI.Xaml.Thickness(20, 0, 0, 0) :
                    new Windows.UI.Xaml.Thickness();
            }
    
            return Windows.UI.Xaml.DependencyProperty.UnsetValue;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, string language)
        {
            throw new NotImplementedException();
        }
    }
    

    Having laid all the necessary groundwork, the rest is easy. :)

    Your converters can be declared as resources (e.g. so they can be reused for multiple elements or even different DataTemplate instances):

    <Page.Resources>
      <local:ItemTypeToBoldConverter x:Key="itemTypeToBoldConverter1"/>
      <local:ItemTypeToMarginConverter x:Key="itemTypeToMarginConverter1"/>
    </Page.Resources>
    

    Finally, you can reference the converters in the template itself:

    <DataTemplate>
      <StackPanel Margin="10" >
        <TextBlock Text="{Binding ItemTitle}"
                    FontWeight="{Binding ItemType, Converter={StaticResource itemTypeToBoldConverter1}}"
                    Margin="{Binding ItemType, Converter={StaticResource itemTypeToMarginConverter1}}"/>
      </StackPanel>
    </DataTemplate>
    

    The above binds two different properties, FontWeight and Margin, to the same data item property, ItemType. But since they use different converters, they each behave appropriately. When the ItemType value is Module, the font weight is set to bold; otherwise, it's set to a normal weight. Similarly, when the ItemType value is Unit, the left margin is set to a non-zero value (in this example, I chose 20); otherwise, it's left set to 0 thickness.


    Note that the above translates your XML data directly to XAML UI element property values. In your question, you mention HTML markup, like <b>, <bold>, and <strong>. The above is the simplest approach, and matches best the exact code example and formatting criteria you've provided. But you can't use it to apply HTML formatting. You're stuck with the formatting and layout that's available in XAML. Now, that is in fact a pretty rich formatting environment, but if you want an HTML-based approach, you can do that instead.

    There would be lots of options there as well, but IMHO the best way would be to write an XSL stylesheet that transforms your XML to the appropriate HTML document, using the XsltTransform class to convert (assuming that's available on WinRT…I didn't check). Then you can use the WebView control (or in WPF, WebBrowser) to display the HTML.