WPF Was ist die richtige Art, SVG-Dateien als Symbole in WPF zu verwenden?

75

Kann jemand ein empfohlenes schrittweises Verfahren beschreiben, um dies zu tun?

BEARBEITEN:

Schritt 1. Konvertieren Sie SVG in XAML ... das ist einfach

Schritt 2. Was jetzt?

NVM
quelle
10
Es tut mir leid, diesen Beitrag wiederzubeleben, aber ich denke, diese Informationen haben Wert: Eine SVG ist im Wesentlichen eine Eins-zu-Eins-Übereinstimmung mit einem WPF-Pfad. Abgesehen von einigen oberflächlichen Markup-Anpassungen sollten Sie in der Lage sein, das SVG direkt in Ihre WPF-Anwendung zu integrieren. Möglicherweise müssen Sie den Pfad höchstens in einer Leinwand hosten, aber das ist alles, IMHO.
Code4life

Antworten:

151

Ihre Technik hängt davon ab, welches XAML-Objekt Ihr SVG-XAML-Konverter erzeugt. Produziert es eine Zeichnung? Ein Bild? Ein Gitter? Eine Leinwand? Ein Weg? Eine Geometrie? In jedem Fall wird Ihre Technik anders sein.

In den folgenden Beispielen gehe ich davon aus, dass Sie Ihr Symbol auf einer Schaltfläche verwenden. Dies ist das häufigste Szenario. Beachten Sie jedoch, dass für jedes ContentControl dieselben Techniken gelten.

Verwenden einer Zeichnung als Symbol

Um eine Zeichnung zu verwenden, malen Sie mit einem DrawingBrush ein Rechteck mit der entsprechenden Größe:

<Button>
  <Rectangle Width="100" Height="100">
    <Rectangle.Fill>
      <DrawingBrush>
        <DrawingBrush.Drawing>

          <Drawing ... /> <!-- Converted from SVG -->

        </DrawingBrush.Drawing>
      </DrawingBrush>
    </Rectangle.Fill>
  </Rectangle>
</Button>

Verwenden eines Bildes als Symbol

Ein Bild kann direkt verwendet werden:

<Button>
  <Image ... />  <!-- Converted from SVG -->
</Button>

Verwenden eines Rasters als Symbol

Ein Raster kann direkt verwendet werden:

<Button>
  <Grid ... />  <!-- Converted from SVG -->
</Button>

Sie können es auch in eine Viewbox aufnehmen, wenn Sie die Größe steuern müssen:

<Button>
  <Viewbox ...>
    <Grid ... />  <!-- Converted from SVG -->
  </Viewbox>
</Button>

Verwenden einer Leinwand als Symbol

Dies ist wie bei der Verwendung eines Bilds oder Rasters, aber da eine Leinwand keine feste Größe hat, müssen Sie die Höhe und Breite angeben (es sei denn, diese werden bereits vom SVG-Konverter festgelegt):

<Button>
  <Canvas Height="100" Width="100">  <!-- Converted from SVG, with additions -->
  </Canvas>
</Button>

Verwenden eines Pfads als Symbol

Sie können einen Pfad verwenden, müssen jedoch den Strich festlegen oder explizit füllen:

<Button>
  <Path Stroke="Red" Data="..." /> <!-- Converted from SVG, with additions -->
</Button>

oder

<Button>
  <Path Fill="Blue" Data="..." /> <!-- Converted from SVG, with additions -->
</Button>

Verwenden einer Geometrie als Symbol

Sie können einen Pfad verwenden, um Ihre Geometrie zu zeichnen. Wenn es gestrichen werden soll, stellen Sie den Strich ein:

<Button>
  <Path Stroke="Red" Width="100" Height="100">
    <Path.Data>
      <Geometry ... /> <!-- Converted from SVG -->
    </Path.Data>
  </Path>
</Button>

oder wenn es gefüllt werden soll, stellen Sie die Füllung ein:

<Button>
  <Path Fill="Blue" Width="100" Height="100">
    <Path.Data>
      <Geometry ... /> <!-- Converted from SVG -->
    </Path.Data>
  </Path>
</Button>

So binden Sie Daten

Wenn Sie die SVG -> XAML-Konvertierung im Code durchführen und möchten, dass die resultierende XAML mithilfe der Datenbindung angezeigt wird, verwenden Sie eine der folgenden Methoden:

Zeichnung binden:

<Button>
  <Rectangle Width="100" Height="100">
    <Rectangle.Fill>
      <DrawingBrush Drawing="{Binding Drawing, Source={StaticResource ...}}" />
    </Rectangle.Fill>
  </Rectangle>
</Button>

Ein Bild binden:

<Button Content="{Binding Image}" />

Ein Gitter binden:

<Button Content="{Binding Grid}" />

Binden eines Rasters in einer Viewbox:

