2016-06-10 8 views
2

Dies ist mein erstes Mal eine Frage zu stellen. Ich habe meinen Code so weit wie möglich vereinfacht, um zu veranschaulichen, wonach ich suche.Bind ItemsControl zu einer Sammlung von ViewModels auf einem ViewModel

Ich habe ein ViewModel (äußere), das eine ObservableCollection eines anderen ViewModel (innere) enthält. Das innere ViewModel ist für ein UserControl. Das äußere ViewModel ist für MainWindow. Ich möchte einfach ein UserControl für jedes Objekt in der ObservableCollection anzeigen. Aber ich habe Probleme, den DataContext-Satz von UserControl auf die Objekte in der ObservableCollection zu setzen.

Inner Ansichtsmodell (für Usercontrol):

public class InnerViewModel : ViewModelBase 
{ 
    string _text; 

    public string Text 
    { 
     get { return _text; } 
     set { SetProperty<string>(ref _text, value); } 
    } 

    public InnerViewModel() { } 
} 

Inner Ansichtsmodell (für Usercontrol):

public class OuterViewModel : ViewModelBase 
{ 
    ObservableCollection<InnerViewModel> _innerViewModels; 

    public ObservableCollection<InnerViewModel> InnerViewModels 
    { 
     get { return _innerViewModels; } 
     set { SetProperty<ObservableCollection<InnerViewModel>>(ref _innerViewModels, value); } 
    } 

    public OuterViewModel() 
    { 
     _innerViewModels = new ObservableCollection<InnerViewModel>(); 
    } 

    public void Init() 
    { 
     InnerViewModels.Clear(); 
     InnerViewModels.Add(new InnerViewModel { Text = "Item1" }); 
     InnerViewModels.Add(new InnerViewModel { Text = "Item2" }); 
    } 
} 

InnerControl XAML (äußerste Tag für Sauberkeit entfernt)

<UserControl.DataContext> 
    <local:InnerViewModel /> 
</UserControl.DataContext> 
<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="50px"></ColumnDefinition> 
     <ColumnDefinition ></ColumnDefinition> 
     <ColumnDefinition Width="50px"></ColumnDefinition> 
    </Grid.ColumnDefinitions> 
    <Label Content="Header"></Label> 
    <Label Grid.Column="1" Content="{Binding Text}" ></Label> 
    <Label Grid.Column="2" Content="Footer"></Label> 
</Grid> 

Mainwindow XAML

<Window.DataContext> 
    <local:OuterViewModel /> 
</Window.DataContext> 
<Grid> 
    <ItemsControl ItemsSource="{Binding InnerViewModels}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <local:InnerControl></local:InnerControl> <!-- HOW DO I SET THE DATACONTEXT ON THIS??? --> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Grid> 

InnerControl.cs Code:

public partial class InnerControl : UserControl 
{ 
    public InnerControl() 
    { 
     InitializeComponent(); 
    } 
} 

MainWindow.cs Code:

public partial class MainWindow : Window 
{ 
    OuterViewModel _vm; 

    public MainWindow() 
    { 
     InitializeComponent(); 

     _vm = (OuterViewModel)DataContext; 
     _vm.Init(); 
    } 
} 

ViewModelBase:

public abstract class ViewModelBase : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String propertyName = null) 
    { 
     if (Equals(storage, value)) 
     { 
      return false; 
     } 

     storage = value; 
     this.OnPropertyChanged(propertyName); 
     return true; 
    } 

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChangedEventHandler eventHandler = this.PropertyChanged; 
     if (eventHandler != null) 
     { 
      eventHandler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

Ergebnis: Screenshot of what I get when I run

+0

Sie mixen zuerst view-model-zuerst, das geht nicht.Persönlich denke ich, View-First ist Bullshit, scheint alle Arten von unnötigen Problemen zu schaffen. –

Antwort

0

Ich denke, Sie verwenden Paul Sheriff Form Channel9 als Code-Quelle? Ihre viewModelBase hat eine INOtifyProperty. Es scheint, dass Sie die RaisePropertyChage ("Eigenschaft") nicht verwenden.

+0

Code für ViewModelBase hinzugefügt –

0

In Sie für die innere VM sehen Sie das Ansicht-Modell in der Ansicht (Ansicht-first) erstellen, das bedeutet, dass Ihre Ansicht, die Sie in den DataTemplate schaffen, hat ein anderes Sicht-Modell als die von den ItemsControl geliefert .

Sie könnten vielleicht, dass überschreiben wieder so (nicht sicher über die Eigenschaftszuweisung Reihenfolge):

<DataTemplate> 
    <local:InnerControl DataContext="{Binding}"/> 
</DataTemplate> 

Wie im Kommentar erwähnt, ich würde die VMs in der Ansicht nicht schaffen, sondern schaffen die Ansichten implizit mit typed DataTemplates.

+0

Dieses DataContext-Bit hinzugefügt und das gleiche Ergebnis erhalten. Ich werde untersuchen, wie Sie die Ansichten implizit mit typisierten DataTemplates erstellen. Danke –

+0

Sie könnten eine Ebene höher gehen, wo es immer noch das 'ItemsControl' Element' DataContext' gibt: '{Binding DataContext, RelativeSource = {RelativeSourceAncestorType = ContentPresenter}}' natürlich, wenn Ihre Ansicht danach die Eigenschaft ändert , das wird auch nicht funktionieren. Es ist sowieso keine richtige Lösung, eher wie ein schmutziger Hack. –

1

Ich löste dies wie folgt:

public partial class MainWindow : Window 
{ 
    OuterViewModel _vm; 

    public MainWindow() 
    { 
     InitializeComponent(); 

     _vm = new OuterViewModel(); 
     _vm.Init(); 
     DataContext = _vm; 
    } 
} 

ändern Mainwindow NICHT haben Datacontext gesetzt

<!-- Don't set DataContext here --> 
<Grid> 
    <ItemsControl ItemsSource="{Binding InnerViewModels}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate DataType="{x:Type local:InnerViewModel}"> 
       <local:InnerControl DataContext="{Binding}"></local:InnerControl> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Grid> 

Changed InnerControl XAML:

Changed MainWindow.cs die Außenansicht Modell zu erstellen NICHT haben DataContext gesetzt:

<!-- Don't set DataContext here --> 
<Grid> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="50px"></ColumnDefinition> 
     <ColumnDefinition ></ColumnDefinition> 
     <ColumnDefinition Width="50px"></ColumnDefinition> 
    </Grid.ColumnDefinitions> 
    <Label Content="Header"></Label> 
    <Label Grid.Column="1" Content="{Binding Text}" ></Label> 
    <Label Grid.Column="2" Content="Footer"></Label> 
</Grid> 
Verwandte Themen