Команда WPF datatemplate - PullRequest
       11

Команда WPF datatemplate

2 голосов
/ 22 января 2010

У меня есть таблица данных для шаблона элемента tabcontrol следующим образом:

<DataTemplate x:Key="TabItemTemplate">
        <DockPanel Width="120">
            <Button 
    Command="{Binding Path=DataContext.DeleteTimeTableCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}"
    Content="X"
    Cursor="Hand"
    DockPanel.Dock="Right"
    Focusable="False" 
    Margin="0,1,0,0"
    Padding="0"
    VerticalContentAlignment="Bottom"
    Width="16" Height="16" />               

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

Проблема у меня в том, что команда Delete, к которой я привязываюсь, имеет метод canExecute, который обновляет все кнопки на всех вкладках в tabcontrol. Я просто хочу, чтобы текущая вкладка была затронута.

У меня есть свойство CanDelete, которое я хочу включить в свою команду. Я пытаюсь найти хороший пример на CommandParameters, так как я думаю, что это путь, по которому я должен идти.

Кто-нибудь получил хорошее предложение для лучшего способа сделать это?

Спасибо.

Ответы [ 2 ]

4 голосов
/ 11 ноября 2010

Я сомневаюсь, что вам все еще нужна помощь с этим, но решил, что я все равно приму ответ.

Способ, которым я занимался в прошлом, - сделать коллекцию элементов, которые вы привязываете к вашему TabControl, набором простых объектов ViewModel. Таким образом, вы можете реализовать логику CanXXX для каждой вкладки вместо TabControl или представления в целом.

В этом примере я использую класс RelayCommand, показанный в статье Джоша Смита о MVVM .

MainViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;

namespace TabBinding.ViewModels
{
    class MainViewModel : ViewModelBase
    {
        private ObservableCollection<TabViewModel> _Tabs;
        public ObservableCollection<TabViewModel> Tabs
        {
            get { return _Tabs; }
            set
            {
                _Tabs = value;
                OnPropertyChanged(this, "Tabs");
            }
        }

        public MainViewModel()
        {
            var tabs = new ObservableCollection<TabViewModel>();
            tabs.Add(new TabViewModel() { TabHeader = "Tab1", Content="Content For Tab1" });
            tabs.Add(new TabViewModel() { TabHeader = "Tab2", Content = "Content For Tab2" });
            tabs.Add(new TabViewModel() { TabHeader = "Tab3", Content = "Content For Tab3" });
            tabs.Add(new TabViewModel() { TabHeader = "Tab4", Content = "Content For Tab4" });
            Tabs = tabs;
        }
    }
}

TabViewModel.cs

using System.Windows.Input;
using System.Windows;

namespace TabBinding.ViewModels
{
    class TabViewModel : ViewModelBase
    {
        RelayCommand _CloseTabCommand;

        private string _TabHeader;
        public string TabHeader
        {
            get { return _TabHeader; }
            set
            {
                _TabHeader = value;
                OnPropertyChanged(this, "TabHeader");
            }
        }

        private string _Content;
        public string Content
        {
            get { return _Content; }
            set
            {
                _Content = value;
                OnPropertyChanged(this, "Content");
            }
        }

        public ICommand CloseTabCommand
        {
            get
            {
                if (_CloseTabCommand == null)
                {
                    _CloseTabCommand = new RelayCommand(
                        param => this.CloseTab(),
                        param => this.CanCloseTab
                        );
                }
                return _CloseTabCommand;
            }
        }

        public void CloseTab()
        {
            MessageBox.Show("Close Me!");
        }

        bool CanCloseTab
        {
            get { return (TabHeader == "Tab2" || TabHeader == "Tab4"); }
        }
    }

}

ViewModelBase.cs

using System.ComponentModel;

namespace TabBinding.ViewModels
{
    class ViewModelBase : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(object sender, string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

RelayCommand.cs

using System;
using System.Diagnostics;
using System.Windows.Input;

namespace TabBinding
{
    /// <summary>
    /// A command whose sole purpose is to 
    /// relay its functionality to other
    /// objects by invoking delegates. The
    /// default return value for the CanExecute
    /// method is 'true'.
    /// </summary>
    public class RelayCommand : ICommand
    {
        #region Fields

        readonly Action<object> _execute;
        readonly Predicate<object> _canExecute;        

        #endregion // Fields

        #region Constructors

        /// <summary>
        /// Creates a new command that can always execute.
        /// </summary>
        /// <param name="execute">The execution logic.</param>
        public RelayCommand(Action<object> 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<object> execute, Predicate<object> 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(parameter);
        }

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

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

        #endregion // ICommand Members
    }
}

MainWindow.xaml

<Window x:Class="TabBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:TabBinding.ViewModels"
        Title="MainWindow" Height="360" Width="550">
    <Window.Resources>
        <vm:MainViewModel x:Key="Data" />
    </Window.Resources>
    <Grid DataContext="{StaticResource Data}">
        <TabControl 
            HorizontalAlignment="Left"
            VerticalAlignment="Top"
            Margin="10,10,10,10"
            Width="500"
            Height="300"
            ItemsSource="{Binding Tabs}">
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="HeaderTemplate">
                        <Setter.Value>
                            <DataTemplate>
                                <StackPanel Orientation="Horizontal">
                                    <Button Content="X" Margin="0,0,10,0" Command="{Binding CloseTabCommand}" />
                                    <TextBlock Text="{Binding TabHeader}"/>
                                </StackPanel>
                            </DataTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Content" Value="{Binding Content}"/>
                </Style>
            </TabControl.ItemContainerStyle>
        </TabControl>
    </Grid>
</Window>

App.xaml

<Application x:Class="TabBinding.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="Views/MainWindow.xaml">
    <Application.Resources>

    </Application.Resources>
</Application>
0 голосов
/ 22 февраля 2016

Если кто-то все еще интересуется ответом, вы можете использовать расширение привязки CommandParameter, чтобы передать текущую модель.

<Button Command="{Binding Path=DataContext.DeleteTimeTableCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}" CommandParameter="{Binding}" />

Переданный объект будет DataContext элемента вкладки. Решение требует реализации ICommand для правильной обработки данного параметра (приведение и т. Д.). Кроме того, событие RequerySuggested должно вызываться после любой модификации модели, поскольку WPF не может определить, когда запрашивать методы CanExecute на вкладках. При использовании асинхронных моделей программирования следует помнить еще одну вещь: вызывать событие обновления только из потока пользовательского интерфейса. Иначе ничего не случится.

...