Laden...

n:n Enities mit CheckBoxen

Erstellt von Cannon vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.151 Views
C
Cannon Themenstarter:in
282 Beiträge seit 2008
vor 10 Jahren
n:n Enities mit CheckBoxen

Ich habe es hier ins Thema gestellt, weil es weniger um Daten, als um das anbinden der Daten geht. Quelle der Daten ist das Entity Framework.

Es geht um folgendes: Ich habe eine Klasse "User" und eine Klasse "Shops" die beiden Klassen haben n:n Beziehungen. Der Datenzugriff funktioniert. Nur die Frage der zuordnung stellt für mich ein Problem dar, was ich zwar gelöst habe, aber der Code sind durcheinander aus und ist zu kompliziert. Es muss ja eine einfacvhere Lösung geben:

Ich habe auf der linken Seite eine ListBox "User" auf der rechten eine ListBox "Shops". Die ListBox-Shop soll alle Elemente Shops enthalten., aber dem User zuzuordnen sein (mit CheckBox). Aber die Frage ist,w ie sieht die Bindung der ListBox "Shops" aus. bind ich an User.Shops werden natürlich nur die zugeordneten Elemente angezeigt. Binde ich direkt an Shops, fehlt mir die Möglichkeit, mit möglichst wenig Code, die Zuordnung herzustellen. Wie kann man das "elegant" lösen?

W
955 Beiträge seit 2010
vor 10 Jahren

Ich habe das mal so gelöst dass ich ViewData/ViewModel-Objekte, also Daten für die Darstellung dieser Beziehung extra eingeführt habe (hier Schicht und Personal). Wenn eine Schicht ausgewählt wird, werden PersonalProSchicht-Objekte für jedes Personal erstellt und in einer Liste angezeigt. Das IstZugeordnet läßt sich dann an eine Checkbox binden. Alles Personal was zugehörigt ist, startet mit "IsChecked". Wenn die dazugehörige Checkbox geklickt wird wird die dazugehörige Bindung entfernt oder erstellt.
Ich hoffe dass es halbwegs verständklich ist.


    public class PersonalProSchicht : Model
    {
        private bool istZugeordnet;

        public PersonalProSchicht(Personalplanung.Models.Personal ps, Schicht schicht)
        {

            Personal = ps;
            Schicht = schicht;
            IstZugeordnet = Schicht.Personalliste.Any(p => p.Id == ps.Id);
        }

        public bool IstZugeordnet 
        { 
            get {

                return istZugeordnet;
            }
            
            set {

                istZugeordnet = value;

                if (!value) Schicht.Personalliste.Remove(Personal);
                else        Schicht.Personalliste.Add(Personal);
                RaisePropertyChanged("IstZugeordnet");
            }
        }

        public Personalplanung.Models.Personal Personal { get; private set; }
        public Schicht Schicht { get; private set; }

        public String Personalnummer { get { return Personal.Nummer; } }
        public String Personalname { get { return String.Format("{0}, {1}", Personal.Nachname, Personal.Vorname); } }
    }


        <Grid> 
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <TextBlock Style="{StaticResource Header}" Foreground="RoyalBlue">
                Zugeordnetes Personal</TextBlock>
            <DataGrid Grid.Row="1"
                      ItemsSource="{Binding Zuordnungen}" AutoGenerateColumns="False" HeadersVisibility="None" 
                      AlternatingRowBackground="#FFDFF3F5" RowBackground="#FFDFE7F2" GridLinesVisibility="None" 
                      CanUserReorderColumns="False" CanUserResizeColumns="False" CanUserSortColumns="True" SelectionMode="Single" 
                      CanUserResizeRows="False" CanUserDeleteRows="True" CanUserAddRows="True" Background="White">
                <DataGrid.Columns>
                    <DataGridTemplateColumn >
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <CheckBox IsChecked="{Binding IstZugeordnet, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTextColumn IsReadOnly="True" Binding="{Binding Personalnummer}" FontWeight="Bold" />
                    <DataGridTextColumn IsReadOnly="True" Binding="{Binding Personalname}" Width="*" />
                </DataGrid.Columns>
            </DataGrid>
        </Grid>

B
112 Beiträge seit 2008
vor 10 Jahren

Ich habe das mal so gelöst dass ich ViewData/ViewModel-Objekte, also Daten für die Darstellung dieser Beziehung extra eingeführt habe (hier Schicht und Personal). Wenn eine Schicht ausgewählt wird, werden PersonalProSchicht-Objekte für jedes Personal erstellt und in einer Liste angezeigt. Das IstZugeordnet läßt sich dann an eine Checkbox binden. Alles Personal was zugehörigt ist, startet mit "IsChecked". Wenn die dazugehörige Checkbox geklickt wird wird die dazugehörige Bindung entfernt oder erstellt.
Ich hoffe dass es halbwegs verständklich ist.

Das trifft sich: ich habe genau das gleiche Problem (anderes Beispiel, aber egal) und dachte mir schon, dass es ja nicht so selten sein kann.

