2017-02-12 4 views
1

Ist es möglich, eine ViewModel für mehrere dynamische Tabs zu haben? Das bedeutet, dass ich beim Erstellen eines neuen Tabs dieselbe Instanz von ViewModel verwenden sollte, damit ich Informationen abrufen und verhindern kann, dass jedes Tab Daten teilt/dieselben Daten anzeigt.wpf - Ein ViewModel für dynamische Registerkarten

Die Einstellung, die ich denke, es zu verwenden wäre für eine Gehaltsabrechnung Anwendung, wo jeder Gehaltsabrechnung jeder Mitarbeiter von jeder Registerkarte aktualisiert werden kann. Daher sollte die Information in jedem Tab unterschiedlich sein.

Ist das möglich?


Update: Added Code

MainViewModel wo Tabs Sammlung behandelt wird:

public ObservableCollection<WorkspaceViewModel> Workspaces { get; set; } 
public MainViewModel() 
{ 
    Workspaces = new ObservableCollection<WorkspaceViewModel>(); 
    Workspaces.CollectionChanged += Workspaces_CollectionChanged; 
} 

void Workspaces_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) 
    { 
     if (e.NewItems != null && e.NewItems.Count != 0) 
      foreach (WorkspaceViewModel workspace in e.NewItems) 
       workspace.RequestClose += this.OnWorkspaceRequestClose; 

     if (e.OldItems != null && e.OldItems.Count != 0) 
      foreach (WorkspaceViewModel workspace in e.OldItems) 
       workspace.RequestClose -= this.OnWorkspaceRequestClose; 
    } 

    private void OnWorkspaceRequestClose(object sender, EventArgs e) 
    { 
     CloseWorkspace(); 
    } 

    private DelegateCommand _exitCommand; 
    public ICommand ExitCommand 
    { 
     get { return _exitCommand ?? (_exitCommand = new DelegateCommand(() => Application.Current.Shutdown())); } 
    } 

    private DelegateCommand _newWorkspaceCommand; 
    public ICommand NewWorkspaceCommand 
    { 
     get { return _newWorkspaceCommand ?? (_newWorkspaceCommand = new DelegateCommand(NewWorkspace)); } 
    } 

    private void NewWorkspace() 
    { 
     var workspace = new WorkspaceViewModel(); 

     Workspaces.Add(workspace); 

     SelectedIndex = Workspaces.IndexOf(workspace); 

    } 

    private DelegateCommand _closeWorkspaceCommand; 
    public ICommand CloseWorkspaceCommand 
    { 
     get { return _closeWorkspaceCommand ?? (_closeWorkspaceCommand = new DelegateCommand(CloseWorkspace,() => Workspaces.Count > 0)); } 
    } 

    private void CloseWorkspace() 
    { 
     Workspaces.RemoveAt(SelectedIndex); 
     SelectedIndex = 0; 
    } 

    private int _selectedIndex = 0; 
    public int SelectedIndex 
    { 
     get { return _selectedIndex; } 
     set 
     { 
      _selectedIndex = value; 
      OnPropertyChanged("SelectedIndex"); 
     } 
    } 

WorkspaceViewModel:

