为什么列表框中的按钮无法运行绑定命令? 我将此命令绑定为简单按钮(不是模板),并且它完美地工作。 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示例吗?
答案 0 :(得分:2)
两个DataContext
的{{1}}不同。让我们看一下Button
视图中的一些元素。
DataContext
的{{1}}是您的Window
课程。DataContext
的{{1}}与ViewModel
相同。我们不需要在您设置的ListBox
绑定中使用DataContext
。Window
之外的RelativeSource
也与ItemsSource
具有相同的Button
。这就是为什么这个DataTemplate
绑定工作正常。DataContext
中的Window
与您在Command
课程中创建的Button
集合中代表的特定项目有DataTemplate
。重要的是,{em>不 DataContext
类本身。这是我 使用MyData
的地方。
ViewModel
如果这不适合你,请告诉我。
答案 1 :(得分: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));
}
}
然后,您应该使用该类型的项填充MyData集合,其中TextBlocks绑定应更改为DataTemplate中的Text。
BTW:你不必在列表框的itemssource绑定中有一个relativesource引用。它从Window继承DataContext,因此仅使用{Binding MyData}就足够了。