Silverlight:在ItemsControl中绑定DataGrid标头内的按钮命令

时间:2013-01-08 11:04:09

标签: silverlight binding datagrid itemscontrol

将按钮命令绑定到“外部”数据上下文的属性时遇到了一些问题。

下图显示了我的布局。我正在尝试将“清除”按钮的CommandParameter(以红色标出)绑定到LocationId。 ItemsControl重复ObservableCollection的位置(请参阅下面的位置定义)。

“清除”按钮基本上是尝试删除附加到位置的地址,以清除DataGrid。为此,我需要将LocationId传递给ViewModel。

实际命令被完美触发,但CommandParameter上的绑定不太正确。

page layout

以下是Location& amp;的基础课程。地址:

class Location 
{   
    int Id;
    ObservableCollection<Address> Addresses;
}

class Address
{
    string AddressText;
}

以下是XAML评论的三个替代尝试&amp;错误消息:

<ItemsControl ItemsSource="{Binding Locations, Mode=TwoWay}">
  <ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
      <StackPanel VerticalAlignment="Stretch" />
    </ItemsPanelTemplate>
  </ItemsControl.ItemsPanel>
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Id}"/>
      <sdk:DataGrid x:Name="ResponseDataGrid" ItemsSource="{Binding Addresses}">
        <sdk:DataGrid.Columns>
          <sdk:DataGridTextColumn Header="Response" Width="*" Binding="{Binding AddressText}"/>
          <sdk:DataGridTemplateColumn Width="100">
            <sdk:DataGridTemplateColumn.HeaderStyle>
              <Style TargetType="sdk:DataGridColumnHeader">
                <Setter Property="ContentTemplate">
                  <Setter.Value>
                    <DataTemplate>
                      <Button Content="Clear" 
                              Command="{Binding DataContext.ClearLocationCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" 
                              CommandParameter="{Binding Id, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>
                      <!--System.Windows.Data Error: BindingExpression path error: 'Id' property not found on 'System.Windows.Controls.ItemsControl' -->

                      <!--CommandParameter="{Binding ItemsSource.Id, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>-->
                      <!--System.Windows.Data Error: BindingExpression path error: 'Id' property not found on 'System.Collections.ObjectModel.ObservableCollection`1[UI.Location]' -->

                      <!--This gives me the ID but uses a specific index so only works for the first repeated Location-->
                      <!--CommandParameter="{Binding ItemsSource[0].Id, RelativeSource={RelativeSource AncestorType=ItemsControl}}"/>-->
                    </DataTemplate>
                  </Setter.Value>
                </Setter>
              </Style>
            </sdk:DataGridTemplateColumn.HeaderStyle>
            <sdk:DataGridTemplateColumn.CellTemplate>
              <DataTemplate>
                <Button Content="Accept">
                  <i:Interaction.Triggers>
                    <i:EventTrigger EventName="Click">
                      <i:InvokeCommandAction 
                        Command="{Binding DataContext.SelectedAddressCommand , RelativeSource={RelativeSource AncestorType=ItemsControl}}" 
                        CommandParameter="{Binding SelectedItem, RelativeSource={RelativeSource AncestorType=sdk:DataGrid}}"/>
                    </i:EventTrigger>
                  </i:Interaction.Triggers>
                </Button>
              </DataTemplate>
            </sdk:DataGridTemplateColumn.CellTemplate>
          </sdk:DataGridTemplateColumn>
        </sdk:DataGrid.Columns>
      </sdk:DataGrid>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

从错误中看,按钮似乎无法完全看到重复的Location对象,它可以看到Locations的集合或特定的索引位置,但不能看到我需要的重复生成的位置!

谢谢!

2 个答案:

答案 0 :(得分:1)

所以你有一个带有ObservableCollection<Location>的ViewModel并点击Clear清除指定位置的ObservableCollection<Address>,对吗?

为什么不将Clear命令放入Location类?我不知道这个命令触发的逻辑,但这样做你将能够访问正确的位置Id属性。

编辑:这是我工作的例子:

<强>类

public class Location
{
    public Location(int id, IEnumerable<Address> addresses)
    {
        this.Id = id;
        this.Addresses =new ObservableCollection<Address>(addresses);
        this.ClearLocationCommand = new RelayCommand<int>(e => MessageBox.Show(string.Format("Clear command called on Location {0}", this.Id)));
    }

    public int Id { get; set; }
    public ObservableCollection<Address> Addresses { get; set; }

    public ICommand ClearLocationCommand { get; set; }
}

public class Address
{
    public Address(string text)
    {
        this.AddressText = text;
    }

    public string AddressText { get; set; }
}

public class MainWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public MainWindowViewModel()
    {
        Locations = new ObservableCollection<Location>(new []
            {
                new Location(1, new [] { new Address("A1") }), 
                new Location(2, new [] { new Address("A2"), new Address("A3"), }), 
            });
    }

    public ObservableCollection<Location> Locations { get; set; }

    private void OnPropertyChanged(string porpertyName)
    {
        var e = this.PropertyChanged;
        if (e != null)
        {
            e(this, new PropertyChangedEventArgs(porpertyName));
        }
    }
}

<强> XAML

<Window x:Class="TestBindingButtons.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:TestBindingButtons="clr-namespace:TestBindingButtons" Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
    <TestBindingButtons:MainWindowViewModel />
</Window.DataContext>
<Grid>
    <ItemsControl ItemsSource="{Binding Locations, Mode=TwoWay}">
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel VerticalAlignment="Stretch" />
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Id}"/>
                    <DataGrid x:Name="ResponseDataGrid" ItemsSource="{Binding Addresses}">
                        <DataGrid.Columns>
                            <DataGridTextColumn Header="Response" Width="*" Binding="{Binding AddressText}"/>
                            <DataGridTemplateColumn Width="100">
                                <DataGridTemplateColumn.HeaderStyle>
                                    <Style TargetType="DataGridColumnHeader">
                                        <Setter Property="ContentTemplate">
                                            <Setter.Value>
                                                <DataTemplate>
                                                    <Button Content="Clear"
                                                            Command="{Binding DataContext.ClearLocationCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
                                                            />
                                                </DataTemplate>
                                            </Setter.Value>
                                        </Setter>
                                    </Style>
                                </DataGridTemplateColumn.HeaderStyle>
                                <DataGridTemplateColumn.CellTemplate>
                                    <DataTemplate>
                                        <Button Content="Accept">

                                        </Button>
                                    </DataTemplate>
                                </DataGridTemplateColumn.CellTemplate>
                            </DataGridTemplateColumn>
                        </DataGrid.Columns>
                    </DataGrid>
                </StackPanel>                    
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>
</Window>

PD: 我没有发布RelayCommand的实现,使用你自己的。 我没有使用你的“sdk”框架,只是简单的微软东西。

答案 1 :(得分:1)

如果将ClearLocationCommand属性移动到Location类,请记住更改以下绑定:

<Button Content="Clear" 
    Command="{Binding DataContext.ClearLocationCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" 
    CommandParameter="{Binding Id, RelativeSource={RelativeSource AncestorType=ItemsControl}}"
    />

为:

<Button Content="Clear" 
    Command="{Binding ClearLocationCommand}" 
    CommandParameter="{Binding Id}"
    />

因为每个外部Location对象现在都有自己的清除命令,并且您已经在该项目行中的正确DataContext