我对WPF / XAML有点新鲜(虽然我已经学会了C#)并且非常感谢我的任何帮助。我确实环顾了其他帖子和谷歌一段时间,但我似乎无法找到一个令人满意或详细的答案让我继续我的项目。请看下面的详细信息。提前谢谢你!
我有一个名为Tile的类,它由一些属性和一个事件处理程序组成。 我还有一个ItemControl,它有一个按钮(如DataTemplate所示),其ItemSource是Tiles的集合。
现在,我想绑定Button的“Click”事件,以便调用Tile类中定义的Event Handler方法。
换句话说,当我单击ItemControl中任何项目的按钮时,必须调用相应Tile实例(来自集合)的方法处理程序。我该如何解决这个问题?
以下是整个代码,为避免分心而简化:
<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”
那么建议/有效的方法是什么?我的代码不适合此要求吗?
答案 0 :(得分:2)
事件处理程序是错误的方法 - 使用Commands
,更重要的是使用MVVM。
我可以看到你是新人(可能来自WinForms
或ASP.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...
}
它可以按要求运作。