Autor Beitrag
haschme
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Mo 04.06.18 12:20 
Hallo zusammen,

ich habe nun schon seit längerem versucht eine Lösung zu finden aber bisher waren all meine Versuche erfolglos.
Es geht darum das ich Daten einer Klasse von meinem View zu einem UserControl per Binding an einer DependencyProperty übergeben will.
Die Bindung hat auch funktioniert jedoch werden jedesmal beim abfeuern der Callback-Methode der DP leere Strings als NewValue übergeben.
Die angebundene Eigenschaft ist aber zu diesem Zeitpunkt definitv gefüllt. (Das weiß ich da die Bindung zum gleichen Zeitpunkt an einem DataGrid ohne DP funktioniert)

Vielleicht hat ja jemand eine Idee was das Problem hier sein könnte.
Anbei ein wenig Code zum verdeutlichen.

Diese Klasse enthält die Property "Name" das ist die Eigenschaft die ich im Binding übergeben will (wohingegen ein leerer String übergeben wird)
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
    public class Field : ObservableObject
    {
        public Field()
        {
            Name = string.Empty;
        }

        private string name = string.Empty;
        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
                RaisePropertyChanged();
            }
        }
  }


Diese Klasse enthält eine Collection der anzubindenen Felder
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
    public class MYObservableObjectFieldHolder : ObservableObject
    {
        public MYObservableObjectFieldHolder()
        {
            Fields = new ObservableCollection<Field>();
        }

        public ObservableCollection<Field> Fields
        {
            get;
            set;
        }
  }


Hier ist der XAML-Code meines Views (dieser soll das UserControl: "UC_MyUserControl" ansteuern und die Namen der Felder an die
DependencyProperty FieldName übergeben (binding)
In dem WrapPanel sollen dann abhängig von der Anzahl an Feldern je ein UserControlObjekt mit dem jeweiligen Feldnamen angezeigt werden.
ausblenden XML-Daten
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
        <ItemsControl DataContext="{Binding MyFieldHolderObject}" ItemsSource="{Binding Fields}" Margin="20,243,20,20">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
              
                    <Controls:UC_MyUserControl FieldName="{Binding Name, Mode=TwoWay}"/> 
          
                </DataTemplate>
        
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel>
                    </WrapPanel>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>


Hier ein Auszug aus dem betroffenen UserControl: "UC_MyUserControl".
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
    public string FieldName
        {
            get { return (string)GetValue(FieldNameProperty); }
            set
            {
                SetValue(FieldNameProperty, value);
            }
        }
    
    
    
    public readonly static DependencyProperty FieldNameProperty =
                DependencyProperty.Register(
                    "FieldName",
                    typeof(string),
                    typeof(UC_MyUserControl),
                    new FrameworkPropertyMetadata(null,
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                    OnFieldNamePropertyChanged)
                 );
         
         
         
    private static void OnFieldNamePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            (obj as UC_MyUserControl).OnFieldNamePropertyChanged(e);
        }     
         
         
         
    private void OnFieldNamePropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            FieldName = (string)e.NewValue;
        }


Vielleicht hatte ja schonmal jemand die gleichen Probleme und kann mir dabei helfen.

Viele Grüße!
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Mo 04.06.18 19:53 
Ich hab keine Antwort auf die Frage, aber eventuell die Lösung für dein Problem:

Lass einfach die ganze "OnFieldNamePropertyChanged"-Methode weg, die brauchst Du nicht.
FieldName fragt den Wert im get schon ganz von alleine ab, die GetValue-Methode tut das.

Ich könnte mir auch vorstellen, dass dadurch dein Problem entsteht, denn sobald der Wert aus der View gesetzt wird, wird die Callback-Methode aufgerufen, die den Wert ändert, was die Callback-Methode aufruft, was den Wert ändert, ...
Du siehst das Problem? ;)

