Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/282.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 将数据从子级聚合到父级以进行绑定_C#_Vb.net_Mvvm_Windows Phone 8_Binding - Fatal编程技术网

C# 将数据从子级聚合到父级以进行绑定

C# 将数据从子级聚合到父级以进行绑定,c#,vb.net,mvvm,windows-phone-8,binding,C#,Vb.net,Mvvm,Windows Phone 8,Binding,这篇文章经过完整的编辑,提供了一个更坚实的例子和简化的提问 我希望将子项更改的结果反映在父项中,特别是字段NumberOfChildrenWithDegrees。如果选中绑定为HasUniversityGreee和HashighSchoolGreee的两个框,则子视图中的HasTwoDegrees将更新。我想在父VM中反映具有HasTwoDegrees的孩子的数量 我原以为这很简单,但事实证明它不起作用-选中两个框不会改变父视图(在区域)中的任何内容。如何实时更改此数字? 我为Windows P

这篇文章经过完整的编辑,提供了一个更坚实的例子和简化的提问

我希望将子项更改的结果反映在父项中,特别是字段
NumberOfChildrenWithDegrees
。如果选中绑定为
HasUniversityGreee
HashighSchoolGreee
的两个框,则子视图中的
HasTwoDegrees
将更新。我想在父VM中反映具有
HasTwoDegrees
的孩子的数量

我原以为这很简单,但事实证明它不起作用-选中两个框不会改变父视图(在
区域)中的任何内容。如何实时更改此数字?

我为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>

由于您的子元素是引发
PropertyChangeEvent
的元素,并且计数绑定到父属性,因此您需要订阅父元素中每个子元素的
PropertyChangedEvent
。然后您需要在父元素中引发自己的属性更改事件,并将PropertyName绑定到UI元素

当引发
PropertyChangedEvent
时,您执行的操作只是调用
OnPropertyChanged()
方法,并传入
NumberOfChildrenWithDegrees
字符串。如果您有更复杂的对象,您可能希望在
ChildOnPropertyChanged()中执行case语句
方法基于事件参数中的PropertyName。我在代码中留下了一个注释示例。下面是完整的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));
        }
    }

}
}
使用System.Linq;
使用Microsoft.Phone.Controls;
使用System.Collections.Generic;
使用系统组件模型;
命名空间PhoneApp1
{
公共部分类测试页:PhoneApplicationPage
{
公共测试页()
{
初始化组件();
this.parentLB.ItemsSource=grandrent1().ParentGroups;
}
公共祖父母祖父母1()
{
List ParentGroups=new List();
ParentGroups.Add(Parent1());
ParentGroups.Add(Parent2());
祖父母gp=新祖父母();
gp.ParentGroups=父组;
返回总成;
}
公共家长2()
{
父p=新父{Name=“Tom”};
子c1=新子{Name=“Tammy”};
子c2=新子{Name=“Timmy”};
p、 AddChild(c1);
p、 AddChild(c2);
返回p;
}
公共家长1()
{
父p=新父{Name=“Carol”};
子c1=新子{Name=“Carl”};
c1.HasHighSchoolDegree=true;
c1.HasUniversityGreee=true;
子c2=新子{Name=“Karla”};
p、 AddChild(c1);
p、 AddChild(c2);
返回p;
}
}
公共类祖父母:BindableBase
{
公共列表父组{get;set;}
}
公共类父级:BindableBase
{
公共字符串名称{get;set;}
私人名单——儿童;
公开儿童名单
{
获取{返回此。_children;}
设置{u children=value;}
}
公共家长()
{
_children=新列表();
}
公共无效添加子对象(子对象)
{
child.PropertyChanged+=ChildOnPropertyChanged;
_添加(child);
}
私有void ChildOnPropertyChanged(对象发送方,PropertyChangedEventArgs PropertyChangedEventArgs)
{
//如果(propertyChangedEventArgs.PropertyName==“HasUniversityGreee”);
关于财产变更(“拥有学位的儿童人数”);
}
拥有学位的儿童的私人国际人数;
拥有学位的儿童的公共int数量
{
获取{return Children.Where(f=>f.HasTwoDegrees.Count();}
设置{u numberOfChildrenWithDegrees=value;}
}
}
公共类子级:BindableBase
{
公共字符串名称{get;set;}
公立学校有两个学位
{
获取{return hashighschooldgree&&hasuniversitygree;}
}
私立学校拥有大学学位;
公立学校有大学学位
{
获取{返回此项。_hasuniversitygree;}
设置
{
_HasUniversityGreee=价值;
不动产变更(“有两个学位”);
}
}
私立学校;
公立学校
{
获取{返回此。\u hasHighSchoolDegree;}
设置
{
_hasHighSchoolDegree=值;
不动产变更(“有两个学位”);
}
}
}
公共抽象类BindableBase:INotifyPropertyChanged
{
公共事件属性更改事件处理程序属性更改;
受保护的bool SetProperty(ref T storage,T value,string propertyName=null)
{
if(object.Equals(存储,值))
返回false;
储存=价值;
此.OnPropertyChanged(propertyName);
返回true;
}
受保护的OnPropertyChanged无效(字符串propertyName=null)
{
if(PropertyChanged!=null)
{
PropertyChanged(这是新的PropertyChangedEventArgs(propertyName));
}
}
}
}

我希望这听起来不太像广告。有了BCL的工具,你只有机会完全按照@jmshapland所说的去做。对于这个简单的聚合,这可能不会太糟糕,但是如果聚合变得更复杂,代码会很快变得更复杂。然而,有一些工具可以支持你,特别是我的own工具:(开源)

这个工具基本上允许您创建一个可观察的表达式并监听其更新

 public class Parent
 {
      private INotifyValue<bool> _allTwoDegrees;
      public Parent()
      {
          _allTwoDegrees = Observable.Expression(() => Children.WithUpdates().All(child => child.HasTwoDegrees));
          _allTwoDegrees.ValueChanged += (o,e) => OnPropertyChanged("AllTwoDegrees");
      }
      public bool AllTwoDegrees
      {
          get
          {
              return _allTwoDegrees.Value;
          }
      }
      ...
 }
公共类父类
{
私有INotifyValue
 public class Parent
 {
      private INotifyValue<bool> _allTwoDegrees;
      public Parent()
      {
          _allTwoDegrees = Observable.Expression(() => Children.WithUpdates().All(child => child.HasTwoDegrees));
          _allTwoDegrees.ValueChanged += (o,e) => OnPropertyChanged("AllTwoDegrees");
      }
      public bool AllTwoDegrees
      {
          get
          {
              return _allTwoDegrees.Value;
          }
      }
      ...
 }
public abstract class Bindable : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] String property = null)
    {
        if (object.Equals(storage, value)) return false;
        storage = value;
        this.OnPropertyChanged(property);
        return true;
    }

    protected void OnPropertyChanged([CallerMemberName] string property = null)
    {
        if (this.PropertyChanged != null)
            this.PropertyChanged(this, new PropertyChangedEventArgs(property));
    }
}
public class Child : Bindable
{
    private string name;
    public string Name
    {
        get { return name; }
        set { SetProperty(ref name, value); }
    }

