Laden...

Binding manuell refresehen

Erstellt von _daniel_ vor 14 Jahren Letzter Beitrag vor 14 Jahren 2.653 Views
_
_daniel_ Themenstarter:in
227 Beiträge seit 2006
vor 14 Jahren
Binding manuell refresehen

Hallo,
ich habe eine ObservableCollection<MyObject> als Property in meinem DataContext.

Leider kann ich bei MyObject das INotifyPropertyChanged nicht implementieren, wesshalb ich das Binding manuell "refreshen" möchte.

Gebunden ist in XAML so:

DataContext="{Binding Path=.}" ItemsSource="{Binding Path=Prop}" 

bisher habe ich folgendes schon gefunden/versucht:

listview.GetBindingExpression(ListView.ItemsSourceProperty).UpdateTarget()

leider tut sich dabei garnichts. (mit ListView.DataContextProperty leider auch nicht)

hat noch wer Ideen?

N
85 Beiträge seit 2007
vor 14 Jahren

prinzipiell gibt es für bindings eine art, das ganze manuell zu refreshen,
und zwar über den UpdateSourceTrigger.

hier ein kleines beispiel

<TextBox x:name="TextBox" Text="{Binding Path=Text, UpdateSourceTrigger=Explicit}" />
BindingExpression be = TextBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();

so funktioniert es im normalfall 😉

_
_daniel_ Themenstarter:in
227 Beiträge seit 2006
vor 14 Jahren

Ja, genau das beispiel findet sich überall.

Nur welches ist das richtige Property für das ListView?

Als "workaround" klappt den DataContext auf null anschließend wieder setzten. Aber ich glaube noch schmutziger gehts wohl nicht 😉

U
1.578 Beiträge seit 2009
vor 14 Jahren

Hallo,
ich habe eine ObservableCollection<MyObject> als Property in meinem DataContext.

Leider kann ich bei MyObject das INotifyPropertyChanged nicht implementieren, wesshalb ich das Binding manuell "refreshen" möchte.

Gebunden ist in XAML so:

DataContext="{Binding Path=.}" ItemsSource="{Binding Path=Prop}"   

bisher habe ich folgendes schon gefunden/versucht:

listview.GetBindingExpression(ListView.ItemsSourceProperty).UpdateTarget()  

leider tut sich dabei garnichts. (mit ListView.DataContextProperty leider auch nicht)

hat noch wer Ideen?

hi ,
ja ich hab ne idee
kapsel das MyObject selber nochmal weg und arbeite nur noch darrueber

class MyObject {} <-- das objekt was du binden willst aber nicht aendern kannst


class MyObjectViewModel : INotifyPropertyChanged
{
    private MyObject _innerObject { get; set; }
    public MyObjectViewModel(MyObject innerObject)
    {
        _innerObject = innerObject
    }
    public string Name
    {
        get { return _innerObject.Name; }
        set
        {
            _innerObject.Name = value;
            OnPropertyChanged(this, "Name");
        }
    }
}

ist das ganz normale MVVM prinzip

_
_daniel_ Themenstarter:in
227 Beiträge seit 2006
vor 14 Jahren

Hallo,
danke. Genau so hab ich das schon. Nur wenn ich jetzt das innerObject aus der Datenbank refreshe, werden eben nicht die Setter in MyObjectViewModel aufgerufen sondern nur das innerObject aktualisiert.

