简体   繁体   中英

Update a listview from modify on selected items

Excuse me if I didn't formulate good the question, but don't know how to name it better...

I have a project with some ListView, binded to ObservableCollection. When I make a right click on my ListView, to change name, or other parameter, the ListView doesn't automatically refresh until I go out, then open again.

Here is my behind code for context :

public class Contexte : INotifyPropertyChanged
    {
        private Affaire affaireSelectionnee;
        public Affaire AffaireSelectionnee
        {
            get { return affaireSelectionnee; }
            set
            {
                if (value == affaireSelectionnee) return;
                affaireSelectionnee = value;
                NotifyPropertyChanged("AffaireSelectionnee");
            }
        }

        private ObservableCollection<Affaire> listeDesAffairesSelectionnees;
        public ObservableCollection<Affaire> ListeDesAffairesSelectionnees
        {
            get { return listeDesAffairesSelectionnees; }
            set { NotifyPropertyChanged(ref listeDesAffairesSelectionnees, value); }
        }
        private ObservableCollection<Phase> listeDesPhasesSelectionnees;
        public ObservableCollection<Phase> ListeDesPhasesSelectionnees
        {
            get { return listeDesPhasesSelectionnees; }
            set { NotifyPropertyChanged(ref listeDesPhasesSelectionnees, value); }
        }
        private ObservableCollection<Assemblage> listeDesAssemblagesSelectionnees;
        public ObservableCollection<Assemblage> ListeDesAssemblagesSelectionnees
        {
            get { return listeDesAssemblagesSelectionnees; }
            set { NotifyPropertyChanged(ref listeDesAssemblagesSelectionnees, value); }
        }
        private ObservableCollection<Repere> listeDesReperesSelectionnees;
        public ObservableCollection<Repere> ListeDesReperesSelectionnees
        {
            get { return listeDesReperesSelectionnees; }
            set { NotifyPropertyChanged(ref listeDesReperesSelectionnees, value); }
        }

        private ObservableCollection<Affaire> listeDesAffaires;
        public ObservableCollection<Affaire> ListeDesAffaires
        {
            get { return listeDesAffaires; }
            set { NotifyPropertyChanged(ref listeDesAffaires, value); }
        }
        private ObservableCollection<Phase> listeDesPhases;
        public ObservableCollection<Phase> ListeDesPhases
        {
            get { return listeDesPhases; }
            set { NotifyPropertyChanged(ref listeDesPhases, value); }
        }
        private ObservableCollection<Assemblage> listeDesAssemblages;
        public ObservableCollection<Assemblage> ListeDesAssemblages
        {
            get { return listeDesAssemblages; }
            set { NotifyPropertyChanged(ref listeDesAssemblages, value); }
        }
        private ObservableCollection<Repere> listeDesReperes;
        public ObservableCollection<Repere> ListeDesReperes
        {
            get { return listeDesReperes; }
            set { NotifyPropertyChanged(ref listeDesReperes, value); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string nomPropriete)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(nomPropriete));
        }

        private bool NotifyPropertyChanged<T>(ref T variable, T valeur, [CallerMemberName] string nomPropriete = null)
        {
            if (object.Equals(variable, valeur)) return false;

            variable = valeur;
            NotifyPropertyChanged(nomPropriete);
            return true;
        }

    }

I load the context once when loading the programm :

DBConnect DataBase = new DBConnect();
string requete = "SELECT * FROM affaire ORDER BY ID";
List<Affaire> liste = DataBase.Select_affaire(requete, true);
contexte = new Contexte { ListeDesAffaires = new ObservableCollection<Affaire>(liste), ListeDesPhases = new ObservableCollection<Phase>(), ListeDesAssemblages = new ObservableCollection<Assemblage>(), ListeDesReperes = new ObservableCollection<Repere>(), AffaireSelectionnee = new Affaire(), ListeDesAffairesSelectionnees = new ObservableCollection<Affaire>(liste), ListeDesPhasesSelectionnees = new ObservableCollection<Phase>(), ListeDesAssemblagesSelectionnees = new ObservableCollection<Assemblage>(), ListeDesReperesSelectionnees = new ObservableCollection<Repere>() };
DataContext = contexte;

Then my function that may update property :

foreach (Phase ph in contexte.ListeDesPhasesSelectionnees)
{
  Phase ph_find = contexte.ListeDesPhases.First(s=>s==ph);
  ph_find.Priorite = new_priorite;
}

ph_find.Priorite is well updated, as is my Observable Collection "contexte.ListeDesPhases", but no refresh is made on the ListView.