<Button>
  <Viewbox ...>
    <ContentPresenter Content="{Binding Grid}" />
  </Viewbox>
</Button>

Leinwand binden:

<Button>
  <ContentPresenter Height="100" Width="100" Content="{Binding Canvas}" />
</Button>

Einen Weg binden:

<Button Content="{Binding Path}" />  <!-- Fill or stroke must be set in code unless set by the SVG converter -->

Eine Geometrie binden:

<Button>
  <Path Width="100" Height="100" Data="{Binding Geometry}" />
</Button>
Ray Burns
quelle
10
+10 Nehmen Sie sich einfach die Zeit für Beispiele für alle Fälle. In meinem Fall habe ich eine Leinwand, daher gehe ich davon aus, dass Folgendes gilt: <Button> <Canvas Height = "100" Width = "100"> <! - Von SVG konvertiert, mit Ergänzungen - -> </ Canvas> </ Button> Aber wie verwende ich das wieder? Ich kann nicht für jede Schaltfläche kopieren / einfügen, in der ich das SVG-Bild verwenden möchte. Ich möchte es als Ressourcen in einem Wörterbuch definieren und als statische / dynamische Ressource verwenden.
NVM
3
Sie können ein einzelnes Canvas nicht an mehreren Stellen in Ihrer Benutzeroberfläche verwenden, da ein Visual nur ein übergeordnetes Element haben kann. Daher würden Sie normalerweise eine Vorlage dafür verwenden. Eine Vorlage können Sie eine separate Instanz des Canvas jeden Ort schaffen Sie es brauchen: <ResourceDictionary><DataTemplate x:Key="MyIconTemplate"><Canvas ... /></DataTemplate></ResourceDictionary>... <Button><ContentPresenter ContentTemplate="{StaticResource MyIconTemplate}" /></Button>.
Ray Burns
1
Ein effizientere aber komplexere Ansatz ist es, eine VisualBrush verwendet ein Bild der Leinwand zu erstellen zu malen mit: <ResourceDictionary><VisualBrush x:Key="MyBrush"><VisualBrush.Visual><Canvas x:Key="MyCanvas" ... /></VisualBrush.Visual></VisualBrush></ResourceDictionary>... <Button><Rectangle Fill="{StaticResource MyBrush}" Width="..." Height="..." /></Button>. Dies ist schwieriger, da Sie auch sicherstellen müssen, dass die Leinwand gemessen / angeordnet wird, und die Breite / Höhe hart codieren müssen (oder eine Vorlage für das Rechteck verwenden müssen).
Ray Burns
Aha!!! Ich wusste, dass ich nicht zweimal dieselbe Leinwand direkt verwenden konnte, weshalb die Antwort noch nicht akzeptiert wurde. Danke vielmals.
NVM
1
CanvasWo lege ich für jedes dieser Elemente - z. B. das Objekt - die SVG ab? Dies ist wichtig, da sich meine
SVGs
52

Installieren Sie die SharpVectors- Bibliothek

Install-Package SharpVectors

Fügen Sie in XAML Folgendes hinzu

<UserControl xmlns:svgc="http://sharpvectors.codeplex.com/svgc">
    <svgc:SvgViewbox Source="/Icons/icon.svg"/>
</UserControl>
FastObject
quelle
6
Ist es besser, die XAML Imges in die App einzubetten oder diesen Ansatz zu verwenden?
MyOwnWay
Funktioniert sehr gut für mich ... mit Nugets und allem. Ich musste das SVG mit den Farbinformationen korrekt erstellen, aber sobald das behoben war, erscheinen sie nicht mehr schwarz, sondern sehen gut aus.
KFN
1
So können Sie mit Sharpvectors an eine Source AttachedProperty binden: stackoverflow.com/a/35088090/828184
CodingYourLife
Update für 2020 Es gibt eine neue Version mit SharpVectors.Reloaded
Andy Braham
6

Windows 10 Build 15063 "Creators Update" unterstützt nativ SVG-Images (allerdings mit einigen Fallstricken) für UWP / UAP-Anwendungen, die auf Windows 10 abzielen.