Für diesen Beitrag haben gedankt: haschme
haschme Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Di 05.06.18 09:31 
Danke schonmal für den Tipp.
Ich habe die CallBack-Methode jetzt entfernt.
Dabei fällt mir auf, dass in der Eigenschaft FieldName nie das set erreicht wird.

Die DependencyProperty scheint auch an sich korrekt zu sein, denn wenn ich
im XAML-Code den FeldNamen änder (ohne Binding) dann wird der FeldName korrekt übernommen.

ausblenden XML-Daten
1:
2:
3:
4:
5:
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Controls:UC_MyUserControl FieldName="Ich bin ein Feld" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>


Ich verstehe einfach nicht wieso nicht das selbe beim Binding passiert.
Beim Binding wird doch im Prinzip auch nur ein String übergeben oder? :o

ausblenden XML-Daten
1:
2:
3:
4:
5:
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Controls:UC_MyUserControl FieldName="{Binding Name, Mode=TwoWay}" />
                </DataTemplate>
            </ItemsControl.ItemTemplate>
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Di 05.06.18 09:43 
WPF ruft für den generierten XAML-Code immer direkt die SetValue-Methode auf, daher wird niemals (außer per eigenem Code) die Property-Set-Methode aufgerufen (dies ist auch der Grund warum man außer SetValue nichts anderes im Setter implementieren sollte: Don’t Add Code to Dependency Property Getter/Setter).

Für diesen Beitrag haben gedankt: haschme
Palladin007
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 1282
Erhaltene Danke: 182

Windows 11 x64 Pro
C# (Visual Studio Preview)
BeitragVerfasst: Di 05.06.18 11:24 
Wie Th69 schon sagt:
WPF arbeitet nicht mit deiner selbst implementierten Property, sondern mit einem internen Speicher für die Werte, Du kannst mit den Methoden GetValue und SetValue genau diesen Speicher manipulieren. Da das aber nicht sehr schön in der Nutzung ist, implementieren man meistens eine Property, die das tut und gleichzeitig typisiert ist.

Wenn Du Code für eine Änderung ausführen möchtest, dann war die Callback-Methode schon richtig, nur die Zuweisung der Property darf da nicht sein.

Für diesen Beitrag haben gedankt: haschme
haschme Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Di 05.06.18 11:46 
user profile iconPalladin007 hat folgendes geschrieben Zum zitierten Posting springen:
Wie Th69 schon sagt:
WPF arbeitet nicht mit deiner selbst implementierten Property, sondern mit einem internet Speicher für die Werte, Du kannst mit den Methoden GetValue und SetValue genau diesen Speicher manipulieren. Da das aber nicht sehr schön in der Nutzung ist, implementieren man meistens eine Property, die das tut und gleichzeitig typisiert ist.

Wenn Du Code für eine Änderung ausführen möchtest, dann war die Callback-Methode schon richtig, nur die Zuweisung der Property darf da nicht sein.


Danke nochmal, da habe ich wieder was dazugelernt :les:

Wie du schon geschrieben hast kann ich dann wohl auf die CallBack verzichten da ich keinen weiteren Code ausführen möchte.
Ich möchte nur, dass wenn sich die DependencyProperty ändert, auch der jeweils angezeigte String im View des UserControls ändert. Deshalb habe ich die DependencyProperty an den UserControlView gebunden. Das UserControl spiegelt wiederum ein einzelnes Item in meinem WrapPanel aus dem MainView wieder.
haschme Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 57
Erhaltene Danke: 1



BeitragVerfasst: Di 12.06.18 13:34 
So ich kam jetzt doch endlich weiter mit meinem vorhaben.
Nun funktioniert mein Binding zur DependencyProperty korrekt.

Geholfen hat mir der folgende Link:
stackoverflow.com/qu...a-usercontrol-in-wpf

Ich hatte dummerweise im Konstruktor des UserControls den DataContext gesetzt.
Des Weiteren musste ich beim Binding meines Feldnamens den ElementName auf den Namen des UserControls setzen.

Damit kann dieser Beitrag geschlossen werden. :-)