Доступ к нажатию кнопки для кнопки в шаблоне данных ListBox на шаблонном элементе управления Silverlight - PullRequest
1 голос
/ 13 апреля 2011

У меня есть шаблон элемента управления Silverlight (не пользовательский элемент управления), который содержит ListBox.

В шаблоне данных ListBox у меня есть кнопка, например:

                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" />
                                        <ColumnDefinition Width="Auto" />
                                        <ColumnDefinition Width="*" />
                                    </Grid.ColumnDefinitions>
                                    <ProgressBar Grid.Column="0" Width="70" Height="20" Value="{Binding Path=Percentage}" Minimum="0.0" Maximum="100.0" />
                                    <TextBlock Grid.Column="0" Text="{Binding Path=Percentage, StringFormat='{}{0:##0.0}%'}" Margin="10,3,3,3" HorizontalAlignment="Center" />
                                    <TextBlock Grid.Column="1" Text="{Binding Path=File.Name}" Margin="3" />
                                    <Button Grid.Column="2" Content="Remove" x:Name="RemoveButton" Command="{TemplateBinding DeleteCommand}" Style="{TemplateBinding UploadButtonStyle}" HorizontalAlignment="Right" Margin="0,0,5,0" />
                                </Grid>
                            </DataTemplate>
                        </ListBox.ItemTemplate>

Видите кнопку там в конце шаблона? Как я могу получить доступ к этому событию? Я не могу использовать метод GetTemplateChild (), поскольку кнопка является частью DataTemplate. Я пробовал командовать (как вы можете видеть выше). Похоже, что это путь, хотя Templated Control не совсем MVVM.

Есть идеи? Может быть, что-то кроме командования? или я неправильно командую?

вот соответствующий код:

... определения свойств / свойств зависимостей ... (должно ли это быть Dep Prop?)

    public static readonly DependencyProperty DeleteCommandProperty =
        DependencyProperty.Register("DeleteCommand", typeof(ICommand), typeof(MultipleFileUpload), new PropertyMetadata(null));

    public ICommand DeleteCommand
    {
        get { return (ICommand)GetValue(DeleteCommandProperty); }
        set 
        { 
            SetValue(DeleteCommandProperty, value);
            FirePropertyChanged("DeleteCommand");  //INotifyPropertyChanged stuff
        }
    }

... в OnApplyTemplate () ...

    public override void OnApplyTemplate()
    {
        ....
        DeleteCommand = new DelegateCommand(RemoveItemFromList, CanRemove);
        ....
        base.OnApplyTemplate();
    }

... Действие ICommand ...

    private void RemoveItemFromList(object commandParameter)
    {
        //NEVER GETTING HERE!
    }

Надеюсь, это что-то маленькое.

Спасибо людям!

Кевин

Ответы [ 4 ]

1 голос
/ 13 апреля 2011

Я добавил команду как свойство к классу объектов, которые я связываю с ItemSource ListBoxes (и других ItemsControl's). Это означает, что я должен изменить свои объекты «данных» для обработки событий GUI - что часто казалось неправильным и хакерским.

Я также получил ItemsControl (но так как список элементов является ItemsControl, это все равно может применяться). Я добавляю свои собственные свойства к производному элементу управления, к которому в конечном итоге я хочу получить доступ из элементов. В вашем случае кнопка обработчик команд. Должно быть легко установить эти свойства, поскольку они не заблокированы в этом вложенном шаблоне.

Затем я переопределил GetContainerForItemOverride () в этом производном классе и возвращаю другой класс, мой собственный производный ContentPresenter. Этот новый ContentPresenter также должен иметь то же свойство команды - установите его равным команде ItemControl в GetContainerForItemOverride при его создании.

Теперь в DataTemplate используйте TemplateBinding (не обычную Binding), чтобы получить эту команду.

Я пытался сделать универсальную / многократно используемую версию всего этого.

Редактировать, базовый пример:

class MyItemsControl : ItemsControl
{
   public Command MyCommand {get;set;} // I've often use a full-blown DP here

snip

   protected override DependencyObject GetContainerForItemOverride()
   {
       return new MyContentPresenter(this.MyCommand); // MyContentPresenter is just a derived ContentPresenter with that same property.
   }

Снова отредактируйте:

Я также поместил код в ItemsControl.PrepareContainerForItemOverride. Этот метод предоставляет вам и ContentControl (ваш собственный, если вы переопределяете GetContainerForItemOverride) и текущий «элемент» в списке. Здесь вы также можете выполнить дальнейшую инициализацию экземпляра ContentControl - если то, что вы хотите сделать, зависит от объекта, с которым он связан.

1 голос
/ 28 апреля 2011

Я сталкивался с этой идеей в MSDN , я не пробовал ее, но решил, что здесь стоит поделиться:

DataContext элементов в спискеПоле не совпадает с представлениями DataContext.DataContext каждого элемента относится к элементу в коллекции, который связан со свойством ItemsSource списка.

Решение состоит в том, чтобы связать свойство команды со статическим ресурсом и установить значениестатический ресурс для команды, которую вы хотите связать.Это проиллюстрировано в следующем XAML из Stock Trader RI.

<!--Specifying the observablecommand in the view's resources-->
<UserControl.Resources>
   <Infrastructure:ObservableCommand x:Key="BuyCommand" />
</UserControl.Resources>

<!—Binding the Button Click to the command. This control can sit inside a datagrid or a   list box. -->
<Button Commands:Click.Command="{Binding Path=Value, Source={StaticResource BuyCommand}}" Commands:Click.CommandParameter="{Binding Path=TickerSymbol}" />

Затем в кодовом представлении представления необходимо указать, что значение ресурса фактически указывает накоманда на презентацию модели.Ниже приведен пример этого из RI Stock Trader, где свойство ресурсов BuyCommand в модели представления помещается в ресурсы.

((ObservableCommand)this.Resources["BuyCommand"]).Value = value != null ? value.BuyCommand : null;
1 голос
/ 13 апреля 2011

Я предлагаю вам использовать одну команду relay:

public class RelayCommand<T> : ICommand
{
    #region Fields

    readonly Action<T> _execute = null;
    readonly Predicate<T> _canExecute = null;

    #endregion // Fields

    #region Constructors

    public RelayCommand(Action<T> execute)
        : this(execute, null)
    {
    }

    /// <summary>
    /// Creates a new command.
    /// </summary>
    /// <param name="execute">The execution logic.</param>
    /// <param name="canExecute">The execution status logic.</param>
    public RelayCommand(Action<T> execute, Predicate<T> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }

    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute((T)parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }

    #endregion // ICommand Members
}

XAML:

<Button Grid.Column="2" Content="Remove" x:Name="RemoveButton" Command="{Binding DeleteCommand}" CommandParameter={Binding} Style="{TemplateBinding UploadButtonStyle}" HorizontalAlignment="Right" Margin="0,0,5,0" />

при каждом нажатии на кнопку она будет вызывать одну и ту же команду удаления, но в качестве параметра будет передавать текущий элемент.

Надеюсь, это поможет

0 голосов
/ 10 октября 2013

Привет, вы можете использовать относительный источник и AncesterType. Тогда это прекрасно работает для меня.

См. Код ниже.

<Button Content="Delete"  Command="{Binding DataContext.DeleteCommand,
          RelativeSource= {RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}"
          CommandParameter="{Binding Path=SelectedItem, RelativeSource= {RelativeSource FindAncestor, AncestorType=
                 {x:Type ListBox}}}"/>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...