Wenn Ihre Anwendung eher eine WPF-App als eine UWP / UAP ist, können Sie diese API weiterhin verwenden (nachdem Sie eine ganze Reihe von Schritten durchlaufen haben): Windows 10 Build 17763 "Oktober 2018 Update" führte das Konzept der XAML-Inseln ein (als " Vorschau "-Technologie, aber ich glaube, im App Store erlaubt; in allen Fällen sind XAML-Inseln mit Windows 10 Build 18362" Mai 2019 Update "keine Vorschaufunktion mehr und werden vollständig unterstützt, sodass Sie UWP-APIs und -Steuerelemente in Ihrem WPF verwenden können Anwendungen.

Sie müssen zuerst die Verweise auf die WinRT-APIs hinzufügen und bestimmte Windows 10-APIs verwenden, die mit Benutzerdaten oder dem System interagieren (z. B. Laden von Bildern von der Festplatte in eine Windows 10 UWP-Webansicht oder Verwenden der Toastbenachrichtigungs-API zum Anzeigen von Toasts). Sie müssen Ihre WPF-Anwendung auch einer Paketidentität zuordnen, wie hier gezeigt (in Visual Studio 2019 immens einfacher). Dies sollte jedoch nicht erforderlich sein, um die Windows.UI.Xaml.Media.Imaging.SvgImageSourceKlasse zu verwenden .

Verbrauch (wenn Sie auf UWP oder Sie haben die Richtungen oben und hinzugefügt XAML Insel Unterstützung unter WPF) gefolgt ist so einfach wie die Einstellung Sourcefür ein <Image />auf dem Weg zum SVG. Dies entspricht der folgenden Verwendung SvgImageSource:

<Image>
    <Image.Source>
        <SvgImageSource UriSource="Assets/svg/icon.svg" />
    </Image.Source>
</Image>

Auf diese Weise geladene SVG-Bilder (über XAML) können jedoch gezackt / aliasiert geladen werden . Eine Abhilfe ist , eine zu spezifizieren RasterizePixelHeightoder RasterizePixelWidthWert, der doppelt + ist Ihre tatsächliche Höhe / Breite:

<SvgImageSource RasterizePixelHeight="300" RasterizePixelWidth="300" UriSource="Assets/svg/icon.svg" /> <!-- presuming actual height or width is under 150 -->

Dies kann dynamisch umgangen werden, indem SvgImageSourceim ImageOpenedEreignis für das Basis-Image ein neues erstellt wird:

var svgSource = new SvgImageSource(new Uri("ms-appx://" + Icon));
PrayerIcon.ImageOpened += (s, e) =>
{
    var newSource = new SvgImageSource(svgSource.UriSource);
    newSource.RasterizePixelHeight = PrayerIcon.DesiredSize.Height * 2;
    newSource.RasterizePixelWidth = PrayerIcon.DesiredSize.Width * 2;
    PrayerIcon2.Source = newSource;
};
PrayerIcon.Source = svgSource;

Das Aliasing ist auf Bildschirmen ohne hohe Auflösung möglicherweise schwer zu erkennen, aber hier ist ein Versuch, es zu veranschaulichen.

Dies ist das Ergebnis des obigen Codes: ein Code Image, der die Initiale verwendet SvgImageSource, und eine Sekunde Imagedarunter, die die in der .vv erstellte SvgImageSource verwendetImageOpened Ereignis :

Geben Sie hier die Bildbeschreibung ein

Dies ist eine vergrößerte Ansicht des oberen Bildes:

Geben Sie hier die Bildbeschreibung ein

Während dies eine vergrößerte Ansicht des unteren (antialiased, korrekt) Bildes ist:

Geben Sie hier die Bildbeschreibung ein

(Sie müssen die Bilder in einem neuen Tab öffnen und in voller Größe anzeigen, um den Unterschied zu erkennen.)

Mahmoud Al-Qudsi
quelle
14
SvgImageSource ist leider eine UWP-Bibliothek, keine WPF.
Adam_0
5
Dies ist UWP, nicht WPF. Sie verwirren XAML
juFo
3

Sie können das resultierende xaml aus der SVG als Zeichenpinsel für ein Rechteck verwenden. Etwas wie das:

<Rectangle>
   <Rectangle.Fill>
      --- insert the converted xaml's geometry here ---
   </Rectangle.Fill>
</Rectangle>
Gus Cavalcanti
quelle
3
Gleiches Problem wie in der ersten Antwort. Ich möchte nicht jedes Mal kopieren und einfügen, wenn ich das gleiche SVG verwenden möchte.
NVM
0

Wir können den Pfadcode direkt aus dem SVG-Code verwenden:

    <Path>
        <Path.Data>
            <PathGeometry Figures="M52.8,105l-1.9,4.1c ... 
Soleil - Mathieu Prévot
quelle
0

Eine weitere Alternative ist dotnetprojects SVGImage

Dies ermöglicht die native Verwendung von .svg-Dateien direkt in xaml.

Das Schöne ist, es ist nur eine Baugruppe, die ungefähr 100k ist. Im Vergleich zu Scharfschützen, die viel größer sind als viele Dateien.

Verwendung:

...
xmlns:svg1="clr-namespace:SVGImage.SVG;assembly=DotNetProjects.SVGImage"
...
<svg1:SVGImage Name="mySVGImage" Source="/MyDemoApp;component/Resources/MyImage.svg"/>
...

Das ist alles.

Sehen:

Markus
quelle