【问题标题】:Getting ID of button clicked inside itemSource?获取在 itemSsource 中单击的按钮的 ID?
【发布时间】:2013-11-12 00:24:35
【问题描述】:

我有一个 observableCollection,我在视图中使用 itemSource 进行循环。 observablecollection 中的每个项目都包含一个按钮,该按钮将命令 (openSessionCommand) 发送到 viewModel。我的问题是 - 我怎样才能将 ID 发送回在 itemSource 中单击了哪个按钮的 viewModel?

<ItemsControl ItemsSource="{Binding AvailableSessions}" Margin="490,181,10.111,39.111">
<ItemsControl.ItemTemplate>
    <DataTemplate >
        <Border  BorderBrush="Black" Background="Gainsboro" BorderThickness="1" Margin="2">
            <Grid Background="#FFECECEC">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto"/>
                    <RowDefinition Height="Auto"/>
                </Grid.RowDefinitions>

                <Button Command="{Binding RelativeSource={RelativeSource FindAncestor, 
                                    AncestorType={x:Type UserControl}}, Path=DataContext.OpenSessionCommand}" 
                        HorizontalAlignment="Left" Margin="10,10,0,0" 
                        VerticalAlignment="Top" Width="243" Height="42">
                    <TextBlock TextWrapping="Wrap">
                        <Run Text="{Binding SessionName}"/><LineBreak/>
                        <Run Text="{Binding Genre}"/><Run Text=" - "/><Run Text="{Binding Tempo}"/>
                    </TextBlock>
                </Button>

                <Label Content="{Binding AdminUsername}" HorizontalAlignment="Left" 
                    Margin="10,53,0,0" VerticalAlignment="Top" Width="243" Height="26"/>
                <Label Content="{Binding Client1Username}" HorizontalAlignment="Left" 
                    Margin="10,71,0,0" VerticalAlignment="Top" Width="243" Height="25"/>

            </Grid>
        </Border>
    </DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
    <ControlTemplate TargetType="ItemsControl">
        <ScrollViewer CanContentScroll="True">
            <ItemsPresenter/>
        </ScrollViewer>
    </ControlTemplate>
</ItemsControl.Template>

<ItemsControl.ItemsPanel>
    <ItemsPanelTemplate>
        <VirtualizingStackPanel/>
    </ItemsPanelTemplate>
</ItemsControl.ItemsPanel>

委托命令:

public class DelegateCommand : ICommand
{
    private readonly Action _command;
    private readonly Func<bool> _canExecute;
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public DelegateCommand(Action command, Func<bool> canExecute = null)
    {
        if (command == null)
        throw new ArgumentNullException();
        _canExecute = canExecute;
        _command = command;
    }

    public void Execute(object parameter)
    {
        _command();
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute();
    }
}

ICommand:

public ICommand OpenSessionCommand { get 
    { return new DelegateCommand(OpenSession); } 
}


public void OpenSession()
{
    ContinueReceiving = false;
    dispatcherTimer.Stop();

    Messenger.Default.Send<NavigateMessage>(
       new NavigateMessage(SessionViewModel.ViewName, this));
}

【问题讨论】:

  • 看命令参数

标签: c# .net wpf xaml mvvm


【解决方案1】:

使用命令参数。使用{Binding} 将传递被点击的可观察集合中的对象。更多 MSDN

<Button Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.OpenSessionCommand}" CommandParemeter="{Binding}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="243" Height="42">
    <TextBlock TextWrapping="Wrap">
        <Run Text="{Binding SessionName}"/><LineBreak/>
        <Run Text="{Binding Genre}"/><Run Text=" - "/>
        <Run Text="{Binding Tempo}"/>
    </TextBlock>
</Button>

您还需要调整 OpenSessionCommand 方法签名以接受您的参数,但这取决于您使用的 Command 实现。

更新

下面是一个接受参数的 DelegateCommand 的通用实现。

public class DelegateCommand<T> : ICommand where T : class
{
    private readonly Action<T> _command;
    private readonly Func<T, bool> _canExecute;
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public DelegateCommand(Action<T> command, Func<T, bool> canExecute = null)
    {
        if (command == null)
            throw new ArgumentNullException();
        _canExecute = canExecute;
        _command = command;
    }

    public void Execute(object parameter)
    {
        _command(parameter as T);
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter as T);
    }
}

现在,当您定义 ICommand 时,它应该是这样的:

    public ICommand OpenSessionCommand { get { return new DelegateCommand<Button>(OpenSession); } }

    public void OpenSession(Button button)
    {
        ContinueReceiving = false;
        dispatcherTimer.Stop();

        Messenger.Default.Send<NavigateMessage>(new NavigateMessage(SessionViewModel.ViewName, this));
    }

【讨论】:

  • 我用我的 DelegateCommand 实现更新了我的问题。当我在“已执行”上添加断点时,我明白了您的意思-我看到该项目作为参数传入。我如何将它传递给 OpenSession() ?
  • OpenSession 会自动有参数。当您创建 canexecute 并执行时,将它们定义为 (o) => Button b = o as Button(作为示例)。
【解决方案2】:

我在带有上下文菜单的列表框中使用了类似的东西。

<ContextMenu>
    <MenuItem Header ="Edit Exercise"   
              Command="{Binding EditExercise_Command}" 
      CommandParameter="{Binding SelectedExercise}"
/>

因此,被调用的方法接收我右键单击的练习作为参数。

你可以通过按钮:)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-13
    • 1970-01-01
    • 2021-09-05
    • 2019-10-09
    • 1970-01-01
    • 2018-01-25
    相关资源
    最近更新 更多