2016-06-10 133 views
2

這是我第一次發佈問題。我儘可能簡化我的代碼來說明我在找什麼。將ItemsControl綁定到ViewModel的ViewModel集合

我有一個ViewModel(外部),它包含另一個ViewModel(內部)的ObservableCollection。內部ViewModel用於UserControl。外部ViewModel用於MainWindow。我只想爲ObservableCollection中的每個項目顯示一個UserControl。但是,我無法將UserControl的DataContext設置爲ObservableCollection中的項目。

內視圖模型(對於用戶控件):

public class InnerViewModel : ViewModelBase 
{ 
    string _text; 

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

    public InnerViewModel() { } 
} 

內視圖模型(對於用戶控件):

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(最外面的標記的清潔度移除)

<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> 

主窗口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代碼:

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

MainWindow.cs代碼:

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)); 
     } 
    } 
} 

結果: Screenshot of what I get when I run

+0

您將view-first與view-model-first混合在一起,這無法解決。就我個人而言,我認爲先看是廢話,似乎會造成各種不必要的問題。 –

回答

0

即時通訊您是否在使用Paul Sheriff表單channel9作爲代碼源?你的viewModelbase有一個INOtifyProperty。看起來你並沒有使用RaisePropertyChage(「財產」)。

+0

爲ViewModelBase添加了代碼 –

0

在您查看內部VM時,您在視圖(視圖優先)中創建視圖模型,這意味着您在DataTemplate中創建的視圖具有與ItemsControl提供的視圖不同的視圖模型。

也許你可以再次改寫,像這樣(不知道的財產分配順序):

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

正如評論指出的那樣,我不會在視圖中創建虛擬機,但含蓄地創建視圖使用typed DataTemplates

+0

添加了DataContext位並獲得了相同的結果。我將研究如何「使用類型化數據模板隱式創建視圖」。 謝謝 –

+0

當然,如果你的視圖在那之後改變屬性,你可以在保證仍然有'ItemsControl'項目'DataContext':'{Binding DataContext,RelativeSource = {RelativeSource AncestorType = ContentPresenter}}' ,這也不起作用。無論如何,這不是一個合適的解決方案,更像一個骯髒的黑客。 –

1

我解決了這個如下:

更改MainWindow.cs創建外視圖模型:

public partial class MainWindow : Window 
{ 
    OuterViewModel _vm; 

    public MainWindow() 
    { 
     InitializeComponent(); 

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

更改主窗口,以不具有的DataContext設置

<!-- 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> 

改變InnerControl XAML來沒有設置DataContext:

<!-- 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>