2016-10-02 39 views
0

爲什麼listbox中的按鈕無法運行綁定命令? 我將這個命令綁定到了簡單的按鈕(不是模板),它的工作完美。 Main.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:d="http://schemas.microsoft.com/expression/blend/2008" 
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:local="clr-namespace:WpfApplication2" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="800" Width="525"> 
<Window.DataContext> 
    <local:ViewModel/> 
</Window.DataContext> 
<Window.Resources> 
    <DataTemplate x:Key="lbTemp"> 
     <StackPanel> 
      <TextBlock Height="50" Text="{Binding}"/> 
      <Button Height="20" Content="click" Command="{Binding Path=TestCommand}" CommandParameter="hello"/> 
     </StackPanel> 
    </DataTemplate> 
</Window.Resources> 
<Grid> 
    <ListBox x:Name="listBox" Width="500" Height="300" ItemTemplate="{StaticResource lbTemp}" ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=DataContext.MyData}"/> 
    <Button Command="{Binding Path=TestCommand}" CommandParameter="hello" Width="200" Height="40"/> 
</Grid> 

ViewModel.cs

public class ViewModel : INotifyPropertyChanged 
{ 
    public ViewModel() { } 

    public ObservableCollection<string> MyData { 
     get 
     { 
      return _MyData; 
     } 
     set 
     { 
      if (!_MyData.SequenceEqual(value)) 
      { 
       _MyData = value; 
      } 
      OnPropertyChanged(); 
     } 
    } 
    private ObservableCollection<string> _MyData = new ObservableCollection<string>(); 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropertyChanged([CallerMemberName]string caller="") 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller)); 
    } 

    private ICommand _testCommand; 
    public ICommand TestCommand 
    { 
     get 
     { 
      return _testCommand; 
     } 
     set 
     { 
      if (_testCommand != value) 
      { 
       _testCommand = value; 
       OnPropertyChanged(); 
      } 
     } 
    } 
} 

而且Command.cs

public class RelayCommand : ICommand 
{ 
    public RelayCommand(Action action, Func<object, bool> canExecutePredicate) 
    { 
     if (action == null || canExecutePredicate == null) 
      throw new ArgumentNullException("Can't be null"); 
     this._action = action; 
     this._canExecutePredicate = canExecutePredicate; 
    } 

    public RelayCommand(Action action) : this(action, (obj) => true) { } 

    Action _action; 
    Func<object, bool> _canExecutePredicate; 

    public event EventHandler CanExecuteChanged; 
    protected virtual void OnCanExecuteChanged() 
    { 
     CanExecuteChanged?.Invoke(this, EventArgs.Empty); 
    } 

    public bool CanExecute(object parameter) 
    { 
     return _canExecutePredicate(parameter); 
    } 

    public void Execute(object parameter) 
    { 
     _action?.Invoke(); 
    } 
} 

你能說這個解決方案有效的XAML的例子嗎?

回答

2

這兩個ButtonDataContext是不同的。讓我們來看看DataContext的視圖中的一些元素。

  • WindowDataContext是你的ViewModel類。
  • ListBoxDataContextWindow的相同。應該不需要在您設置的ItemsSource綁定中使用RelativeSource
  • ButtonDataTemplate之外也有與Window相同的DataContext。這就是爲什麼這個Command綁定工作正常。
  • DataTemplate內部的Button有一個DataContext它代表您在ViewModel類中創建的MyData集合所代表的特定項目。重要的是,它不是而是ViewModel類本身。

這裏是我在那裏我使用RelativeSource

<Button Height="20" Content="click" Command="{Binding DataContext.TestCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}" CommandParameter="hello"/> 

請讓我知道如果這不適合你。

+0

謝謝!完美地工作! – Alexey

1

我認爲這是因爲TestCommand是ViewModel的屬性 - 而不是MyData集合的元素(字符串)。

你必須做的一類:

class MyItemClass : INotifyPropertyChanged 
{ 
    public string Text {get;set;} 
    private ICommand _testCommand; 
    public ICommand TestCommand 
    { 
     get 
     { 
      return _testCommand; 
     } 
     set 
     { 
      if (_testCommand != value) 
      { 
       _testCommand = value; 
       OnPropertyChanged(); 
      } 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    protected virtual void OnPropertyChanged([CallerMemberName]string caller="") 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(caller)); 
    } 
    } 

您應該然後與類型,其中的TextBlocks結合應該改變在DataTemplate中爲文本的項目填寫您的收藏邁德特。

順便說一句:你不必在列表框的itemssource綁定中有一個relativesource引用。它從Window繼承DataContext,因此只需使用{Binding MyData}即可。

+0

這是一個簡單的測試應用程序,用於測試wpf數據模板。對於填充MyData,我使用以下代碼: Environment.GetEnvironmentVariables()。Values.Cast ().ToList(); MyData = new System.Collections.ObjectModel。ObservableCollection (GetCollection()); TestCommand = new RelayCommand(()=> MessageBox.Show(「test command」),(obj)=> true); – Alexey

+0

好的,但你違反了查看模型的想法,因爲你的每個元素上的按鈕激活另一個對象的命令,這在我看來可能但很奇怪:-) –