Laden...

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

Erstellt von Brendan vor 8 Jahren Letzter Beitrag vor 8 Jahren 2.376 Views
B
Brendan Themenstarter:in
39 Beiträge seit 2006
vor 8 Jahren
XamlWriter tut Bindings von per Code generierten WPF-Controls nicht serialisieren

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


Hinweis von Coffeebean vor 8 Jahren

Bitte benutze (die richtigen) Code-Tags

Die Lösung ist immer ganz einfach.
Nur der Weg dorthin ist schwierig!

S
506 Beiträge seit 2006
vor 8 Jahren
B
Brendan Themenstarter:in
39 Beiträge seit 2006
vor 8 Jahren

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!

S
506 Beiträge seit 2006
vor 8 Jahren

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.