none
Erhalte keine BindingExpression bei Zugriff auf CustomControl-Eigenschaft mit GetBindingExpression RRS feed

  • Frage

  • Hallo,

    Ich habe mit VS2015 ein WPF-CustomControl namens CustomTextBox gemacht, das von der TextBox erbt.

    Dieses CustomControl verwende ich in einem dynamischen WPF-Maskendesigner, wo man aus einem WPF-Window mit Controls (einer Art Toolbox), diejenigen, die man braucht, auf ein zweites WPF-Window (das als Entwurfsfenster dient) zieht.

    Nach dem Ablegen eines Controls bzw. Rechtsklick und Auswahl im Kontextmenü wird ein Dialogfenster zum Anpassen der Einstellungen geöffnet.

    Hier kann man zu jedem Control, das man auf das Designfenster gezogen hat Schriftgröße, Ausrichtung und die Datenbindung einstellen.

    Abschließend kann der Anwender seinen fertigen Entwurf des WPF-Fensters als XML-Datei serialisieren und später wieder laden.

    Wenn man nach dem Wiederladen das Dialogfenster für die Einstellungen eines bestimmten Controls öffnet gibt es keine größeren Probleme mithilfe von Reflection Eigenschaften wie Text, Schriftart und Ausrichtung herauszulesen.

    Die Ermittlung des Bindings aber, stellt anscheinend ein größeres Problem dar.

    Ich habe folgende Varianten zur Ermittlung ausprobiert, bekomme aber für das Text-Property entweder keine FieldInfo (erste Variante) oder aber keine BindingExpression (zweite Variante).

    Kleine Anmerkung: element ist ein FrameworkElement.

    Variante 1:

                foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(element))
                {
                    string pdName = propertyDescriptor.Name;
                    FieldInfo fieldInfo = element.GetType().GetField(propertyDescriptor.Name + "Property");
                    if (fieldInfo == null)
                        continue;
                    DependencyProperty dependencyProperty = fieldInfo.GetValue(element) as DependencyProperty;
                    if (dependencyProperty == null)
                        continue;
                    BindingExpression bindingExpression = element.GetBindingExpression(dependencyProperty);
                    if (bindingExpression == null)
                        continue;
    
                    ////TODO
                }


    Variante 2:

                foreach (var field in element.GetType().GetFields())
                {
                    DependencyProperty dependencyProperty = field.GetValue(element) as DependencyProperty;
                    if (dependencyProperty != null)
                    {
                        BindingExpression bindingExpression = element.GetBindingExpression(dependencyProperty);
                        if (bindingExpression != null)
                        {
                            string test = "";
                            ////TODO
                        }
                    }
                }

    Gibt es eventuell einen Fehler in meinem CustomControl, dessen ich mir nicht bewusst bin?

    Hier die Definition aus Generic.xaml:

        <!--Style for the CustomControl CustomTextBox-->
        <Style TargetType="{x:Type local:CustomTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
        </Style>

    Und das CustomControl selbst:

    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfDesignerCustomControlLibrary
    {
        /// <summary>
        /// Class for a CustomControl which inherits from TextBox and adds additional properties.
        /// </summary>
        public class CustomTextBox : TextBox
        {
            /// <summary>
            /// The constructor.
            /// </summary>
            static CustomTextBox()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomTextBox), new FrameworkPropertyMetadata(typeof(CustomTextBox)));
            }
    
            /// <summary>
            /// DependencyProperty for external access to the property TableName.
            /// </summary>
            public static readonly DependencyProperty TableNameProperty =
                DependencyProperty.Register("TableName", typeof(string), typeof(CustomTextBox));
    
            /// <summary>
            /// Gets or sets the name of the datatable which is the datasource.
            /// </summary>
            public string TableName
            {
                get { return (string)GetValue(TableNameProperty); }
                set { SetValue(TableNameProperty, value); }
            }
        }
    }


    Und zum Schluss noch ein Ausschnitt aus dem serialisierten XML, das wiedergeladen werden kann:

        <wdccl:CustomTextBox TableName="table1" TextWrapping="Wrap" Text="{Binding Path=[0][Column1], UpdateSourceTrigger=PropertyChanged, FallbackValue=Could not find the specified path!}" TextAlignment="Left" FontSize="12" FontStyle="Normal" FontWeight="Bold" HorizontalContentAlignment="Left" VerticalContentAlignment="Top" Width="150" Margin="0,0,0,0" Canvas.Left="100" Canvas.Top="20">
          <wdccl:CustomTextBox.TextDecorations>
            <x:Null />
          </wdccl:CustomTextBox.TextDecorations>
          <wdccl:CustomTextBox.ContextMenu>
            <ContextMenu HorizontalOffset="0" VerticalOffset="0" Placement="MousePoint">
              <MenuItem Header="Edit" />
            </ContextMenu>
          </wdccl:CustomTextBox.ContextMenu>
        </wdccl:CustomTextBox>
    

    Dienstag, 10. Mai 2016 12:10

