Car*_*eth 2 data-binding wpf user-controls
我有一个非常简单的复合模型,由两个类组成:
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
Run Code Online (Sandbox Code Playgroud)
两者都实现了我已经缩写的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>
Run Code Online (Sandbox Code Playgroud)
ViewModel是一个ParentModelVM,它注册为DependencyProperty,默认情况下绑定双向.我有一个名为EditChildModel的类似UserControl,它具有ChildModelVM类型的ViewModel属性,也注册为DependencyProperty,默认情况下绑定双向.
这个逻辑对我来说似乎有意义:ParentModelVM有一个String,它使用TextBox控件编辑,Text控件的Text属性被绑定,它有一个ChildModelVM,使用EditChildModel控件编辑,其ViewModel属性被绑定.
ParentModelVM.Name正确绑定到其文本框,并且两个ChildViewModelVM属性正确绑定到其文本框.但是,EditParentModel.ViewModel.ChildModel 与EditChildModel.ViewModel 不是同一个对象,我无法弄清楚原因.如果我ViewModel="{Binding Path=ChildModel}"从EditParentModel UserControl中删除该属性,整个应用程序的行为完全相同.例如,NameInput使用"A Parent Model"初始化,但EditChildModel.NameInput不会像我期望的那样使用"A Child Model"进行初始化.
任何有关这方面的帮助将不胜感激.谢谢!
- 编辑 -
好吧,我已经简化了荒谬,但它仍然无效.我有一个名为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
Run Code Online (Sandbox Code Playgroud)
我创建了一个名为"SuperTextControl"的UserControl,其行为与TextBox完全相同,DependencyProperty称为"Says"而不是Text.这是整个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>
Run Code Online (Sandbox Code Playgroud)
这是代码隐藏:
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
Run Code Online (Sandbox Code Playgroud)
然后我创建了一个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>
Run Code Online (Sandbox Code Playgroud)
整个代码隐藏:
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
Run Code Online (Sandbox Code Playgroud)
SimpleParentControl中的TextBox按预期显示"This is some text".本地:SuperTextControl什么都不显示.这是我可能想到的创建可重用的UserControl的最简单的例子,但它不起作用.当然,有人成功地创建了一个可重复使用的UserControl,就像自定义文本框一样简单,但没有在线教程具体讨论如何执行此操作.这是一个非常微不足道的例子,似乎没有理由失败.我非常感谢对此的任何见解.谢谢.
整个问题是我在UserControl级别设置了我的DataContext,它正在"窥视"到父控件中.感谢LPL指向我的博客文章澄清了这个问题:在WPF/Silverlight中创建可重用的UserControl的简单模式
它与RelativeSource vs. ElementName无关,与在代码隐藏中设置DataContext无关; 这些都是完成同样事情的不同方式.问题在该博客文章底部附近的图表中很明显.在子控件(SuperTextControl)中执行此操作:
<UserControl x:Class="SuperTextControl" ... >
<UserControl.DataContext>
<Binding RelativeSource="{RelativeSource Self}"/>
</UserControl.DataContext>
...
</UserControl>
Run Code Online (Sandbox Code Playgroud)
相当于在父代中声明控件如下:
<local:SuperTextControl Says="{Binding Path=SomeText}">
<local:SuperTextControl.DataContext>
<Binding RelativeSource="{RelativeSource Self}" />
</local:SuperTextControl.DataContext>
</local:SuperTextControl>
Run Code Online (Sandbox Code Playgroud)
这是不合理的.我之前的回答是不正确的:如果以相同的方式定义DataContext,则更改为ElementName会出现同样的问题.要解决这个问题,请在UserControl的最外层子节点上设置"内部"DataContext,而不是UserControl本身:
<UserControl x:Class="SuperTextControl" x:Name="SuperTextControl">
<Grid>
<Grid.DataContext>
<Binding ElementName="SuperTextControl" />
</Grid.DataContext>
<TextBox Name="SaysInput" Text="{Binding Path=Says}" />
</Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4786 次 |
| 最近记录: |