Edit : Well I could solve the problem adding a ListView1.Items.Refresh()... I am not sure this is the most correct way(is not bidding supposed to refresh the listview automaticaly?), but for now it works

Edit2 :

My XAML code (ListView of the phase) :

<ListView x:Name="ListView2" ItemsSource="{Binding ListeDesPhases}" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="4" MouseDoubleClick="ListView_MouseDoubleClick" GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler" SelectionChanged="ListView_SelectionChanged" >

            <ListView.View>

                <GridView AllowsColumnReorder="true" x:Name="GridView2">
                    <GridViewColumn DisplayMemberBinding="{Binding ID}" Header="ID" Width="50"/>
                    <GridViewColumn DisplayMemberBinding= "{Binding NomPhase}" Header="{x:Static p:Resources.Nom}" Width="200"/>
                    <GridViewColumn DisplayMemberBinding="{Binding IdAffaire}" Header="{x:Static p:Resources.IdAffaire}" Width="100"/>
                    <GridViewColumn DisplayMemberBinding="{Binding CommPhase}" Header="{x:Static p:Resources.Commentaire}" Width="100"/>
                    <GridViewColumn DisplayMemberBinding="{Binding Priorite}" Header="{x:Static p:Resources.Priorite}" Width="100"/>
                </GridView>
            </ListView.View>
        </ListView>

My Phase class :

public class Phase
    {
        public string NomPhase { get; set; }
        public long IdAffaire { get; set; }
        public string CommPhase { get; set; }
        public int Priorite { get; set; }
        public long ID { get; set; }
        public List<Assemblage> ListAssemblages { get; set; }
        public Phase()
        {
            this.NomPhase = "";
            this.IdAffaire = 0;
            this.CommPhase = "";
            this.Priorite = 0;
            this.ID = 0;
            this.ListAssemblages = new List<Assemblage>();
        }
        ...
    }

Edit3 :

Tried to modify as indicated by Netstep, but still the same :

public ObservableCollection<Phase> ListeDesPhases
        {
            get { return listeDesPhases; }
            set { NotifyPropertyChanged(ref listeDesPhases, value);
                NotifyPropertyChanged("Priorite");
            }
        }

Edit 4 :

Well, I now understand that nothing was happening, I read that course http://www.wpf-tutorial.com/data-binding/responding-to-changes/ to understand it... So example given by NetStep was the good one (just didn't understand what is the RaisePropertyChanged(() => Priorite); part? Is this due to the use of mvvmlight.net library?

public class Phase : INotifyPropertyChanged
    {
        private string nomPhase;
        public string NomPhase
        {
            get { return this.nomPhase; }
            set
            {
                if (this.nomPhase != value)
                {
                    this.nomPhase = value;
                    this.NotifyPropertyChanged("NomPhase");
                }
            }
        }
        private int priorite;
        public int Priorite
        {
            get { return this.priorite; }
            set
            {
                if (this.priorite != value)
                {
                    this.priorite = value;
                    this.NotifyPropertyChanged("Priorite");
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        public void NotifyPropertyChanged(string propName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    ...//all of my other functions
    }

So this is what I did and it works good now.

Then I have the following question : I have 4 different objects displayed in 4 ListView(Contract, Subcontract, Phase and Detail). Contract is the "Mother Class", it countains parameters, but also contains a list of Subcontracts. Subcontracts contains several parameters, and a list of Phases, and each Phase contains some parameters, with a list of Details. Each of them is displayed in a different ListView(4 ListView). May I define 4 different ObservableCollection, or is there a way to define only one ObservableCollection for all the "tree", then bind on parameters of my ObservableCollection>?

To have the field properly updated in UI, please ensure that Phase class also implement INotifyPropertyChanged someway and call

NotifyPropertyChanged("Priorite")

in set accessor. Just using the ObservableCollection is not enough, it handles notifying only Add/Remove operations. And you right - ListView1.Items.Refresh() is a workaround in this case. Hope this will help, otherwise please share Phase class code and your xaml code to get more clear comment/answer.

Here is the example, based on MVVM light library:

using GalaSoft.MvvmLight;

namespace WpfApp1
{
    public class Phase : ViewModelBase
    {
        private int _priorite;

        public int Priorite
        {
            get { return _priorite; }
            set
            {
                _priorite = value;
                RaisePropertyChanged(() => Priorite);
            }
        }
    }
}

All the rest of code can remain unchanged. You also can inherit you Context class from ViewModelBase

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM