У меня есть очень простая составная модель, выполненная из двух классов:переплет Вложенных управлений пользователя в Composite View Model
Public Class ParentModelVM
Public Property Name As String
Public Property ChildModel As ChildModelVM
Public Sub New()
Name = "A Parent Model"
ChildModel = New ChildModelVM With {.Name = "A Child Model"}
End Sub
End Class
Public Class ChildModelVM
Public Property Name As String
Public Property Description As String
End Class
Обе реализации INotifyPropertyChanged, которые я сокращенная вне. Я пытаюсь создать пользовательский элемент управления для редактирования ParentModelVM:
<UserControl x:Class="EditParentModel" .../>
<UserControl.DataContext>
<Binding RelativeSource="{RelativeSource Self}" Path="ViewModel" />
</UserControl.DataContext>
<TextBox Name="NameInput" Text="{Binding Path=Name}"/>
<local:EditChildModel x:Name="ChildModelInput" ViewModel="{Binding Path=ChildModel}"/>
</UserControl>
ViewModel является ParentModelVM, который зарегистрирован как DependencyProperty, который связывает двухстороннее по умолчанию. У меня есть аналогичный UserControl с именем EditChildModel, у которого есть свойство ViewModel типа ChildModelVM, также зарегистрированное как DependencyProperty, которое по умолчанию связывает двусторонний путь.
Эта логика, по-видимому, имеет смысл для меня: ParentModelVM имеет строку, которая редактируется с помощью элемента управления TextBox, свойство Text которого привязано, и в нем есть ChildModelVM, который редактируется с помощью элемента управления EditChildModel, свойство которого связано с ViewModel.
ParentModelVM.Name правильно привязывается к его текстовому полю, а два свойства ChildViewModelVM корректно привязываются к их текстовым полям. Тем не менее, EditParentModel.ViewModel.ChildModel: не тот же объект, что и EditChildModel.ViewModel, и я не могу понять, почему. Поведение всего приложения точно такое же, если я удалю атрибут ViewModel="{Binding Path=ChildModel}"
из EditParentModel UserControl. Например, NameInput инициализирует «родительскую модель», но EditChildModel.NameInput не инициализирует «детскую модель», как я ожидаю.
Любая помощь в этом была бы принята с благодарностью. Благодаря!
--Edit--
Хорошо, я упростил это за абсурд, и он до сих пор не работает. У меня есть модель под названием SimpleParent. Это весь код:
Imports System.ComponentModel
Public Class SimpleParent
Implements INotifyPropertyChanged
Private _someText As String
Public Property SomeText As String
Get
Return _someText
End Get
Set(ByVal value As String)
_someText = value
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("SomeText"))
End Set
End Property
Public Sub New()
SomeText = "This is some text."
End Sub
Public Event PropertyChanged(ByVal sender As Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
Я создал UserControl под названием «SuperTextControl», который действует так же, как TextBox, с DependencyProperty под названием «Говорит» вместо текста. Вот весь XAML:
<UserControl x:Class="SuperTextControl"
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="23" d:DesignWidth="300">
<UserControl.DataContext>
<Binding RelativeSource="{RelativeSource Self}"/>
</UserControl.DataContext>
<TextBox Name="SaysInput" Text="{Binding Path=Says}" />
</UserControl>
А вот отделенный код:
Public Class SuperTextControl
Public Shared ReadOnly SaysProperty As DependencyProperty =
DependencyProperty.Register("Says", GetType(String), GetType(SuperTextControl))
Public Property Says As String
Get
Return CTypeDynamic(Of String)(GetValue(SaysProperty))
End Get
Set(ByVal value As String)
SetValue(SaysProperty, value)
End Set
End Property
End Class
Затем я создал SimpleParentControl, который имеет SimpleParent DependencyProperty. У меня это как DP, потому что я могу захотеть вложить этот элемент управления в другие элементы управления, которые привязаны к свойству SimpleParent. Вот весь XAML:
<UserControl x:Class="SimpleParentControl"
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:WpfTest"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.DataContext>
<Binding RelativeSource="{RelativeSource Self}" Path="SimpleParent" />
</UserControl.DataContext>
<StackPanel>
<TextBox Text="{Binding Path=SomeText}" />
<local:SuperTextControl Says="{Binding Path=SomeText}" />
</StackPanel>
</UserControl>
И весь отделенного кода:
Public Class SimpleParentControl
Public Shared ReadOnly SimpleParentProperty As DependencyProperty =
DependencyProperty.Register("SimpleParent", GetType(SimpleParent), GetType(SimpleParentControl))
Public Property SimpleParent As SimpleParent
Get
Return CTypeDynamic(Of SimpleParent)(GetValue(SimpleParentProperty))
End Get
Set(ByVal value As SimpleParent)
SetValue(SimpleParentProperty, value)
End Set
End Property
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
SimpleParent = New SimpleParent()
End Sub
End Class
текстовое поле в SimpleParentControl отображает "Это какой-то текст", как и ожидалось. Локальный: SuperTextControl ничего не отображает. Это самый простой пример, который я могу придумать о создании многократно используемого UserControl, но все же он не работает. Конечно, кто-то добился успеха, создав повторно используемый UserControl так же просто, как пользовательское текстовое поле, но ни одно онлайн-учебники не обсуждают конкретно, как это сделать. Это чрезвычайно тривиальный пример, который, по-видимому, не имеет причины. Я был бы очень признателен за понимание этого. Благодарю.
вы можете использовать [WPFInspector] (wpfinspector.codeplex.com), чтобы увидеть, что это 'DataContext' вашего пользовательского элемента управления EditChildModel. без этого шаблона и без кода, за которым трудно сказать, что вы пропустили. – stukselbax
Упростите дизайн. Не используйте DP для привязки DataContext. Установите VM непосредственно в DataContext. – LPL
@ LPL - Можете ли вы объяснить это дальше? Я думал, что я уже установил EditChildModel.ViewModel непосредственно в DataContext элемента управления EditParentModel через привязку. Благодарю. –