Drei Fragen:

  • Die PersonalProSchicht-Objekte für jede Person könntest Du doch auch ein für alle Mal erstellen und bei der Auswahl einer neuen Schicht nur die Eigenschaft "IstZugeordnet" anpassen. Oder was spricht dagegen?

  • Die CheckBoxList aus dem WPF extended toolkit müsste es doch auch tun, statt des DataGrids?

  • Und vor allem: reden wir hier von Model- oder von ViewModel-Objekten? Ist "Schicht" mit zugeordneter "Personalliste" eine Instanz, deren Daten direkt in die Datenbank zurückgeschrieben oder sonstwie serialisiert werden? Oder ist es eine ViewModel-Instanz, und zwischen ihr und der Serialisierung hängt noch eine "innere" Model-Instanz?

Mein Problem ist nämlich die Synchronisierung zwischen einem SchichtViewModel mit zugehöriger Liste von PersonalViewModel-Instanzen und dem "inneren" SchichtModel mit seinen PersonalModel-Instanzen. Ich habe den Verdacht, dass ich hier MVVM-Beispiele töricht anwende.

5.299 Beiträge seit 2008
vor 10 Jahren

Dassis sicherlich leicht möglich, dass man MVVM iwie falsch anwendet. Aber wirklich diskutieren kann man sowas wohl nur am konkreten, als zip angehängten, lauffähigen Beispiel.

Der frühe Apfel fängt den Wurm.

W
955 Beiträge seit 2010
vor 10 Jahren

Hi,

Die CheckBoxList aus dem WPF extended toolkit müsste es doch auch tun, statt des
DataGrids?

Sicher, deshalb abstrahieren wir ja die Daten von der View.

  • Die PersonalProSchicht-Objekte für jede Person könntest Du doch auch ein für alle Mal erstellen und bei der Auswahl einer neuen Schicht nur die Eigenschaft "IstZugeordnet" anpassen. Oder was spricht dagegen?

PersonalProSchicht ist kein Model und hat somit keine Persistenz. Um jede Kombination anzufertigen müssten alle Entities aus der DB geladen werden und ein Kreuzprodukt (also alle Schicht-Personal-Kombination) erzeugt werden. Ist O.K. wenn es ressourcentechnisch belanglos ist.

reden wir hier von Model- oder von ViewModel-Objekten? Ist "Schicht" mit zugeordneter "Personalliste" eine Instanz, deren Daten direkt in die Datenbank zurückgeschrieben oder sonstwie serialisiert werden? Oder ist es eine ViewModel-Instanz, und zwischen ihr und der Serialisierung hängt noch eine "innere" Model-Instanz?

Personal und Schicht sind (pesistzenzfähige) Modellobjekte, PersonalProSchicht ein ViewModel wenn Du so willst. Ich habe es eingeführt weil es schwierig ist die Relation zwischen Personal und Schicht an eine Checkbox zu binden, habe das Ding aber nicht ViewModel genannt weil es keine eigene View abstrahiert. (Was man jedoch tun könnte).

Mein Problem ist nämlich die Synchronisierung zwischen einem SchichtViewModel mit zugehöriger Liste von PersonalViewModel-Instanzen und dem "inneren" SchichtModel mit seinen PersonalModel-Instanzen. Ich habe den Verdacht, dass ich hier MVVM-Beispiele töricht anwende. Ich verstehe das Problem nicht. PersonalProSchicht bildet lediglich die Relation Personal::Schicht so ab, das es an eine Checkbox gebunden werden kann.

C
Cannon Themenstarter:in
282 Beiträge seit 2008
vor 10 Jahren

Ich habe das inzwischen auch so ähnlich wie witte gemacht. Nur, dass ich die Zurodnung direkt in der Personal-Klasse mache und die manuell setzen kann. Sonst wird es wegen der Repositories un dem UnitOfWork etwas umständlich.


		void Load()
		{
			// load users
			Users.Clear();
			var users = WorkUnit.Users.Query(e => e.AccessLevel <= AccessLevelProperties.Level);
			foreach (User user in users) {
				Users.Add(user);
			}
			UserCollection.MoveCurrentToFirst();
			// load clubs
			Clubs.Clear();
			var clubs = WorkUnit.Clubs.GetAll();
			foreach (Club club in clubs) Clubs.Add(club);
			ClubCollection.MoveCurrentToFirst();
		}

		void LoadAssigns()
		{
			foreach (Club club in Clubs) {
				club.IsUserAssigned = (club.Users.Contains(CurrentUser)) ? true : false;
			}
			_assignsloaded = true;
		}

		void SaveAssigns()
		{
			if (!_assignsloaded) return;
			foreach (Club club in Clubs) {
				if ((club.IsUserAssigned) && (!club.Users.Contains(CurrentUser))) {
					club.Users.Add(CurrentUser);
				} else if ((!club.IsUserAssigned) && (club.Users.Contains(CurrentUser))) {
					club.Users.Remove(CurrentUser);
				}
			}
		}

LoadAssigns() und SaveAssigns() wird über CurrentChanging und CurrentChanged-Ereignisse der UserCollection gesteuert.