Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use xaml vector images as image source in Windows 8 app

I created some assets in inkscape and would like to use them as icons in a windows 8 application. I have done some reading and it seams that while .Net 4.5 supports SVG, the modern ui profile does not. I converted the svg to xaml using this tool.

I get the following xaml.

<Canvas xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="svg2997" Width="744.09448" Height="1052.3622" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Canvas x:Name="layer1">
    <Path Fill="#FFCCCCCC" Stroke="#FF000000" StrokeThickness="1.34377062" StrokeMiterLimit="4" x:Name="path3007" Data="M372.58272,134.72445C167.96301,134.72445 2.06820310000001,300.58818 2.06820310000001,505.20789 2.06820310000001,709.8276 167.96301,875.72241 372.58272,875.72241 577.20243,875.72241 743.06616,709.8276 743.06616,505.20789 743.06616,300.58818 577.20243,134.72445 372.58272,134.72445z M280.73888,251.77484L455.94149,251.77484 455.94149,413.70594 628.16035,413.70594 628.16035,588.97071 455.94149,588.97071 455.94149,773.71514 280.73888,773.71514 280.73888,588.97071 106.22005,588.97071 106.22005,413.70594 280.73888,413.70594 280.73888,251.77484z" />
  </Canvas>
</Canvas>

If I add this directly to my apps xaml it will render however the scale is way off.

I would like to use this as an image source for an image object if possible.

<Image HorizontalAlignment="Left" Height="100" Margin="127,37,0,0" VerticalAlignment="Top" Width="100" Source="Assets/plus_circle.xaml"/>

Can this be done?

like image 369
Chris Gonzales Avatar asked Feb 10 '13 03:02

Chris Gonzales


2 Answers

Most AppBar buttons are based on a style included in StandardStyles called AppBarButtonStyle.

To customize the text of the button you set the AutomationProperties.Name attached property, to customize the icon in the button you set the Content property, and it's also a good idea to set the AutomationProperties.AutomationId attached property for accessibility reasons.

Here's an example of a button customized using this approach:

<Style x:Key="FolderButtonStyle" TargetType="ButtonBase" BasedOn="{StaticResource AppBarButtonStyle}">
    <Setter Property="AutomationProperties.AutomationId" Value="FolderAppBarButton"/>
    <Setter Property="AutomationProperties.Name" Value="Folder"/>
    <Setter Property="Content" Value="&#xE188;"/>
</Style>

As mentioned above, to customize the icon you set the Content property. The challenge is how you set the content so it displays your custom vector art.

It turns out you can place any path Xaml, even yours, into a Viewbox to change its scale. That was my first approach, but it doesn't work. In fact, it seems any time you use Xaml expanded notation to set the Content property for a button it doesn't work.

<Style x:Key="SquareButtonStyle" TargetType="ButtonBase" BasedOn="{StaticResource AppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="SquareAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Square"/>
<Setter Property="Content">
    <Setter.Value>
        <!-- This square will never show -->
        <Rectangle Fill="Blue" Width="20" Height="20" />
    </Setter.Value>
</Setter>

I actually think this is a bug, but luckily there is a workaround.

Tim Heuer wrote an excellent article on the simplest way to use a Xaml Path as the artwork for a button. That article is here:

http://timheuer.com/blog/archive/2012/09/03/using-vectors-as-appbar-button-icons.aspx

In short, you need to define a style that sets up all the bindings correctly:

<Style x:Key="PathAppBarButtonStyle" BasedOn="{StaticResource AppBarButtonStyle}" TargetType="ButtonBase">
<Setter Property="ContentTemplate">
    <Setter.Value>
        <DataTemplate>
            <Path Width="20" Height="20" 
                Stretch="Uniform" 
                Fill="{Binding Path=Foreground, RelativeSource={RelativeSource Mode=TemplatedParent}}" 
                Data="{Binding Path=Content, RelativeSource={RelativeSource Mode=TemplatedParent}}"/>
        </DataTemplate>
    </Setter.Value>
</Setter>

Then you create a style that inherits from that style and you paste in your path. Here is the style for your artwork you listed above:

<Style x:Key="CrossButtonStyle" TargetType="ButtonBase" BasedOn="{StaticResource PathAppBarButtonStyle}">
    <Setter Property="AutomationProperties.AutomationId" Value="CrossAppBarButton"/>
    <Setter Property="AutomationProperties.Name" Value="Cross"/>
    <Setter Property="Content" Value="M372.58272,134.72445C167.96301,134.72445 2.06820310000001,300.58818 2.06820310000001,505.20789 2.06820310000001,709.8276 167.96301,875.72241 372.58272,875.72241 577.20243,875.72241 743.06616,709.8276 743.06616,505.20789 743.06616,300.58818 577.20243,134.72445 372.58272,134.72445z M280.73888,251.77484L455.94149,251.77484 455.94149,413.70594 628.16035,413.70594 628.16035,588.97071 455.94149,588.97071 455.94149,773.71514 280.73888,773.71514 280.73888,588.97071 106.22005,588.97071 106.22005,413.70594 280.73888,413.70594 280.73888,251.77484z"/>
</Style>

And finally, you use it in your AppBar like this:

<Button Style="{StaticResource CrossButtonStyle}" />

Dev support, design support and more awesome goodness on the way: http://bit.ly/winappsupport

like image 167
Jared Bienz - MSFT Avatar answered Nov 15 '22 18:11

Jared Bienz - MSFT


I'm pretty positive you can't just inject Path Data into an Image Source and expect it to magically work unless it's through a Drawing Object as Source. What you can however do is adopt your Path into a ContentControl for re-use in the same way without having to go through the trouble of Drawing objects for every instance.

So instead of;

<Image Source="..."/>

Just do something like this and plop it in your Object.Resources or ResourceDictionary;

 <Style x:Key="YourThingy" TargetType="ContentControl">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ContentControl">
                   <Path Fill="#FFCCCCCC" Stroke="#FF000000" StrokeThickness="1.34377062" StrokeMiterLimit="4" x:Name="path3007" Data="M372.58272,134.72445C167.96301,134.72445 2.06820310000001,300.58818 2.06820310000001,505.20789 2.06820310000001,709.8276 167.96301,875.72241 372.58272,875.72241 577.20243,875.72241 743.06616,709.8276 743.06616,505.20789 743.06616,300.58818 577.20243,134.72445 372.58272,134.72445z M280.73888,251.77484L455.94149,251.77484 455.94149,413.70594 628.16035,413.70594 628.16035,588.97071 455.94149,588.97071 455.94149,773.71514 280.73888,773.71514 280.73888,588.97071 106.22005,588.97071 106.22005,413.70594 280.73888,413.70594 280.73888,251.77484z" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Then just plop it on your view wherever and as many times as you like;

  <ContentControl Style="{StaticResource YourThingy}"/>

You will however want to play with that Path of yours. It seems set a large size, but hopefully this provides a good alternative for your circumstance. Cheers!

like image 33
Chris W. Avatar answered Nov 15 '22 18:11

Chris W.