Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
XamlWriter tut Bindings von per Code generierten WPF-Controls nicht serialisieren
Brendan
myCSharp.de - Member



Dabei seit:
Beiträge: 39

Themenstarter:

XamlWriter tut Bindings von per Code generierten WPF-Controls nicht serialisieren

beantworten | zitieren | melden

Wir versuchen derzeit mit VS 2013 und WPF einen WPF-Window-Designer zu programmieren.
In dieser App werden controls zur laufzeit erstellt und auf einem Canvas abgelegt.
Darüberhinaus werden die Eigenschaften und Bindings im Code eingestellt.
Zu guter Letzt wollen wir das Canvas und die darauf befindlichen Controls serialisieren, wofür wir den XamlWriter verwenden:

    public string SerializeControlToXaml(FrameworkElement control)
    {
        StringBuilder outstr = new StringBuilder();
    
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.OmitXmlDeclaration = true;
        XamlDesignerSerializationManager dsm =
            new XamlDesignerSerializationManager(XmlWriter.Create(outstr, settings));
        dsm.XamlWriterMode = XamlWriterMode.Expression;
        System.Windows.Markup.XamlWriter.Save(control, dsm);
    
        string xaml = outstr.ToString();
        return xaml;
    }

Der "control" Parameter beinhaltet das Canvas und ist der Parent für alle code-behind erstellten Controls.
Unter anderem erstellen wir TextBoxen, die an SelectedItem und eine Column von einem DataGrid gebunden sind.

 private void CreateTextboxes()
    {
        CreateTextbox("firstname", _datagridname, "SelectedItem.vorname", 220, 10);
        CreateTextbox("familyname", _datagridname, "SelectedItem.nachname", 220, 40);
    }

    private void CreateTextbox(string name, string sourceName, string path, double leftPos, double topPos)
    {
        TextBox tb = new TextBox();
        tb.SetValue(Canvas.LeftProperty, leftPos);
        tb.SetValue(Canvas.TopProperty, topPos);
        tb.Width = 150;
        tb.Name = name;
    
        // Binding to the selected item of the DataGrid.
        Binding tbbinding = new Binding();
        FrameworkElement sourceElement;
        ControlList.TryGetValue(sourceName, out sourceElement);
        if (sourceElement != null)
        {
            tbbinding.Source = sourceElement;
        }
        tbbinding.Path = new PropertyPath(path);
        tb.SetBinding(TextBox.TextProperty, tbbinding);
    
        _canvasPanel.Children.Add(tb);
    
        // The new TextBox is added to the Controllist.
        ControlList.Add(name, tb);
    }

Am Ende haben wir zwei TextBoxen, die an die DataGrid-Columns "firstname" und "familyname" gebunden sind.
Der Parameter "sourceName" enthält den Namen des DataGrid-Controls.
Wenn man mit zur Laufzeit generierten Controls arbeitet, muss man beim Binding einer TextBox anstelle von ElementName die Source-Eigenschaft setzen.
Diese bekommt - wie man im Code sieht - den DataGrid.

Wenn wir nun das Parent/Canvas serialisieren, fehlen die Bindings:
    <Canvas Background="#FFF0F8FF" Name="DropInCanvas" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sd="clr-namespace:System.Data;assembly=System.Data" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
      <DataGrid CanUserAddRows="False" AutoGenerateColumns="True" Name="datagrid1" Canvas.Left="20" Canvas.Top="10">
        <DataGrid.ItemBindingGroup>
          <BindingGroup Name="{x:Null}" NotifyOnValidationError="False" ValidatesOnNotifyDataError="True" SharesProposedValues="True" />
        </DataGrid.ItemBindingGroup>
        <sd:DataRowView />
        <sd:DataRowView />
        <sd:DataRowView />
        <sd:DataRowView />
      </DataGrid>
      <TextBox Name="firstname" Width="150" Canvas.Left="220" Canvas.Top="10" xml:space="preserve"></TextBox>
      <TextBox Name="familyname" Width="150" Canvas.Left="220" Canvas.Top="40" xml:space="preserve"></TextBox>
    </Canvas>

Weiß jemand warum das so ist und was man eventuell dagegen tun kann?

Danke im voraus!

Brendan
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von Brendan am .
Die Lösung ist immer ganz einfach.
Nur der Weg dorthin ist schwierig!

Moderationshinweis von Coffeebean (31.03.2016 - 08:05:22):

Bitte benutze (die richtigen) Code-Tags

private Nachricht | Beiträge des Benutzers
Stu42
myCSharp.de - Member



Dabei seit:
Beiträge: 506
Herkunft: Aus dem Norden

beantworten | zitieren | melden

Schau mal hier http://www.codeproject.com/Articles/27158/XamlWriter-and-Bindings-Serialization
private Nachricht | Beiträge des Benutzers
Brendan
myCSharp.de - Member



Dabei seit:
Beiträge: 39

Themenstarter:

beantworten | zitieren | melden

Danke, den Artikel habe ich heute Morgen bei meinen Nachforschungen ebenfalls entdeckt.
Einziges Problem:
Wenn man bei dem Binding für die TextBox Elementname anstelle von Source setzt, wird das Binding korrekt serialisiert.
Tut man jedoch - was bei generisch erzeugten Controls in diesem Fall zwingend notwendig ist - der Source-Eigenschaft den Datagrid zuweisen, steht nach der Serialisierung im Binding nur der Path und die Source fehlt.
Die Lösung ist immer ganz einfach.
Nur der Weg dorthin ist schwierig!
private Nachricht | Beiträge des Benutzers
Stu42
myCSharp.de - Member



Dabei seit:
Beiträge: 506
Herkunft: Aus dem Norden

beantworten | zitieren | melden

Wenn du das Binding im Code-Behind erstellt und dort die Source auf ein Objekt setzt, wie soll er das denn überhaubt speichern können? Im Xaml kann man doch auch nicht einfach ein Objekt als Source angeben.
private Nachricht | Beiträge des Benutzers