如何在整个应用程序中使用Canvas作为StaticResource?

时间:2013-11-06 16:07:52

标签: xaml pdf windows-phone-8 vector-graphics

我有一堆图标应该在Windows Phone 8应用程序中的不同大小的许多不同位置使用。使用普通图形我必须为每个支持的分辨率创建每个大小的每个图标。这可能会成为很多文件......

因此我想使用矢量图形。由于我将所有图标都设为PDF / Illustrator。这不是问题。我使用Blend导入这些文件并自动创建XAML:

<Canvas x:Name="TestIcon" Height="27.985" Canvas.Left="5.506" Canvas.Top="2.007" Width="20.988">
    <Path Data="F1M26.992,... Fill="#FF376EB5" Height="27.977" Canvas.Left="0" Stretch="None" Canvas.Top="0" Width="27.993">
        <Path.Clip>
            <RectangleGeometry Rect="0,-0.001,27.992,27.977"/>
         </Path.Clip>
    </Path>
</Canvas>

问题:如何在整个应用中使用此画布?

我将Canvas添加到Application.Resources并尝试引用它:

<!-- Version 1 -->
<Button Content="{StaticResource TestIcon} .../>

<!-- Version 2 -->
<Button ...>
    <ContentPresenter Content="{StaticResource TestIcon}" .../>
</Button>

<!-- Version 3 -->
<Button ...>
    <Canvas ..>
        <Path Data="F1M26.992,... ...>
            <Path.Clip>
                ...
             </Path.Clip>
        </Path>
    </Canvas>
</Button>

使用版本1或2时,一切都在Designer中正常工作。一旦我运行应用程序,它就会出现一个System.Windows.Markup.XamlParseException:

  

无法分配属性'System.Windows.Controls.ContentPresenter.Content'。

版本3在Designer和运行时都可以正常工作。但是,当然这个解决方案不使用对VectorGraphic的任何引用,而是直接包含Canvas。

知道如何解决这个问题吗?

3 个答案:

答案 0 :(得分:3)

您应该只为Resources中的每个形状创建ControlTemplate,然后在您的应用中的任何位置重复使用此模板:

<ControlTemplate x:Key="MyIcon">
    <Canvas x:Name="TestIcon" Height="27.985" Canvas.Left="5.506" Canvas.Top="2.007" Width="20.988">
        <Path Data="F1M26.992,... Fill="#FF376EB5" Height="27.977" Canvas.Left="0" Stretch="None" Canvas.Top="0" Width="27.993">
            <Path.Clip>
                <RectangleGeometry Rect="0,-0.001,27.992,27.977"/>
             </Path.Clip>
        </Path>
    </Canvas>
</ControlTemplate>

on another place, where you want to show  it:
<ContentControl Template="{StaticResource MyIcon}"/>

答案 1 :(得分:2)

检查出来:Reusing Vector Graphics in Windows 8 Store Apps

有三种方法可以重用XAML路径

  1. 使用路径本身

    <Border Height="200"
        Width="200"
        BorderBrush="Red"
        BorderThickness="1"
        Background="Yellow"
        Padding="20"
        Grid.Row="1"
        Grid.Column="1">
    <Viewbox Stretch="Uniform">
        <!-- Works at designtime but crashes at runtime -->
        <!--<ContentControl Content="{StaticResource PrancingHorse}" />-->    
        <!-- That would work if if were possible to define the PathGeomatry as a resource. -->
        <!--<Path Data="{StaticResource PrancingGeometry}" />-->
        <Path Data="M22.923445,61.752014L22.733789,61.7598....."
                Fill="White" />
    </Viewbox>
    

  2. 将路径数据用作字符串资源

    <Page.Resources>
        <x:String x:Key="PrancingString">M22.923445,61.752014L22.733789,61.759857 .....</x:String>
    </Page.Resources>
    
    <Border Height="200"
        Width="200"
        BorderBrush="Red"
        BorderThickness="1"
        Padding="20"
        Grid.Row="3"
        Grid.Column="2">
    <Viewbox Stretch="Uniform">
        <Path Data="{StaticResource PrancingString}"
              Fill="White" />
    </Viewbox>
    

  3. 使用图标控件

  4. IconControl.cs

    public sealed class IconControl : Control
    {
        public static readonly DependencyProperty DataGeometryProperty =
            DependencyProperty.Register("DataGeometry", typeof(PathGeometry), typeof(IconControl), new PropertyMetadata(null));
    
        public static readonly DependencyProperty DataProperty =
            DependencyProperty.Register("Data", typeof(String), typeof(IconControl), new PropertyMetadata(null, new PropertyChangedCallback(OnDataChanged)));
    
        public IconControl()
        {
            this.DefaultStyleKey = typeof(IconControl);
        }
    
        // Write-only to be used in a binding.
        public String Data
        {
            private get { return (String)GetValue(DataProperty); }
            set { SetValue(DataProperty, value); }
        }
    
        // Read-only to be used in the control's template.
        public PathGeometry DataGeometry
        {
            get { return (PathGeometry)GetValue(DataGeometryProperty); }
            private set { SetValue(DataGeometryProperty, value); }
        }
    
        private static void OnDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            IconControl ic = d as IconControl;
    
            // In WPF: ic.DataGeometry = PathGeometry.CreateFromGeometry(PathGeometry.Parse(e.NewValue.ToString()));
            ic.DataGeometry = new PathGeometryParser().Parse(e.NewValue.ToString());
        }
    }
    

    PathGeometryParser.cs

    public class PathGeometryParser
    {
        #region Constants
        const bool AllowSign = true;
        const bool AllowComma = true;
        const bool IsFilled = true;
        const bool IsClosed = true; 
        #endregion
    
        #region Fields
        IFormatProvider _formatProvider;
    
        PathFigure _figure = null;     // Figure object, which will accept parsed segments
        string _pathString;        // Input string to be parsed
        int _pathLength;
        int _curIndex;          // Location to read next character from
        bool _figureStarted;     // StartFigure is effective 
    
        Point _lastStart;         // Last figure starting point
        Point _lastPoint;         // Last point 
        Point _secondLastPoint;   // The point before last point
    
        char _token = ' ';             // Non whitespace character returned by ReadToken 
        #endregion
    
        static internal char GetNumericListSeparator(IFormatProvider provider)
        {
            char numericSeparator = ',';
    
            // Get the NumberFormatInfo out of the provider, if possible
            // If the IFormatProvider doesn't not contain a NumberFormatInfo, then 
            // this method returns the current culture's NumberFormatInfo. 
            NumberFormatInfo numberFormat = NumberFormatInfo.GetInstance(provider);
    
            // Is the decimal separator is the same as the list separator?
            // If so, we use the ";". 
            if ((numberFormat.NumberDecimalSeparator.Length > 0) && (numericSeparator == numberFormat.NumberDecimalSeparator[0]))
            {
                numericSeparator = ';';
            }
    
            return numericSeparator;
        }
    
        /// <summary>
        /// Turns a string into a PathGeometry.
        /// </summary>
        /// <remarks>
        /// Code could use some refactoring, to expose the logic as an extension method of PathGeometry.
        /// </remarks>
        public PathGeometry Parse(string path)
        {
            PathGeometry _pathGeometry = null;
    
            _formatProvider = CultureInfo.InvariantCulture;
            _pathString = path;
            _pathLength = path.Length;
            _curIndex = 0;
    
            _secondLastPoint = new Point(0, 0);
            _lastPoint = new Point(0, 0);
            _lastStart = new Point(0, 0);
    
            _figureStarted = false;
    
            bool first = true;
    
            char last_cmd = ' ';
    
            while (ReadToken()) // Empty path is allowed in XAML
            {
                char cmd = _token;
    
                if (first)
                {
                    if ((cmd != 'M') && (cmd != 'm') && (cmd != 'f') && (cmd != 'F'))  // Path starts with M|m 
                    {
                        ThrowBadToken();
                    }
    
                    first = false;
                }
    
                switch (cmd)
                {
                    case 'f':
                    case 'F':
                        _pathGeometry = new PathGeometry();
                        double _num = ReadNumber(!AllowComma);
                        _pathGeometry.FillRule = _num == 0 ? FillRule.EvenOdd : FillRule.Nonzero;
                        break;
    
                    case 'm':
                    case 'M':
                        // XAML allows multiple points after M/m
                        _lastPoint = ReadPoint(cmd, !AllowComma);
    
                        _figure = new PathFigure();
                        _figure.StartPoint = _lastPoint;
                        _figure.IsFilled = IsFilled;
                        _figure.IsClosed = !IsClosed;
                        //context.BeginFigure(_lastPoint, IsFilled, !IsClosed);
                        _figureStarted = true;
                        _lastStart = _lastPoint;
                        last_cmd = 'M';
    
                        while (IsNumber(AllowComma))
                        {
                            _lastPoint = ReadPoint(cmd, !AllowComma);
    
                            LineSegment _lineSegment = new LineSegment();
                            _lineSegment.Point = _lastPoint;
                            _figure.Segments.Add(_lineSegment);
                            //context.LineTo(_lastPoint, IsStroked, !IsSmoothJoin);
                            last_cmd = 'L';
                        }
                        break;
    
                    case 'l':
                    case 'L':
                    case 'h':
                    case 'H':
                    case 'v':
                    case 'V':
                        EnsureFigure();
    
                        do
                        {
                            switch (cmd)
                            {
                                case 'l': _lastPoint = ReadPoint(cmd, !AllowComma); break;
                                case 'L': _lastPoint = ReadPoint(cmd, !AllowComma); break;
                                case 'h': _lastPoint.X += ReadNumber(!AllowComma); break;
                                case 'H': _lastPoint.X = ReadNumber(!AllowComma); break;
                                case 'v': _lastPoint.Y += ReadNumber(!AllowComma); break;
                                case 'V': _lastPoint.Y = ReadNumber(!AllowComma); break;
                            }
    
                            LineSegment _lineSegment = new LineSegment();
                            _lineSegment.Point = _lastPoint;
                            _figure.Segments.Add(_lineSegment);
                            //context.LineTo(_lastPoint, IsStroked, !IsSmoothJoin);
                        }
                        while (IsNumber(AllowComma));
    
                        last_cmd = 'L';
                        break;
    
                    case 'c':
                    case 'C': // cubic Bezier 
                    case 's':
                    case 'S': // smooth cublic Bezier
                        EnsureFigure();
    
                        do
                        {
                            Point p;
    
                            if ((cmd == 's') || (cmd == 'S'))
                            {
                                if (last_cmd == 'C')
                                {
                                    p = Reflect();
                                }
                                else
                                {
                                    p = _lastPoint;
                                }
    
                                _secondLastPoint = ReadPoint(cmd, !AllowComma);
                            }
                            else
                            {
                                p = ReadPoint(cmd, !AllowComma);
    
                                _secondLastPoint = ReadPoint(cmd, AllowComma);
                            }
    
                            _lastPoint = ReadPoint(cmd, AllowComma);
    
                            BezierSegment _bizierSegment = new BezierSegment();
                            _bizierSegment.Point1 = p;
                            _bizierSegment.Point2 = _secondLastPoint;
                            _bizierSegment.Point3 = _lastPoint;
                            _figure.Segments.Add(_bizierSegment);
                            //context.BezierTo(p, _secondLastPoint, _lastPoint, IsStroked, !IsSmoothJoin);
    
                            last_cmd = 'C';
                        }
                        while (IsNumber(AllowComma));
    
                        break;
    
                    case 'q':
                    case 'Q': // quadratic Bezier 
                    case 't':
                    case 'T': // smooth quadratic Bezier
                        EnsureFigure();
    
                        do
                        {
                            if ((cmd == 't') || (cmd == 'T'))
                            {
                                if (last_cmd == 'Q')
                                {
                                    _secondLastPoint = Reflect();
                                }
                                else
                                {
                                    _secondLastPoint = _lastPoint;
                                }
    
                                _lastPoint = ReadPoint(cmd, !AllowComma);
                            }
                            else
                            {
                                _secondLastPoint = ReadPoint(cmd, !AllowComma);
                                _lastPoint = ReadPoint(cmd, AllowComma);
                            }
    
                            QuadraticBezierSegment _quadraticBezierSegment = new QuadraticBezierSegment();
                            _quadraticBezierSegment.Point1 = _secondLastPoint;
                            _quadraticBezierSegment.Point2 = _lastPoint;
                            _figure.Segments.Add(_quadraticBezierSegment);
                            //context.QuadraticBezierTo(_secondLastPoint, _lastPoint, IsStroked, !IsSmoothJoin);
    
                            last_cmd = 'Q';
                        }
                        while (IsNumber(AllowComma));
    
                        break;
    
                    case 'a':
                    case 'A':
                        EnsureFigure();
    
                        do
                        {
                            // A 3,4 5, 0, 0, 6,7
                            double w = ReadNumber(!AllowComma);
                            double h = ReadNumber(AllowComma);
                            double rotation = ReadNumber(AllowComma);
                            bool large = ReadBool();
                            bool sweep = ReadBool();
    
                            _lastPoint = ReadPoint(cmd, AllowComma);
    
                            ArcSegment _arcSegment = new ArcSegment();
                            _arcSegment.Point = _lastPoint;
                            _arcSegment.Size = new Size(w, h);
                            _arcSegment.RotationAngle = rotation;
                            _arcSegment.IsLargeArc = large;
                            _arcSegment.SweepDirection = sweep ? SweepDirection.Clockwise : SweepDirection.Counterclockwise;
                            _figure.Segments.Add(_arcSegment);
                            //context.ArcTo(
                            //    _lastPoint,
                            //    new Size(w, h),
                            //    rotation,
                            //    large,
                            //    sweep ? SweepDirection.Clockwise : SweepDirection.Counterclockwise,
                            //    IsStroked,
                            //    !IsSmoothJoin
                            //    );
                        }
                        while (IsNumber(AllowComma));
    
                        last_cmd = 'A';
                        break;
    
                    case 'z':
                    case 'Z':
                        EnsureFigure();
                        _figure.IsClosed = IsClosed;
                        //context.SetClosedState(IsClosed);
    
                        _figureStarted = false;
                        last_cmd = 'Z';
    
                        _lastPoint = _lastStart; // Set reference point to be first point of current figure
                        break;
    
                    default:
                        ThrowBadToken();
                        break;
                }
    
                if (null != _figure)
                {
                    if (_figure.IsClosed)
                    {
                        if (null == _pathGeometry)
                            _pathGeometry = new PathGeometry();
    
                        _pathGeometry.Figures.Add(_figure);
    
                        _figure = null;
                        first = true;
                    }
                }
    
    
            }
    
            if (null != _figure)
            {
                if (null == _pathGeometry)
                    _pathGeometry = new PathGeometry();
    
                if (!_pathGeometry.Figures.Contains(_figure))
                    _pathGeometry.Figures.Add(_figure);
    
            }
            return _pathGeometry;
        }
    
        // Not used! Just here for the completeness.
        public string ParseBack(PathGeometry geometry)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            IFormatProvider provider = new System.Globalization.CultureInfo("en-us");
            string format = null;
    
            sb.Append("F" + (geometry.FillRule == FillRule.EvenOdd ? "0" : "1") + " ");
    
            foreach (PathFigure figure in geometry.Figures)
            {
                sb.Append("M " + ((IFormattable)figure.StartPoint).ToString(format, provider) + " ");
    
                foreach (PathSegment segment in figure.Segments)
                {
                    char separator = GetNumericListSeparator(provider);
    
                    if (segment.GetType() == typeof(LineSegment))
                    {
                        LineSegment _lineSegment = segment as LineSegment;
    
                        sb.Append("L " + ((IFormattable)_lineSegment.Point).ToString(format, provider) + " ");
                    }
                    else if (segment.GetType() == typeof(BezierSegment))
                    {
                        BezierSegment _bezierSegment = segment as BezierSegment;
    
                        sb.Append(String.Format(provider,
                                "C{1:" + format + "}{0}{2:" + format + "}{0}{3:" + format + "} ",
                                separator,
                                _bezierSegment.Point1,
                                _bezierSegment.Point2,
                                _bezierSegment.Point3
                                ));
                    }
                    else if (segment.GetType() == typeof(QuadraticBezierSegment))
                    {
                        QuadraticBezierSegment _quadraticBezierSegment = segment as QuadraticBezierSegment;
    
                        sb.Append(String.Format(provider,
                                "Q{1:" + format + "}{0}{2:" + format + "} ",
                                separator,
                                _quadraticBezierSegment.Point1,
                                _quadraticBezierSegment.Point2));
                    }
                    else if (segment.GetType() == typeof(ArcSegment))
                    {
                        ArcSegment _arcSegment = segment as ArcSegment;
    
                        sb.Append(String.Format(provider,
                                "A{1:" + format + "}{0}{2:" + format + "}{0}{3}{0}{4}{0}{5:" + format + "} ",
                                separator,
                                _arcSegment.Size,
                                _arcSegment.RotationAngle,
                                _arcSegment.IsLargeArc ? "1" : "0",
                                _arcSegment.SweepDirection == SweepDirection.Clockwise ? "1" : "0",
                                _arcSegment.Point));
                    }
                }
    
                if (figure.IsClosed)
                    sb.Append("Z");
            }
    
            return sb.ToString();
        }
    
        #region Privates
        private void SkipDigits(bool signAllowed)
        {
            // Allow for a sign 
            if (signAllowed && More() && ((_pathString[_curIndex] == '-') || _pathString[_curIndex] == '+'))
            {
                _curIndex++;
            }
    
            while (More() && (_pathString[_curIndex] >= '0') && (_pathString[_curIndex] <= '9'))
            {
                _curIndex++;
            }
        }
    
        private bool ReadBool()
        {
            SkipWhiteSpace(AllowComma);
    
            if (More())
            {
                _token = _pathString[_curIndex++];
    
                if (_token == '0')
                {
                    return false;
                }
                else if (_token == '1')
                {
                    return true;
                }
            }
    
            ThrowBadToken();
    
            return false;
        }
    
        private Point Reflect()
        {
            return new Point(2 * _lastPoint.X - _secondLastPoint.X,
                                2 * _lastPoint.Y - _secondLastPoint.Y);
        }
    
        private void EnsureFigure()
        {
            if (!_figureStarted)
            {
                _figure = new PathFigure();
                _figure.StartPoint = _lastStart;
    
                //_context.BeginFigure(_lastStart, IsFilled, !IsClosed);
                _figureStarted = true;
            }
        }
    
        private double ReadNumber(bool allowComma)
        {
            if (!IsNumber(allowComma))
            {
                ThrowBadToken();
            }
    
            bool simple = true;
            int start = _curIndex;
    
            //
            // Allow for a sign
            //
            // There are numbers that cannot be preceded with a sign, for instance, -NaN, but it's 
            // fine to ignore that at this point, since the CLR parser will catch this later.
            // 
            if (More() && ((_pathString[_curIndex] == '-') || _pathString[_curIndex] == '+'))
            {
                _curIndex++;
            }
    
            // Check for Infinity (or -Infinity).
            if (More() && (_pathString[_curIndex] == 'I'))
            {
                // 
                // Don't bother reading the characters, as the CLR parser will 
                // do this for us later.
                // 
                _curIndex = Math.Min(_curIndex + 8, _pathLength); // "Infinity" has 8 characters
                simple = false;
            }
            // Check for NaN 
            else if (More() && (_pathString[_curIndex] == 'N'))
            {
                // 
                // Don't bother reading the characters, as the CLR parser will
                // do this for us later. 
                //
                _curIndex = Math.Min(_curIndex + 3, _pathLength); // "NaN" has 3 characters
                simple = false;
            }
            else
            {
                SkipDigits(!AllowSign);
    
                // Optional period, followed by more digits 
                if (More() && (_pathString[_curIndex] == '.'))
                {
                    simple = false;
                    _curIndex++;
                    SkipDigits(!AllowSign);
                }
    
                // Exponent
                if (More() && ((_pathString[_curIndex] == 'E') || (_pathString[_curIndex] == 'e')))
                {
                    simple = false;
                    _curIndex++;
                    SkipDigits(AllowSign);
                }
            }
    
            if (simple && (_curIndex <= (start + 8))) // 32-bit integer
            {
                int sign = 1;
    
                if (_pathString[start] == '+')
                {
                    start++;
                }
                else if (_pathString[start] == '-')
                {
                    start++;
                    sign = -1;
                }
    
                int value = 0;
    
                while (start < _curIndex)
                {
                    value = value * 10 + (_pathString[start] - '0');
                    start++;
                }
    
                return value * sign;
            }
            else
            {
                string subString = _pathString.Substring(start, _curIndex - start);
    
                try
                {
                    return System.Convert.ToDouble(subString, _formatProvider);
                }
                catch (FormatException except)
                {
                    throw new FormatException(string.Format("Unexpected character in path '{0}' at position {1}", _pathString, _curIndex - 1), except);
                }
            }
        }
    
        private bool IsNumber(bool allowComma)
        {
            bool commaMet = SkipWhiteSpace(allowComma);
    
            if (More())
            {
                _token = _pathString[_curIndex];
    
                // Valid start of a number
                if ((_token == '.') || (_token == '-') || (_token == '+') || ((_token >= '0') && (_token <= '9'))
                    || (_token == 'I')  // Infinity
                    || (_token == 'N')) // NaN 
                {
                    return true;
                }
            }
    
            if (commaMet) // Only allowed between numbers
            {
                ThrowBadToken();
            }
    
            return false;
        }
    
        private Point ReadPoint(char cmd, bool allowcomma)
        {
            double x = ReadNumber(allowcomma);
            double y = ReadNumber(AllowComma);
    
            if (cmd >= 'a') // 'A' < 'a'. lower case for relative
            {
                x += _lastPoint.X;
                y += _lastPoint.Y;
            }
    
            return new Point(x, y);
        }
    
        private bool ReadToken()
        {
            SkipWhiteSpace(!AllowComma);
    
            // Check for end of string 
            if (More())
            {
                _token = _pathString[_curIndex++];
    
                return true;
            }
            else
            {
                return false;
            }
        }
    
        private bool More()
        {
            return _curIndex < _pathLength;
        }
    
        // Skip white space, one comma if allowed
        private bool SkipWhiteSpace(bool allowComma)
        {
            bool commaMet = false;
    
            while (More())
            {
                char ch = _pathString[_curIndex];
    
                switch (ch)
                {
                    case ' ':
                    case '\n':
                    case '\r':
                    case '\t': // SVG whitespace 
                        break;
    
                    case ',':
                        if (allowComma)
                        {
                            commaMet = true;
                            allowComma = false; // one comma only
                        }
                        else
                        {
                            ThrowBadToken();
                        }
                        break;
    
                    default:
                        // Avoid calling IsWhiteSpace for ch in (' ' .. 'z']
                        if (((ch > ' ') && (ch <= 'z')) || !Char.IsWhiteSpace(ch))
                        {
                            return commaMet;
                        }
                        break;
                }
    
                _curIndex++;
            }
    
            return commaMet;
        }
    
        private void ThrowBadToken()
        {
            throw new FormatException(string.Format("Unexpected character in path '{0}' at position {1}", _pathString, _curIndex - 1));
        } 
        #endregion
    }
    

    XAML

    <Border Grid.Row="3"
            Grid.Column="3"
            BorderBrush="Yellow"
            BorderThickness="1"
            Height="200"
            Width="200">
        <local:IconControl Height="200"
                           Width="200"
                           Padding="20"
                           Background="White"
                           Foreground="Red"
                           Data="{StaticResource PrancingString}" />
    </Border>
    