Antworten

  • Da ich sowieso mit CustomControls arbeite und die Ergebnisse von GetBindingExpression teilweise sehr ambivalent sind, habe ich mich für den einfachsten Weg entschieden und meinen Controls ein neues DependencyProperty hinzugefügt, das den Pfad aufnimmt und aus dem man ihn per Reflection problemlos wieder auslesen kann.

    Für die Source hatte ich ja bereits das DependencyProperty "TableName".

    Mittwoch, 11. Mai 2016 11:02

Alle Antworten

  • Noch ein kurzer Nachtrag zu meiner Frage.

    Wie es scheint, muss ich im Generic.xaml den Style für CustomTextBox erweitern und im Code des CustomControls das DependencyProperty TextProperty überschreiben.

    Unter diesen Bedingungen wird mit Hilfe der obigen Variante-1 die BindingExpression von dem Property Text gefunden.

    Normalerweise sollte es nicht nötig sein, DependencyProperties von dem Parent-Control zu überschreiben, es sei denn, man möchte über FrameworkPropertyMetadata andere Defaultwerte einstellen.

    Ist das, was ich da nun mache korrekt oder bin ich auf dem Holzweg?

    Hier der neue Style für CustomTextBox:

        <Style TargetType="{x:Type local:CustomTextBox}" BasedOn="{StaticResource {x:Type TextBox}}">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:CustomTextBox}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                            <TextBox HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
                                     VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
                                     Text="{TemplateBinding Text}">
                            </TextBox>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    

    Und der Code vom CustomControl:

    using System.Windows;
    using System.Windows.Controls;
    
    namespace WpfDesignerCustomControlLibrary
    {
        /// <summary>
        /// Class for a CustomControl which inherits from TextBox and adds additional properties.
        /// </summary>
        public class CustomTextBox : TextBox
        {
            /// <summary>
            /// The constructor.
            /// </summary>
            static CustomTextBox()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomTextBox), new FrameworkPropertyMetadata(typeof(CustomTextBox)));
            }
    
            /// <summary>
            /// DependencyProperty for external access to the property TableName.
            /// </summary>
            public static readonly DependencyProperty TableNameProperty =
                DependencyProperty.Register("TableName", typeof(string), typeof(CustomTextBox));
    
            /// <summary>
            /// Overrides the TextProperty of TextBox.
            /// Is needed for GetBindingExpression.
            /// </summary>
            public static readonly new DependencyProperty TextProperty =
                DependencyProperty.Register("Text", typeof(string), typeof(CustomTextBox));
    
            /// <summary>
            /// Gets or sets the name of the datatable which is the datasource.
            /// </summary>
            public string TableName
            {
                get { return (string)GetValue(TableNameProperty); }
                set { SetValue(TableNameProperty, value); }
            }
    
            /// <summary>
            /// Overrides the Text-property of TextBox.
            /// Is needed for GetBindingExpression.
            /// </summary>
            public new string Text
            {
                get { return (string)GetValue(TextProperty); }
                set { SetValue(TextProperty, value); }
            }
        }
    }
    

    Dienstag, 10. Mai 2016 14:48
  • Da ich sowieso mit CustomControls arbeite und die Ergebnisse von GetBindingExpression teilweise sehr ambivalent sind, habe ich mich für den einfachsten Weg entschieden und meinen Controls ein neues DependencyProperty hinzugefügt, das den Pfad aufnimmt und aus dem man ihn per Reflection problemlos wieder auslesen kann.

    Für die Source hatte ich ja bereits das DependencyProperty "TableName".

    Mittwoch, 11. Mai 2016 11:02