    public bool HasTwoDegrees { get { return HasHighSchoolDegree && HasUniversityDegree; } }

    private bool hasUniversityDegree;
    public bool HasUniversityDegree
    {
        get { return this.hasUniversityDegree; }
        set
        {
            SetProperty(ref hasUniversityDegree, value);
            OnPropertyChanged("HasTwoDegrees");
        }
    }

    private bool hasHighSchoolDegree;
    public bool HasHighSchoolDegree
    {
        get { return this.hasHighSchoolDegree; }
        set
        {
            SetProperty(ref hasHighSchoolDegree, value);
            OnPropertyChanged("HasTwoDegrees");
        }
    }
}
public class Parent : Bindable
{       
    private string[] bindingNames;
    private string[] allowedProperties;

    private string name;
    public string Name
    {
        get { return name; }
        set { SetProperty(ref name, value); }
    }

    private ObservableCollection<Child> children = new ObservableCollection<Child>();
    public ObservableCollection<Child> Children
    {
        get { return this.children; }
        set { children = value; }
    }

    public Parent()
    {
        this.children.CollectionChanged += children_CollectionChanged;
        bindingNames = new string[] { "NumberOfChildrenWithDegrees" };
        allowedProperties = new string[] { "HasUniversityDegree", "HasHighSchoolDegree" };
    }

    private void children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
            foreach (Object item in e.NewItems)
                if (item is INotifyPropertyChanged)
                    (item as INotifyPropertyChanged).PropertyChanged += item_PropertyChanged;
        if (e.OldItems != null)
            foreach (Object item in e.OldItems)
                (item as INotifyPropertyChanged).PropertyChanged -= item_PropertyChanged;
    }

    private void item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (bindingNames != null)
            foreach (string item in bindingNames)
                if (allowedProperties.Contains(e.PropertyName))
                    OnPropertyChanged(item);
    }

    public int NumberOfChildrenWithDegrees
    {
        get { return Children.Where(f => f.HasTwoDegrees).Count(); }
    }
}
public partial class MainPage : PhoneApplicationPage
{
    ObservableCollection<Parent> parentGroups = new ObservableCollection<Parent>();

    public ObservableCollection<Parent> ParentGroups
    {
        get { return parentGroups; }
        set { parentGroups = value; }
    }

    public MainPage()
    {
        InitializeComponent();
        this.parentLB.DataContext = this;
        FillParents();
    }

    public void FillParents()
    {
        Parent p = new Parent { Name = "Tom" };
        Child c1 = new Child { Name = "Tammy" };
        Child c2 = new Child { Name = "Timmy" };
        p.Children.Add(c1);
        p.Children.Add(c2);
        ParentGroups.Add(p);
        p = new Parent { Name = "Carol" };
        c1 = new Child { Name = "Carl" };
        c1.HasHighSchoolDegree = true;
        c1.HasUniversityDegree = true;
        c2 = new Child { Name = "Karla" };
        p.Children.Add(c1);
        p.Children.Add(c2);
        ParentGroups.Add(p);
    }
}