答案 2 :(得分:0)

对我来说最简单的方法:

<ResourceDictionary ...>
    <Canvas x:Key="appbar_tools">
        <Path Fill="#FF000000" Data="F1 M 25.3333,42.75C 26.5189,42.75 27.6436,43.0106 28.6533,43.4777L 34.9459,37.185L 32.5825,34.8217L 30.3433,37.0609L 28.1042,34.8217L 29.0343,33.8915C 27.1425,33.1521 25.7233,31.6492 23.4735,29.3994C 18.836,24.7619 16.1846,19.8945 18.0395,18.0396C 19.8945,16.1846 23.9702,18.0444 28.6077,22.6819C 30.8575,24.9317 33.1521,27.1425 33.8915,29.0344L 34.8217,28.1042L 37.0608,30.3433L 34.8217,32.5825L 37.185,34.9459L 43.4777,28.6533C 43.0106,27.6436 42.75,26.5189 42.75,25.3333C 42.75,20.9611 46.2944,17.4167 50.6667,17.4167C 51.6877,17.4167 52.6636,17.61 53.5597,17.9619L 47.5,24.0216L 51.9783,28.5L 58.0381,22.4403C 58.39,23.3364 58.5833,24.3123 58.5833,25.3333C 58.5833,29.7056 55.0389,33.25 50.6667,33.25C 49.8136,33.25 48.9921,33.1151 48.2222,32.8654L 41.6634,39.4242L 50.8787,48.6395L 51.4384,48.0797L 56.8841,53.5253L 53.5253,56.8841L 48.0797,51.4384L 48.6395,50.8787L 39.4242,41.6634L 32.8654,48.2222C 33.1151,48.9921 33.25,49.8136 33.25,50.6667C 33.25,55.0389 29.7056,58.5833 25.3333,58.5833C 24.3123,58.5833 23.3364,58.39 22.4403,58.0381L 28.5,51.9783L 24.0217,47.5L 17.9619,53.5597C 17.61,52.6636 17.4167,51.6877 17.4167,50.6667C 17.4167,46.2944 20.9611,42.75 25.3333,42.75 Z "/>
    </Canvas>
</ResourceDictionary>

然后在你的控制中:

<Rectangle Width="50" Height="50" Fill="Black">
    <Rectangle.OpacityMask>
        <VisualBrush Stretch="Fill" Visual="{DynamicResource appbar_copy}" />
    </Rectangle.OpacityMask>
</Rectangle>