2016-06-10 2 views
2

Это мой первый вопрос. Я упростил свой код как можно больше, чтобы проиллюстрировать, что я ищу.Bind ItemsСвяжитесь с коллекцией ViewModels на ViewModel

У меня есть ViewModel (внешний), который содержит ObservableCollection другого ViewModel (внутренний). Внутренняя ViewModel предназначена для UserControl. Внешний ViewModel предназначен для MainWindow. Я просто хочу отображать один UserControl для каждого элемента в ObservableCollection. Но у меня возникли проблемы с набором DataContext UserControl для элементов в ObservableCollection.

Внутренний ViewModel (для UserControl):

public class InnerViewModel : ViewModelBase 
{ 
    string _text; 

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

    public InnerViewModel() { } 
} 

Внутренний ViewModel (для 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 (внешний тег удален для чистоты)

<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 Код:

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, это не сработает.Лично я думаю, что view-first - это фигня, похоже, создает всевозможные ненужные проблемы. –

ответ

0

Я думаю, что вы используете канал шеста шеста Paul9 в качестве источника кода? Ваш viewModelbase имеет свойство INOtifyProperty. Кажется, вы не используете RaisePropertyChage («свойство»).

+0

добавлен код для ViewModelBase –

0

В представлении для внутренней виртуальной машины вы создаете модель представления в представлении (первый вид), это означает, что ваше представление, которое вы создаете в DataTemplate, имеет другую модель представления, чем та, которая предоставляется ItemsControl ,

Вы могли бы, возможно, перезаписать, что снова, как это (не уверен насчет того, имущественного назначения):

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

Как отмечено в комментарии, я бы не создавать виртуальные машины в представлении, но создают мнение неявно используя typed DataTemplates.

+0

Добавлен этот бит DataContext и получил тот же результат. Я рассмотрю, как «создавать представления неявно с помощью типизированных DataTemplates». Спасибо –

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

Изменение MainWindow, чтобы не иметь 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> 
Смежные вопросы