Cant access nested wpf item command by mvvm

Lets say i got a dummy WPF application (MVVM oriented). My main window contains a custom List i created, and the list contains a custom item. the item has an image button, and i want the button command to be the command i got in the viewmodel. the viewmodel is binded to the main window. how can i do it ?

i attached the dummy project (download it here : http://www.2shared.com/file/qmO3E5rx/NestedCommand.html or here : http://www.multiupload.nl/KCFLSKAIH0),

but if you don't want to download it, the code goes like this :

MainWindow XAML:

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Application="clr-namespace:WpfApplication2"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Application:List x:Name="myList" DataContext="{Binding}" />
</Grid>

MainWindow Code-Behind:

        public MainWindow()
    {
        InitializeComponent();
        CharacterViewModel viewModel = new CharacterViewModel();
        this.myList.ItemsList.ItemsSource = viewModel.Model.Powers;
    }

List XAML:

<UserControl x:Class="WpfApplication2.List"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:Application="clr-namespace:WpfApplication2"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<Grid>
    <ListView x:Name="ItemsList" ItemsSource="{Binding Path=Name}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Application:Item x:Name="myItem" />
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>

Item XAML:

<UserControl x:Class="WpfApplication2.Item"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="50" d:DesignWidth="50">
<Grid>
    <Button x:Name="ButtonImage" Command="**????????**">
        <Button.Template>
            <ControlTemplate>
                <Border HorizontalAlignment="Center" VerticalAlignment="Center" >
                    <Image Width="50" Height="50" Source="/WpfApplication2;component/Images/Jellyfish.jpg"/>
                </Border>
            </ControlTemplate>
        </Button.Template>
    </Button>
</Grid>

ViewModel Code :

    public class CharacterViewModel : ObjectBase
{
    public Character Model { get; private set; }
    public DelegateCommand<object> RemoveCommand { get; private set; }

    public CharacterViewModel()
        : this(Character.Create())
    {
    }

    public CharacterViewModel(Character model)
    {
        Model = model;
        RemoveCommand = new DelegateCommand<object>(RemoveCommand_Execute, RemoveCommand_CanExecute, "Save");
    }

    void RemoveCommand_Execute(object arg)
    {
        Model.Powers.Clear();
        MessageBox.Show(string.Format("{0} character powers removed.", Model.Name));
    }

    bool RemoveCommand_CanExecute(object arg)
    {
        return Model.Name != string.Empty;
    }
}

Model Code:

public class Character : ObjectBase
{
    string _Name = string.Empty;
    ObservableCollection<string> _Powers = new ObservableCollection<string>();

    public string Name
    {
        get { return _Name; }
        set
        {
            if (_Name == value)
                return;

            _Name = value;
            OnPropertyChanged("Name");
        }
    }

    public ObservableCollection<string> Powers
    {
        get { return _Powers; }
    }

    public static Character Create()
    {
        Character hero = new Character()
        {
            Name = "Superman",
        };

        hero.Powers.Add("Flight");
        hero.Powers.Add("Strength");
        hero.Powers.Add("X-Ray Vision");

        return hero;
    }
}

Framework Code :

public class DelegateCommand<T> : ICommand
{
    public DelegateCommand(Action<T> execute) : this(execute, null) { }

    public DelegateCommand(Action<T> execute, Predicate<T> canExecute) : this(execute, canExecute, "") { }

    public DelegateCommand(Action<T> execute, Predicate<T> canExecute, string label)
    {
        _Execute = execute;
        _CanExecute = canExecute;

        Label = label;
    }

    readonly Action<T> _Execute = null;
    readonly Predicate<T> _CanExecute = null;

    public string Label { get; set; }

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

    public bool CanExecute(object parameter)
    {
        return _CanExecute == null ? true : _CanExecute((T)parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add
        {
            if (_CanExecute != null)
                CommandManager.RequerySuggested += value;
        }
        remove
        {
            if (_CanExecute != null)
                CommandManager.RequerySuggested -= value;
        }
    }
}

public abstract class ObjectBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

Thanks for helping


The DataContext for the ListItem is the item that it is bound to which is not what you're looking for. You're looking for the DataContext of the UserControl and to get that you'll need to either reference the UserControl explicitly using ElementName or use a RelativeSource binding to explore the visual tree. RelativeSource is probably the best solution and since it references the control itself you'll need to specify in the Path of the binding that you're looking for the RemoveCommand member on the DataContext - something like Path=DataContext.RemoveCommand . See full example below.

XAML:

<Grid DataContext="{Binding}"> <!-- Set the binding for the DataContext of the control and all of its children -->
    <ListView ItemsSource="{Binding Path=Model.Powers}">
        <ListView.ItemTemplate>
            <DataTemplate>
                <!-- Use RelativeSource to access the Grid control and then get its DataContext -->
                <Button Command="{Binding Path=DataContext.RemoveCommand, RelativeSource={RelativeSource AncestorType=Grid}}">
                    <Border HorizontalAlignment="Center" VerticalAlignment="Center" >
                        <Image Width="50" Height="50" Source="/WpfApplication2;component/Images/Jellyfish.jpg"/>
                    </Border>
                </Button>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</Grid>
链接地址: http://www.djcxy.com/p/56144.html

上一篇: Viewmodel命令绑定

下一篇: 通过mvvm无法访问嵌套wpf项目命令