WPF - 将事件绑定到ItemsControl中Item的类方法

时间:2014-12-11 09:39:53

标签: c# wpf xaml event-binding

我对WPF / XAML有点新鲜(虽然我已经学会了C#)并且非常感谢我的任何帮助。我确实环顾了其他帖子和谷歌一段时间,但我似乎无法找到一个令人满意或详细的答案让我继续我的项目。请看下面的详细信息。提前谢谢你!

目的

我有一个名为Tile的类,它由一些属性和一个事件处理程序组成。 我还有一个ItemControl,它有一个按钮(如DataTemplate所示),其ItemSource是Tiles的集合。

现在,我想绑定Button的“Click”事件,以便调用Tile类中定义的Event Handler方法。

换句话说,当我单击ItemControl中任何项目的按钮时,必须调用相应Tile实例(来自集合)的方法处理程序。我该如何解决这个问题?

以下是整个代码,为避免分心而简化:

XAML

<Window x:Class="SampleWPF.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="300" Width="300">

    <!-- Make a ItemControl for "Tile"s. -->
    <ItemsControl x:Name="TileList">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!-- Wire the click event of this Button 
                 to event handler in the Tile class. -->
                <Button Content="Show"></Button>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

</Window>

代码隐藏

namespace SampleWPF
{
    public partial class MainWindow : Window
    {
        ObservableCollection<Tile> tiles;

        public MainWindow()
        {
            InitializeComponent();

            // Adding some sample data for testing.
            tiles = new ObservableCollection<Tile>();
            tiles.Add(new Tile("Item 1"));
            tiles.Add(new Tile("Item 2"));

            TileList.ItemsSource = tiles;
        }
    }

    public class Tile : INotifyPropertyChanged
    {
        public string Data
        { /* Accessors and PropertyNotifiers */ }

        public Tile(string data)
        { /* Initializing and assigning "Data" */ }

        // INotifyPropertyChanged implementation...
        // { ... }

        // This event handler should be bound to the Button's "Click" event
        // in the DataTemplate of the Item.
        public void ShowButton_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Viewing item from: " + this.Data);
        }
    }
}

因此,如果我单击第一个“显示”按钮,输出应该是“查看项目来自:项目1”,如果我单击第二个“显示”按钮,输出应该是“查看项目来自:项目2”

那么建议/有效的方法是什么?我的代码不适合此要求吗?

3 个答案:

答案 0 :(得分:2)

事件处理程序是错误的方法 - 使用Commands,更重要的是使用MVVM。

我可以看到你是新人(可能来自WinFormsASP.NET背景)你应该阅读这篇博客,了解你的思维需要如何改变 - 这是最重要的部分在处理WPF之前了解:http://rachel53461.wordpress.com/2012/10/12/switching-from-winforms-to-wpfmvvm/

你还应该阅读Kent Boogart关于MVVM如何根据基本原则运作的博客:http://kentb.blogspot.co.uk/2009/03/view-models-pocos-versus.html

答案 1 :(得分:1)

让我先从一些基础知识开始: 不要在codeBehind中分配itemsource - 使用Binding,如下所示:

<Controll ItemSource="{Binding MyObservableCollection}"/>

有很多方法可以实现这一目标。我认为使用this.Data并不是最好的解决方案。 例如,如果您的尾巴有ID或其他东西您可以将此ID分配给按钮CommandParameter,如下所示

<Button CommanParameter="{Binding Path=ID}" Click="ShowButton_Click"/>

然后在你的button_click事件中你可以“抓住”这样:

public void ShowButton_Click(object sender, EventArgs e)
{
  int ID = int.Parse(((Button)sender).CommandParameter.ToString());
}

修改

要使用此绑定,您需要设置DataContext。您可以在这样的ctor中执行此操作:

 public MainWindow()
    {
        InitializeComponent();

        // Adding some sample data for testing.
        tiles = new ObservableCollection<Tile>();
        tiles.Add(new Tile("Item 1"));
        tiles.Add(new Tile("Item 2"));
        // below You are setting a datacontext of a MainWindow to itself
        this.DataContext = this;
    }

另一个编辑

我们假设您的尾部类具有名为ID的属性。如果您将此ID绑定到Button.CommandParameter以后可以使用linq检索磁贴,如下所示:

public void ShowButton_click(object sender, EventArgs e)
{
   int MyId = int.Parse(((Button)sender).CommandParameter.ToString());
   Tile TileIWasSearchingFor = (from t in tiles where t.ID == MyId select t).First();
// do something with tile You found
}

答案 2 :(得分:1)

因为我的要求相当“简单”,所以我已经完成了一项工作,避免了命令。感谢MajkeloDev的答案:https://stackoverflow.com/a/27419974/3998255作为指导。

这是最终的事件处理程序:

public void ShowButton_Click(object sender, EventArgs e)
    {
        Tile requestingTile = (sender as Button).DataContext as Tile;
        if(requestingTile != null)
            MessageBox.Show("Viewing item from: " + this.Data); 
            // Or whatever else you want to do with the object...
    }

此外,将ItemSource添加为XAML属性:

<ItemsControl x:Name="TileList" ItemsSource="{Binding tiles}">

在MainWindow的构造函数中设置DataContext:

public MainWindow()
{ 
    this.DataContext = this;
    // Whatever else you want to do...
}

它可以按要求运作。