WPF绑定到当前元素和父元素的属性

时间:2017-02-28 21:28:50

标签: c# wpf xaml data-binding

我对WPF非常陌生,我在创建绑定时尝试使用Knockout JS作为类比。我听说WPF的绑定引擎更加强大,但是我在Knockout中遇到了一些容易陷入困境的事情。

假设我有一个Person类,它有一个Addresses集合。

public class Person
{
    public string PersonId {get;set;}
    public IList<Address> Addresses{get; set;}
    public string FormattedName{get;set;}
}

public class Address
{
    public string AddressId{get;set;}
    public string Address1{get;set;}
    public string City{get;set;}
    public string State{get;set;}
    public string Zip{get;set;}
}

假设在一个页面上,我有一组人,每个人,我想显示所有地址并提供选择地址的按钮。所以,我的页面视图模型如下所示:

public class AddressSelection
{
    public string PersonId{get;set;}
    public string AddressId{get;set;}
}

public class PersonAddressSelectionViewModel
{
    public IList<Person> People {get; set;}

    public Person SelectedPerson {get;set;}
    public Address SelectedAddress{get;set;}

    public void SelectAddress(string personId, string addressId)
    {
        this.SelectedPerson = this.People.FirstOrDefault(x => x.PersonId == personId);
        this.SelectedAddress = this.SelectedPerson?.Addresses.FirstOrDefault(x => x.AddressId == addressId);
    }

    public void SelectAddress(AddressSelection arg)
    {  SelectAddress(arg.PersonId, arg.AddressId); }
}

现在,我想显示一个UI,显示每位乘客的标题,然后是每个地址的按钮。选择该按钮时,应触发SelectAddress功能。但是,在XAML中,我不确定如何分配绑定以使用父元素属性和当前元素属性;它是否可以从它们创建一个对象,甚至只是调用一个方法并从两者中传递参数fetch。

在淘汰赛中,您只需绑定该功能并访问父上下文,如:

<!-- ko foreach: $data.people -->
<h2 data-bind="text: formattedName"></h2>
<ul data-bind="foreach: $data.addresses">
    <li>
        <button data-bind="click: function() { $parents[1].selectAddress($parent.personId, $data.addressId); }">Select Address</button>
    </li>
</ul>
<!-- /ko -->

我似乎无法弄清楚如何在XAML中做同样的事情。

<ItemsControl Grid.Row="2" ItemsSource="{x:Bind ViewModel.People, Mode=OneWay}"
    HorizontalAlignment="Center" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="5">
                <TextBlock Style="{StaticResource TextBlockSmallStyle}" VerticalAlignment="Center" Width="180" Text="{Binding FormattedName, Mode=OneWay}" />
                <ItemsControl ItemsSource="{Binding Addresses}" Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <VirtualizingStackPanel Orientation="Horizontal" />
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Horizontal">
                                <Button Width="180" Style="{StaticResource ButtonStyle}"
                                Content="{Binding Address1}"
                                Click="SelectAddressClicked" Tag="{Binding **what to put here**}" />
                            </StackPanel>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>
代码背后的

SelectAddressClicked(object sender, object args) {
    ((Button)sender).Tag as Address; // would prefer this to be something that has both the address id and person id
}

1 个答案:

答案 0 :(得分:0)

你应该用MVVM而不是代码

来做这件事

Google RelayCommand班级实施

然后在您的视图模型中添加以下定义

public RelayCommand SelectAddressCommand { get; private set; }
构造函数中的

SelectAddressCommand  = new RelayCommand( args => SelectAddress(args) );

in xaml

<Button Command={Binding SelectAddressCommand}
        CommandParameter={...}

但根据我的理解,您可以使用ListBox代替ItemsControl来避免麻烦。它内置了SelectedItem属性,您可以直接将其绑定到View模型