首页 > 解决方案 > WPF ItemsControl 无法绑定命令

问题描述

我是 wpf 的新手,我知道这个问题已经在其他时候被问过,我试图实施一些我找到的解决方案。但它不起作用。我做错了什么,但我看不到它是什么。我创建了一个新的简单应用程序来测试这个问题。

namespace WpfApp3
{
    public class MyElement
    {
        public string Text { get; set; }
        public MyElement(string t)
        {
            Text = t;
        }
    }

    public class MyCommand : ICommand
    {
        public bool CanExecute(object parameter)
        {
            return true;
        }
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter)
        {
            _handler(parameter);
        }

        private Action<object> _handler;
        public MyCommand(Action<object> handler) { _handler = handler; }
    }

    public class MyItemsControlViewModel
    {
        ObservableCollection<MyElement> _items;
        public ObservableCollection<MyElement> MyElementItems { get { return _items; } set { _items = value; RaisePropertyChanged("MyElementItems"); } }
        ObservableCollection<MyElement> _temporayList;
       
        private ICommand _itemClicked;
        public ICommand ItemClicked { get { return _itemClicked; } }

        public MyItemsControlViewModel()
        {
            _items = new ObservableCollection<MyElement>();
            _temporayList = new ObservableCollection<MyElement>();
            _itemClicked = new MyCommand(OnItemSelected);

            AddItem("Element 1");
            AddItem("Element 2");
            AddItem("Element 3");
            UpdateList();
        }

        public void UpdateList()
        {
            MyElementItems = _temporayList;
        }
        public void AddItem(string t)
        {
            MyElement item = new MyElement(t);
            _temporayList.Add(item);
        }

        public void OnItemSelected(object param)
        {
            Debug.WriteLine("Executed!");
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
}

XAML

<UserControl x:Class="WpfApp3.MyUserControl"
                  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:local="clr-namespace:WpfApp3"
                  mc:Ignorable="d" 
                  d:DesignHeight="1080" d:DesignWidth="570"
                  x:Name="myCustomControl">
    <Grid >
        <Button x:Name="btnOutsideItemsControl"  Width="100" Height="100 " VerticalAlignment="Top" Command="{Binding ItemClicked}" />
        <ItemsControl 
            x:Name="listItems"             
            ScrollViewer.PanningMode="None"
            IsEnabled="False"
            Background = "Transparent"         
            HorizontalAlignment="Center"
            ItemsSource="{Binding MyElementItems}" Margin="0,152,0,0" Width="549">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <WrapPanel HorizontalAlignment="Left" Margin="50,0,0,0" 
                                        Background="Transparent" Orientation="Vertical"/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Button 
                    Content="{Binding Text}"
                    Command="{Binding ElementName=listItems, Path=DataContext.ItemClicked}"/>

            </DataTemplate>
            </ItemsControl.ItemTemplate>    
        </ItemsControl>
    </Grid>
</UserControl>

该组件在 MainWindow.xaml 中使用。

namespace WpfApp3
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MyItemsControlViewModel _myViewModel;
        public MyItemsControlViewModel MyViewModel { get { return _myViewModel; } }
        public MainWindow()
        {
            _myViewModel = new MyItemsControlViewModel();
            InitializeComponent();

            myCustomControl.DataContext = MyViewModel;
        }
    }
}

XAML

<Window x:Class="WpfApp3.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:WpfApp3"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <local:MyUserControl x:Name="myCustomControl"/>
    </Grid>
</Window>

当我运行应用程序时,我可以正确地看到带有正确文本的 3 项列表。但是,如果我单击列表中的一个按钮,我将看不到 Debug.WriteLine("Executed!"); 的输出。

但是,如果我单击 ItemsControl 之外的按钮btnOutsideItemsControl,它就可以工作。我可以看到 Debug.WriteLine("Executed!"); 的输出 所以我认为命令的定义也是正确的。

为了正确绑定 ItemsControl 内 Button 的 Command 属性,我试试这个

<Button Command="{Binding ElementName=listItems, Path=DataContext.ItemClicked}">

还有这个

<Button Command="{Binding DataContext.ItemClicked, RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=ItemsControl}}">

但它不起作用。

请帮忙!

标签: c#wpfdata-bindingwpf-controls

解决方案


一旦我告诉你,你就会踢自己。

您的问题是您设置IsEnabled="False"ItemsControl. 删除它,宇宙就会一切顺利。


推荐阅读