Tod*_*ain 5 c# vb.net binding mvvm windows-phone-8
此帖子已完全编辑,以提供更加可靠的示例和简化的问题
我希望将Child变化的结果反映在Parent中,尤其是字段中NumberOfChildrenWithDegrees.如果您选中这两个框用的绑定HasUniversityDegree,并HasHighSchoolDegree随后HasTwoDegrees在子视图更新.我想要的是HasTwoDegrees在父虚拟机中反映的子女数量.
我认为这只是简单,但事实证明它不起作用 - 检查两个框在父视图中没有任何变化(该<TextBlock Text="{Binding NumberOfChildrenWithDegrees,Mode=TwoWay,UpdateSourceTrigger=Explicit}"/>区域.我怎样才能让这个数字变化实时发生?
我已经为Windows Phone创建了一个小样本,可以直接插入名为TestPage的页面.只需将XAML放在内容网格中,然后将代码放在代码隐藏(VB)中即可.
XAML:
<Grid x:Name="ContentPanel" Background="{StaticResource PhoneChromeBrush}" Grid.Row="1">
<ListBox x:Name="parentLB" Margin="12,12,12,12" HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" Margin="0,12,0,0">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Parent Name: "/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Number of Children with Degrees: "/>
<TextBlock Text="{Binding NumberOfChildrenWithDegrees,Mode=TwoWay,UpdateSourceTrigger=Explicit}"/>
</StackPanel>
<ListBox Margin="12,0,0,0" x:Name="group2" ItemsSource="{Binding Children,Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Child Name: "/>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
<CheckBox Content="Has High School Degree:" IsChecked="{Binding HasHighSchoolDegree,Mode=TwoWay}"/>
<CheckBox Content="Has University Degree: " IsChecked="{Binding HasUniversityDegree,Mode=TwoWay}"/>
<CheckBox Content="Has Two Degrees? " IsEnabled="False" IsChecked="{Binding HasTwoDegrees}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Run Code Online (Sandbox Code Playgroud)
代码隐藏:
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Partial Public Class TestPage
Inherits PhoneApplicationPage
Public Sub New()
InitializeComponent()
parentLB.ItemsSource = Grandparent1.ParentGroups
End Sub
Public Function Grandparent1() As GrandParent
Dim ParentGroups As New List(Of Parent)
ParentGroups.Add(Parent1)
ParentGroups.Add(Parent2)
Dim gp As New GrandParent
gp.ParentGroups = ParentGroups
Return gp
End Function
Public Function Parent2() As Parent
Dim p As New Parent With {.Name = "Tom"}
Dim c1 As New Child With {.Name = "Tammy"}
Dim c2 As New Child With {.Name = "Timmy"}
Dim children As New List(Of Child)
children.Add(c1)
children.Add(c2)
p.Children = children
Return p
End Function
Public Function Parent1() As Parent
Dim p As New Parent With {.Name = "Carol"}
Dim c1 As New Child With {.Name = "Carl"}
c1.HasHighSchoolDegree = True
c1.HasUniversityDegree = True
Dim c2 As New Child With {.Name = "Karla"}
Dim children As New List(Of Child)
children.Add(c1)
children.Add(c2)
p.Children = children
Return p
End Function
End Class
Public Class GrandParent
Inherits BindableBase
Public Property ParentGroups As List(Of Parent)
End Class
Public Class Parent
Inherits BindableBase
Public Property Name As String
Private _children As List(Of Child)
Public Property Children As List(Of Child)
Get
Return Me._children
End Get
Set(value As List(Of Child))
Me.SetProperty(Me._children, value)
End Set
End Property
Private _numberOfChildrenWithDegrees As Integer
Public Property NumberOfChildrenWithDegrees As Integer
Get
Return Children.Where(Function(f) f.HasTwoDegrees).Count
End Get
Set(value As Integer)
Me.SetProperty(Me._numberOfChildrenWithDegrees, value)
End Set
End Property
End Class
Public Class Child
Inherits BindableBase
Public Property Name As String
Public ReadOnly Property HasTwoDegrees As Boolean
Get
Return HasHighSchoolDegree AndAlso HasUniversityDegree
End Get
End Property
Private _hasUniversityDegree As Boolean
Public Property HasUniversityDegree As Boolean
Get
Return Me._hasUniversityDegree
End Get
Set(value As Boolean)
Me.SetProperty(Me._hasUniversityDegree, value)
OnPropertyChanged("HasTwoDegrees")
End Set
End Property
Private _hasHighSchoolDegree As Boolean
Public Property HasHighSchoolDegree As Boolean
Get
Return Me._hasHighSchoolDegree
End Get
Set(value As Boolean)
Me.SetProperty(Me._hasHighSchoolDegree, value)
OnPropertyChanged("HasTwoDegrees")
End Set
End Property
End Class
Public MustInherit Class BindableBase
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Function SetProperty(Of T)(ByRef storage As T, value As T,
Optional propertyName As String = Nothing) As Boolean
If Object.Equals(storage, value) Then Return False
storage = value
Me.OnPropertyChanged(propertyName)
Return True
End Function
Protected Sub OnPropertyChanged(Optional propertyName As String = Nothing)
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Run Code Online (Sandbox Code Playgroud)
由于您的子元素是引发 的元素,PropertyChangeEvent并且计数绑定到父属性,因此您需要订阅PropertyChangedEvent父元素中的每个子元素。然后,您需要在父级中引发您自己的属性更改事件,并将 PropertyName 绑定到 UI 元素。
引发时执行的操作PropertyChangedEvent只是调用传入字符串OnPropertyChanged()的方法。如果您有一个更复杂的对象,您可能希望根据事件参数中的 PropertyName 在方法内NumberOfChildrenWithDegrees执行 case 语句。ChildOnPropertyChanged()我在代码中留下了一个带注释的示例。下面是完整的 C# 代码,我不需要更改 XAML。请注意,我还更改了列表的创建和添加方式,以便在将每个孩子添加到列表时订阅其属性更改事件。
using System.Linq;
using Microsoft.Phone.Controls;
using System.Collections.Generic;
using System.ComponentModel;
namespace PhoneApp1
{
public partial class TestPage : PhoneApplicationPage
{
public TestPage()
{
InitializeComponent();
this.parentLB.ItemsSource = Grandparent1().ParentGroups;
}
public GrandParent Grandparent1()
{
List<Parent> ParentGroups = new List<Parent>();
ParentGroups.Add(Parent1());
ParentGroups.Add(Parent2());
GrandParent gp = new GrandParent();
gp.ParentGroups = ParentGroups;
return gp;
}
public Parent Parent2()
{
Parent p = new Parent { Name = "Tom" };
Child c1 = new Child { Name = "Tammy" };
Child c2 = new Child { Name = "Timmy" };
p.AddChild(c1);
p.AddChild(c2);
return p;
}
public Parent Parent1()
{
Parent p = new Parent { Name = "Carol" };
Child c1 = new Child { Name = "Carl" };
c1.HasHighSchoolDegree = true;
c1.HasUniversityDegree = true;
Child c2 = new Child { Name = "Karla" };
p.AddChild(c1);
p.AddChild(c2);
return p;
}
}
public class GrandParent : BindableBase
{
public List<Parent> ParentGroups { get; set; }
}
public class Parent : BindableBase
{
public string Name { get; set; }
private List<Child> _children;
public List<Child> Children
{
get { return this._children; }
set { _children = value; }
}
public Parent()
{
_children = new List<Child>();
}
public void AddChild(Child child)
{
child.PropertyChanged += ChildOnPropertyChanged;
_children.Add(child);
}
private void ChildOnPropertyChanged(object sender, PropertyChangedEventArgs propertyChangedEventArgs)
{
//if(propertyChangedEventArgs.PropertyName == "HasUniversityDegree");
OnPropertyChanged("NumberOfChildrenWithDegrees");
}
private int _numberOfChildrenWithDegrees;
public int NumberOfChildrenWithDegrees
{
get { return Children.Where(f => f.HasTwoDegrees).Count(); }
set { _numberOfChildrenWithDegrees = value; }
}
}
public class Child : BindableBase
{
public string Name { get; set; }
public bool HasTwoDegrees
{
get { return HasHighSchoolDegree && HasUniversityDegree; }
}
private bool _hasUniversityDegree;
public bool HasUniversityDegree
{
get { return this._hasUniversityDegree; }
set
{
_hasUniversityDegree = value;
OnPropertyChanged("HasTwoDegrees");
}
}
private bool _hasHighSchoolDegree;
public bool HasHighSchoolDegree
{
get { return this._hasHighSchoolDegree; }
set
{
_hasHighSchoolDegree = value;
OnPropertyChanged("HasTwoDegrees");
}
}
}
public abstract class BindableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool SetProperty<T>(ref T storage, T value, string propertyName = null)
{
if (object.Equals(storage, value))
return false;
storage = value;
this.OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged(string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
Run Code Online (Sandbox Code Playgroud)