Я изучаю паттерн MVVM и у меня возникли проблемы с привязкой данных. Я понимаю, как это работает, но в моем примере он использует неправильный DataContext для поиска привязки.
Я не нашел другой вопрос, который подходит для моей проблемы.
Итак, у меня есть это представление:
<UserControl x:Class="Kenshinaro.CashRegister.UI.View.CashRegister.CashRegisterChoiceView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<ItemsControl ItemsSource="{Binding CashRegisters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</UserControl>
Со следующим ViewModel:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kenshinaro.CashRegister.UI.View.CashRegister;
namespace Kenshinaro.CashRegister.UI.ViewModel.CashRegister
{
public class CashRegisterChoiceViewModel : MVVM.ViewModel
{
private ObservableCollection<CashRegisterItemsControlView> _cashRegisters = new ObservableCollection<CashRegisterItemsControlView>()
{
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "1"
}
}
}
}
},
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "2"
}
}
}
}
},
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "3"
}
}
}
}
}
};
public ObservableCollection<CashRegisterItemsControlView> CashRegisters
{
get => _cashRegisters;
set => SetProperty(ref _cashRegisters, value);
}
}
}
(Мой класс ViewModel реализует интерфейс INotifyPropertyChanged)
Так что это представление показывает список этого представления:
<UserControl x:Class="Kenshinaro.CashRegister.UI.View.CashRegister.CashRegisterItemsControlView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Kenshinaro.CashRegister.UI.View.CashRegister"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<md:Card Margin="10">
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<local:CashRegisterCardView Padding="5"/>
<Button Margin="20" Grid.Row="1" Content="Pick me"/>
</Grid>
</md:Card>
</UserControl>
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Kenshinaro.CashRegister.UI.ViewModel.CashRegister
{
public class CashRegisterItemsControlViewModel : MVVM.ViewModel
{
private View.CashRegister.CashRegisterCardView _view;
public View.CashRegister.CashRegisterCardView View
{
get => _view;
set => SetProperty(ref _view, value);
}
}
}
И это представление также показывает это представление:
<UserControl x:Class="Kenshinaro.CashRegister.UI.View.CashRegister.CashRegisterCardView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Kenshinaro.CashRegister.UI.View.CashRegister"
xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Background="White" >
<Grid>
<TextBlock Text="{Binding DataContext.Name, RelativeSource={RelativeSource AncestorType=local:CashRegisterCardView}}"/>
</Grid>
</UserControl>
ViewModel:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Kenshinaro.CashRegister.Model;
namespace Kenshinaro.CashRegister.UI.ViewModel.CashRegister
{
public class CashRegisterCardViewModel : MVVM.ViewModel
{
private Model.CashRegister _model;
public Model.CashRegister Model
{
get => _model;
set => SetProperty(ref _model, value);
}
public String Name
{
get => _model.Name;
set => _model.Name = value;
}
}
}
Теперь, еслиЯ запускаю приложение. Привязка к TextBlock в последнем виде не отображается. Выходные данные VisualStudio сообщают:
System.Windows.Data Ошибка: 40: Ошибка пути BindingExpression: свойство 'Name' не найдено в 'object' '' CashRegisterItemsControlViewModel '(HashCode = 35528341)'. BindingExpression: Path = DataContext.Name;DataItem = 'CashRegisterCardView' (Name = '');целевым элементом является TextBlock (Name = '');Целевым свойством является «Текст» (тип «Строка»)
. Как я могу из этого выбрать, оно ищет Свойство в DataContext CashRegisterItemsControlView, но я просто не понимаю почему, потому чтоя устанавливаю DataContext вручную при инициализации коллекции (только для тестирования):
private ObservableCollection<CashRegisterItemsControlView> _cashRegisters = new ObservableCollection<CashRegisterItemsControlView>()
{
new CashRegisterItemsControlView()
{
DataContext = new CashRegisterItemsControlViewModel()
{
View = new CashRegisterCardView()
{
DataContext = new CashRegisterCardViewModel()
{
Model = new Model.CashRegister()
{
Name = "1"
}
}
}
}
},
...
Так почему же он по-прежнему использует неверный DataContext?
Теперь, когда я изменяю привязку к View.DataContext.Nameон ищет в заданном вручную DataContext:
System.Windows.Data Ошибка: 40: Ошибка пути BindingExpression: свойство 'View' не найдено в 'object' '' CashRegisterCardView '(Name =' ')». BindingExpression: Path = View.DataContext.Name;DataItem = 'CashRegisterCardView' (Name = '');целевым элементом является TextBlock (Name = '');Свойство target - «Текст» (тип «Строка»)
Я в замешательстве .. Надеюсь, вы мне поможете.
Спасибо!
ЕслиВам нужна информация о других классах, просто спросите. Я не хочу ставить больше кода в вопрос, так как он достаточно длинный.