public PayslipModel Payslip { get; set; } 

    public WorkspaceViewModel() 
    { 
     Payslip = new PayslipModel(); 
     SaveToDatabase = new DelegateCommand(Save,() => CanSave); 

     SelectAll = new DelegateCommand(Select,() => CanSelect); 

     UnSelectAll = new DelegateCommand(UnSelect,() => CanUnSelect); 
    } 

    public ICommand SaveToDatabase 
    { 
     get; set; 
    } 

    private bool CanSave 
    { 
     get { return true; } 
    } 

    private async void Save() 
    { 
     try 
     { 
      MessageBox.Show(Payslip.Amount.ToString()); 
     } 
     catch (DbEntityValidationException ex) 
     { 
      foreach (var en in ex.EntityValidationErrors) 
      { 
       var exceptionDialog = new MessageDialog 
       { 
        Message = { Text = string.Format("{0}, {1}", en.Entry.Entity.GetType().Name, en.Entry.State) } 
       }; 

       await DialogHost.Show(exceptionDialog, "RootDialog"); 

       foreach (var ve in en.ValidationErrors) 
       { 
        exceptionDialog = new MessageDialog 
        { 
         Message = { Text = string.Format("{0}, {1}", ve.PropertyName, ve.ErrorMessage) } 
        }; 

        await DialogHost.Show(exceptionDialog, "RootDialog"); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      var exceptionDialog = new MessageDialog 
      { 
       Message = { Text = string.Format("{0}", ex) } 
      }; 

      await DialogHost.Show(exceptionDialog, "RootDialog"); 
     } 

    } 


    public event EventHandler RequestClose; 
    private void OnRequestClose() 
    { 
     if (RequestClose != null) 
      RequestClose(this, EventArgs.Empty); 
    } 

    private string _header; 
    public string Header 
    { 
     get { return _header; } 
     set 
     { 
      _header = value; 
      OnPropertyChanged("Header"); 
     } 
    } 

Payroll Usercontrol wo WorkspaceViewModel Datacontext ist:

public Payroll() 
{ 
    InitializeComponent(); 
    DataContext = new WorkspaceViewModel(); 
} 

Payroll.xaml tabcontrol:

<dragablz:TabablzControl ItemsSource="{Binding Workspaces}" SelectedIndex="{Binding SelectedIndex}" BorderBrush="{x:Null}"> 
      <dragablz:TabablzControl.ItemTemplate> 
       <DataTemplate> 
        <TextBlock Text="{Binding Header}"/> 
       </DataTemplate> 
      </dragablz:TabablzControl.ItemTemplate> 
      <dragablz:TabablzControl.ContentTemplate> 
       <DataTemplate> 
        <ContentControl Margin="16"> 
         <local:TabLayout DataContext="{Binding Path=Payslip, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" x:Name="tabLayout"/> 
        </ContentControl> 
       </DataTemplate> 
      </dragablz:TabablzControl.ContentTemplate> 
     </dragablz:TabablzControl> 

Dies funktioniert wie erwartet, jede Registerkarte zeigt unterschiedliche Informationen und Bindungen in Ordnung arbeiten. Ich kann die Informationen in der MessageBox jedoch nicht abrufen.

+1

Können Sie dieselbe Quelle nicht mehrmals derselben Quelle hinzufügen? Oder warum möchten Sie dasselbe Modell für mehrere Registerkarten verwenden, wenn Sie nicht möchten, dass sie die Daten gemeinsam nutzen ...? – mm8

Antwort

0

ich es nicht den Weg zur Arbeit hatte ich es bekommen konnte, so stellte ich den Knopf in der Ansicht speichern, die Datacontext-Info auf, wo Mitarbeiter hat sind geladen und haben es von dort aus zum arbeiten gebracht, da es direkt auf die Eigenschaften zugreift.

0

Ich bin mir nicht sicher, ob ich Ihre Frage vollständig verstehe, aber wenn Sie ein Fenster mit Tabcontrol benötigen, in dem jede Registerkarte auf einen Mitarbeiter verweist, dann müssen Sie die ItemsSource der Tabcontrol an eine Liste der Ansichtsmodell

Es ist nicht möglich, alle Registerkarten an dieselbe Instanz zu binden, da dann alle Registerkarten dasselbe tun und dieselben Informationen anzeigen.

+0

Das klingt nach dem, was ich erreichen möchte. Wie kann ich die ItemsSource an eine Liste des ViewModel binden? Oder muss ich dazu eine neue Frage stellen? – bruh1234

+0

Eigentlich habe ich gerade ein paar Checks gemacht, und das ist es, was ich momentan habe, aber es gibt ein Problem. Jedes Mal, wenn ich eine Registerkarte hinzufüge, wird das ViewModel erneut instanziiert. Wenn ich also die angezeigten Informationen in meiner Datenbank speichern möchte, erhalte ich eine NullPointerException. Die Schaltfläche zum Speichern befindet sich in einer anderen Ansicht, und der DataContext dieser Ansicht behandelt die TabControl-Elemente (WorkspaceViewModel). – bruh1234

0

ViewModels sollte eine 1: 1-Beziehung mit dem Modell haben. In Ihrem TabControl Datacontext, sagen wir, Sie haben Eigenschaften wie:

public ObservableCollection<EmployeeViewModel> Employees {get;set;} 
public EmployeeViewModel CurrentEmployee 
{ 
    get { return _currentEmployee;} 
    set 
    { 
     _currentEmployee = value; 
     OnPropertyChanged("CurrentEmployee"); 
    } 
} 

wo Mitarbeiter an Itemssource des TabControl gebunden ist, und currentEmployee CurrentItem. Um eine neue Registerkarte zu erstellen:

var employee = new Employee(); 
var vm = new EmployeeViewModel(employee); 
Employees.Add(vm); 
CurrentEmployee = vm; 

Wenn Sie eine Taste speichern möchten außerhalb des TabControl, stellen nur seine Datacontext currentEmployee.

Ich hoffe, das hilft!

Edit:

Zwei Dinge, die ich denke, verursachen Probleme:

  1. Payroll.Xaml sollte an MainViewModel gebunden sein, da sich die Workspaces-Sammlung dort befindet.

  2. Instanziieren Sie ViewModels nicht im Code Ihrer Ansicht. Verwenden Sie stattdessen ein DataTemplate (siehe this question).

Werfen Sie einen Blick auf Josh Smith's MVVM demo app (source code)

+0

Vielen Dank! Ich werde dies versuchen und als Antwort akzeptieren, wenn es funktioniert :) – bruh1234

+0

Ich habe etwas Code hinzugefügt, um zu zeigen, was ich bisher habe. Ich habe deine Lösung versucht, aber Bindungen scheinen zu verschwinden. – bruh1234

Verwandte Themen