/edit
hier mal mein Beispiel vollständig:


    public class MyObj
    {
        public string Name { get; set; }
    }

    public class Src : INotifyPropertyChanged
    {
        public ObservableCollection<MyObj> Prop { get; set; }

        public void Changed()
        {
            if (PropertyChanged != null)

                PropertyChanged(this, new PropertyChangedEventArgs("Prop"));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

XAML:


        <ListView Grid.Row="0" DataContext="{Binding Path=.}" ItemsSource="{Binding Path=Prop}" Name="listView" >
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Number Plate" DisplayMemberBinding="{Binding Path=Name}" />
                </GridView>
            </ListView.View>
        </ListView>
        <Button Height="23" Click="button1_Click">Button</Button>

und Code Behind des Windows:


    public partial class Window1 : Window
    {
        Src src = new Src();
        public Window1()
        {
            InitializeComponent();
            src.Prop = new ObservableCollection<MyObj>();
            src.Prop.Add(new MyObj() { Name = "item1" });
            src.Prop.Add(new MyObj() { Name = "item2" });
            src.Prop.Add(new MyObj() { Name = "item3" });
            src.Prop.Add(new MyObj() { Name = "item4" });
            this.DataContext = src;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            src.Prop[2].Name = "! changed item !";
            src.Changed();
        }
    }

Wo hab ich hier nen Denkfehler? 🙁

M
334 Beiträge seit 2007
vor 14 Jahren

MyObj muss auch INotifyPropertyChanged implementieren.

Du änderst ja auch ein Objekt in der Liste und nicht die Liste selbst.

U
1.578 Beiträge seit 2009
vor 14 Jahren

Hallo,
danke. Genau so hab ich das schon.

nein hast du nicht
du hast die gesamte liste gekapselt - das ist quatsch, das macht ObservableCollection bereits
du musst dein "MyObj" selber kapseln und das dann in der liste verwenden

class MyObj
class MyObjViewModel ... (inner = MyObj)
public ObservableCollection<MyObjViewModel> ...

_
_daniel_ Themenstarter:in
227 Beiträge seit 2006
vor 14 Jahren

Ok, stimmt natürlich.

Ändert aber nichts daran, dass _innerMyObj direkt aktualisiert (NhibernateSession.Refresh(..)) wird und die Setter aus dem MyObjViewModel nicht aufgerufen werden.

Es sei denn, ich frag das Objekt neu aus der Datenbank ab und setze Property für Property, was ich mir eigentlich sparen wollte mit einem Binding Refresh 😃

M
334 Beiträge seit 2007
vor 14 Jahren

... Setter aus dem MyObjViewModel nicht aufgerufen werden.

Das ist das Problem. Woher soll das Binding dann wissen dass es aktualisiert werden muss?

Leider kann ich bei MyObject das INotifyPropertyChanged nicht implementieren

warum eigentlich nicht? Hibernate steht da nicht im Weg.

_
_daniel_ Themenstarter:in
227 Beiträge seit 2006
vor 14 Jahren

Das ist das Problem. Woher soll das Binding dann wissen dass es aktualisiert werden muss?

Desshalb möchte ich es ja manuell tun 😃
Das einzigste was bisher funktioniert hat war
DataContext = null;
DataContext = src;

warum eigentlich nicht? Hibernate steht da nicht im Weg.

Weil die Datenobjekte lediglich die Properites ohne zusätzliche Dinge enthalten sollen. Desshalb hab ich ja entsprechende ViewModels.

U
1.578 Beiträge seit 2009
vor 14 Jahren

ach kinder - werdet mal erwachsen #gg

wenn du eine "Refresh" methode hast welche das neue "_innerMyObj" aktualisiert, trigger doch einfach alle notwendigen propertychanges an und feddich is

public void Refresh(MyObj newObj)
{
    _innerMyObj = newObj;
    OnPropertyChanged(this, "Name");
    OnPropertyChanged(this, "Value");
    OnPropertyChanged(this, "ScheissenDreck");
}

dann liest die ui diese aufgelisteten properties neu

_
_daniel_ Themenstarter:in
227 Beiträge seit 2006
vor 14 Jahren

weniger brauchbar bei mehr als einer Handvoll Properties.

M
334 Beiträge seit 2007
vor 14 Jahren

Du hast dich für den unbequemen Weg entschieden. 😃
Lösungsmöglichkeiten sind genug gepostet worden.

U
1.578 Beiträge seit 2009
vor 14 Jahren

das es geht heisst nicht das es auch "richtig" ist {o;
btw
ein neues model erfordert ein neues viewmodel! soviel zum thema "refresh"
wenn du ein neues innerobjekt hast - entferne das komplette viewmodel und pack ein neues rein - aus die maus