Is there a way I can bind a Command to Ctrl+MWheelUp/Down? U know in a browser, you can do the same to increase/decrease font size? I want to replicate that effect in WPF. Possible? I was looking at InputBinding > MouseBindings and MouseAction does not seem to support Mouse Scrolls.
* I seem to have posted a similar question, but can't find it anymore
It can be done using very simple custom MouseGesture:
public enum MouseWheelDirection { Up, Down}
public class MouseWheelGesture : MouseGesture
{
public MouseWheelDirection Direction { get; set; }
public MouseWheelGesture(ModifierKeys keys, MouseWheelDirection direction)
: base(MouseAction.WheelClick, keys)
{
Direction = direction;
}
public override bool Matches(object targetElement, InputEventArgs inputEventArgs)
{
var args = inputEventArgs as MouseWheelEventArgs;
if (args == null)
return false;
if (!base.Matches(targetElement, inputEventArgs))
return false;
if (Direction == MouseWheelDirection.Up && args.Delta > 0
|| Direction == MouseWheelDirection.Down && args.Delta < 0)
{
inputEventArgs.Handled = true;
return true;
}
return false;
}
}
public class MouseWheel : MarkupExtension
{
public MouseWheelDirection Direction { get; set; }
public ModifierKeys Keys { get; set; }
public MouseWheel()
{
Keys = ModifierKeys.None;
Direction = MouseWheelDirection.Down;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return new MouseWheelGesture(Keys, Direction);
}
}
in the xaml:
<MouseBinding Gesture="{local:MouseWheel Direction=Down, Keys=Control}" Command="..." />
Ok, I did something like this in my ShellView : Window
this.KeyDown += (s, e) =>
{
_leftCtrlPressed = (e.Key == Key.LeftCtrl) ? true : false;
};
this.MouseWheel += (s, e) =>
{
if (_leftCtrlPressed) {
if (e.Delta > 0)
_vm.Options.FontSize += 1;
else if (e.Delta < 0)
_vm.Options.FontSize -= 1;
}
};
I think the Behaviour method will make things cleaner and more reusable, but I didn't really get it. It'll will be great if someone explained it in a simple way here?
Window has the MouseWheel event. You can do some command binding magic which you can then bind to a DataContext property. Check out this SO article for hints: Key press inside of textbox MVVM. Also take a look at this article: http://code.msdn.microsoft.com/eventbehaviourfactor
I simply bind the command using Interaction.Triggers.
You'll need to reference the expression interactivity namespace in XAML.
<i:Interaction.Triggers>
<i:EventTrigger EventName="PreviewMouseWheel">
<cmd:InvokeCommandAction Command="{Binding MouseWheelCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
Then in the associated command.
private void MouseWheelCommandExecute(MouseWheelEventArgs e)
{
if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
if (e.Delta > 0)
{
if (Properties.Settings.Default.ZoomLevel < 4)
Properties.Settings.Default.ZoomLevel += .1;
}
else if (e.Delta < 0)
{
if (Properties.Settings.Default.ZoomLevel > 1)
Properties.Settings.Default.ZoomLevel -= .1;
}
}
}
If Delta is rising the mouse is scrolling Up, falling it is scrolling Down. I use this in an application where Scrolling will occur in scroll-able content but when either of the Ctrl keys are down, the application actually zooms.
Related
I am using a TextBox control for the user input in my Windows Phone 8.1 app.
How can I hide the characters as user gives input?
I am not using a PasswordBox because the defined InputScope is "Number" which is not possible in a PasswordBox.
While searching for a solution on the internet I found the only way by customizing the TextBox with the help of an UserControl.
Is there any easier way to do this without creating any UserControl?
Following is my code snippet:
In XAML page:
<TextBox Text="{Binding CardNo, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
MaxLength="17"
x:Name="CardNoTextBox"
InputScope="Number"
Margin="70,5"
PlaceholderText="Enter Your Card Number"
TextChanged="CardNoTextBox_TextChanged"
BorderBrush="Gray"
BorderThickness="2"
FontSize="20"/>
In code behind (xaml.cs):
private void CardNoTextBox_TextChanged(object sender, RoutedEventArgs routedEventArgs)
{
if (IsTextAllowed(CardNoTextBox.Text))
{
if (CardNoTextBox.Text.Length == 5)
{
if (CardNoTextBox.Text[4] != ' ')
{
string text = CardNoTextBox.Text.Insert(4, " ");
CardNoTextBox.Text = text;
CardNoTextBox.Select(CardNoTextBox.Text.Length, 0);
}
}
if (CardNoTextBox.Text.Length == 12)
{
if (CardNoTextBox.Text[11] != ' ')
{
string text = CardNoTextBox.Text.Insert(11, " ");
CardNoTextBox.Text = text;
CardNoTextBox.Select(CardNoTextBox.Text.Length, 0);
}
}
}
else
{
CardNoTextBox.Text = "";
}
}
After spending hours in finding an easier way I got an amazing solution. Hope this would help others too.
I simply added the following value to the FontFamily property of my TextBox control:
FontFamily="ms-appx:///Assets/PassDot.ttf#PassDot"
And gave the size of font 35,
FontSize="35"
This works just fine for my project.
I managed to create a custom TextBox, in which Text is *, but there is hiddenText that keeps the real string. Note that managing Caret position is not easy, because it changes due to some internal logic. Therefore, it is always at the end of the string. (Also note that you might need to handle some exceptions and bugs)
public class HiddenTextBox : TextBox
{
internal string hiddenText { get; private set; }
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Space)
addText(" ");
else if (e.Key == Key.Back)
removeText(true);
else if (e.Key == Key.Delete)
removeText(false);
else if (e.Key == Key.Return)
e.Handled = true;
base.OnPreviewKeyDown(e);
}
protected override void OnPreviewTextInput(TextCompositionEventArgs e)
{
addText(e.Text);
e.Handled = true;
}
void addText(string text)
{
hiddenText = hiddenText != null ? hiddenText.Insert(CaretIndex, text) : text;
update();
}
void removeText(bool back)
{
if (hiddenText == null || hiddenText.Length == 0 || (back==false && CaretIndex == hiddenText.Length))
return;
if (back)
hiddenText = hiddenText.Substring(0, CaretIndex - 1) + hiddenText.Substring(CaretIndex, hiddenText.Length - CaretIndex);
else
hiddenText = hiddenText.Substring(0, CaretIndex) + hiddenText.Substring(CaretIndex+1, hiddenText.Length - CaretIndex);
update();
}
void update()
{
StringBuilder star = new StringBuilder();
foreach (var s in hiddenText)
{
star.Append("*");
}
Text = star.ToString();
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
if (hiddenText != null)
CaretIndex += hiddenText.Length;
}
}
I want to search in a data grid via typing in a textbox, but I am unable to find solution.
Do I need to do any binding? If so, then how do I do it?
If you want filter text in your Datagrid i.e by Name, try this...
private bool DataMatchesFilterText(User user, string filterText)
{
return user.Name.ToString() == filterText;
}
Yeah you will require your data grid to be bound to a Property that contains all your data.
Then add a event handler to your Textbox to act on one of the key events, e.g.
Xaml:
<TextBox x:Name="SearchBox" KeyUp="FilterTextBox_TextChanged" />
Then in the code behind you need to act on that event. Here you need to extract the filter text, get the rows in your DataGrid and then perform some method to determine if it should be visible or not. You will need to implement your own DataMatchesFilterText method.
Codebehind:
private void FilterTextBox_TextChanged(object sender, KeyEventArgs e)
{
var filterTextBox = (TextBox)sender;
var filterText = filterTextBox.Text;
SetRowVisibilityByFilterText(filterText);
}
private void SetRowVisibilityByFilterText(string filterText)
{
GetVisibleRows(yourGrid)
.ToList()
.ForEach(
x =>
{
if (x == null) return;
x.Visibility =
DataMatchesFilterText(x.Item as YourRowProperty, filterText) ? Visibility.Visible : Visibility.Collapsed;
});
}
public static IEnumerable<DataGridRow> GetVisibleRows(DataGrid grid)
{
if (grid == null || grid.Items == null) yield break;
int count = grid.ItemsSource == null
? grid.Items.Count
: grid.ItemsSource.Cast<object>().Count();
for (int i = 0; i < count; i++)
{
yield return (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(i);
}
}
I am looking to find a generic way to support keyboard wedge scanning for my WPF TextBox controls.
(I am really a novice when it comes to more advanced WPF features, so I would like to ask if I am going in the right direction before I put a lot of time into research.)
What I am wanting to do is to add an Attached Property (or something) to my TextBoxes that will cause it to read all input into the box and then call a custom "ScanCompleted" command with the scanned input.
If an Attached Property is not a good fit for this, then is there a way to get this command on a TextBox without descending my own custom "ScanableTextBox"?
(Note: The criteria for a scan (instead of typed data) is that it will start with the Pause key (#19) and end with a Return key (#13).)
I think this could probably be accomplished with attached properties (behaviors), but would be much simpler and more straightforward to simply subclass TextBox and override the OnTextChanged, OnKeyDown, OnKeyUp and similar methods to add custom functionality.
Why don't you want to create your own control in this way?
update: Attached Behaviour
If you really don't want a derived control, here is an attached behaviour that accomplishes this (explanation below):
public class ScanReading
{
private static readonly IDictionary<TextBox, ScanInfo> TrackedTextBoxes = new Dictionary<TextBox, ScanInfo>();
public static readonly DependencyProperty ScanCompletedCommandProperty =
DependencyProperty.RegisterAttached("ScanCompletedCommand", typeof (ICommand), typeof (ScanReading),
new PropertyMetadata(default(ICommand), OnScanCompletedCommandChanged));
public static void SetScanCompletedCommand(TextBox textBox, ICommand value)
{
textBox.SetValue(ScanCompletedCommandProperty, value);
}
public static ICommand GetScanCompletedCommand(TextBox textBox)
{
return (ICommand) textBox.GetValue(ScanCompletedCommandProperty);
}
private static void OnScanCompletedCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var textBox = d as TextBox;
if (textBox == null)
return;
var command = (ICommand) e.NewValue;
if (command == null)
{
textBox.Unloaded -= OnTextBoxUnloaded;
textBox.KeyUp -= OnTextBoxKeyUp;
TrackedTextBoxes.Remove(textBox);
}
else
{
textBox.Unloaded += OnTextBoxUnloaded;
TrackedTextBoxes.Add(textBox, new ScanInfo(command));
textBox.KeyUp += OnTextBoxKeyUp;
}
}
static void OnTextBoxKeyUp(object sender, KeyEventArgs e)
{
var textBox = (TextBox) sender;
var scanInfo = TrackedTextBoxes[textBox];
if (scanInfo.IsTracking)
{
if (e.Key == Key.Return)
{
scanInfo.ScanCompletedCommand.Execute(textBox.Text);
scanInfo.IsTracking = false;
}
}
else if (string.IsNullOrEmpty(textBox.Text) && e.Key == Key.Pause)
{
TrackedTextBoxes[textBox].IsTracking = true;
}
}
static void OnTextBoxUnloaded(object sender, RoutedEventArgs e)
{
var textBox = (TextBox) sender;
textBox.KeyUp -= OnTextBoxKeyUp;
textBox.Unloaded -= OnTextBoxUnloaded;
TrackedTextBoxes.Remove(textBox);
}
}
public class ScanInfo
{
public ScanInfo(ICommand scanCompletedCommand)
{
ScanCompletedCommand = scanCompletedCommand;
}
public bool IsTracking { get; set; }
public ICommand ScanCompletedCommand { get; private set; }
}
Consume this by declaring a TextBox like so (where local is the namespace of your attached property, and ScanCompleted is an ICommand on your view-model):
<TextBox local:ScanReading.ScanCompletedCommand="{Binding ScanCompleted}" />
Now when this property is set, we add the TextBox to a static collection along with its associated ICommand.
Each time a key is pressed, we check whether it is the Pause key. If it is, and if the TextBox is empty, we set a flag to true to start looking for the Enter key.
Now each time a key is pressed, we check whether it is the Enter key. If it is, we execute the command, passing in the TextBox.Text value, and reset the flag to false for that TextBox.
We've also added a handler for the TextBox.Unloaded event to clean up our event subscriptions and remove the TextBox from the static list.
I've got an XNA + Silverlight game in Mango: Mostly XNA with some Silverlight UI on top. The problem I'm having is that when you hit a button or interact with a Silverlight control, the touch information is still passed along to the XNA game loop. How do you suppress this?
Wrote up a class to do the tracking for me. After your page loads (in the Loaded handler), create this and give it the root element (so it can attach to the LayoutUpdated event). Register any controls that might overlay the game surface during play. Then just call TouchesControl and pass in the touch position to find out if you should ignore that point or not. It caches the regions of the controls and updates them when there's a layout update.
Should work for rectangular elements moving, changing size or collapsing/expanding.
public class ControlTouchTracker
{
private List<FrameworkElement> controls = new List<FrameworkElement>();
private Dictionary<FrameworkElement, ControlRegion> controlBounds = new Dictionary<FrameworkElement, ControlRegion>();
public ControlTouchTracker(FrameworkElement rootElement)
{
rootElement.LayoutUpdated += this.OnLayoutUpdated;
}
public void RegisterControl(FrameworkElement control)
{
controls.Add(control);
}
public void RemoveControl(FrameworkElement control)
{
controls.Remove(control);
controlBounds.Remove(control);
}
private void OnLayoutUpdated(object sender, EventArgs e)
{
foreach (Control control in this.controls)
{
this.RefreshControlBounds(control);
}
}
private void RefreshControlBounds(FrameworkElement control)
{
if (this.ControlIsVisible(control))
{
try
{
GeneralTransform controlTransform = control.TransformToVisual(Application.Current.RootVisual);
Point offset = controlTransform.Transform(new Point(0, 0));
this.controlBounds[control] = new ControlRegion
{
Left = (float)offset.X,
Right = (float)(offset.X + control.ActualWidth),
Top = (float)offset.Y,
Bottom = (float)(offset.Y + control.ActualHeight)
};
}
catch (ArgumentException)
{
}
}
else
{
if (this.controlBounds.ContainsKey(control))
{
this.controlBounds.Remove(control);
}
}
}
private bool ControlIsVisible(FrameworkElement control)
{
// End case
if (control == null)
{
return true;
}
if (control.Visibility == Visibility.Collapsed)
{
return false;
}
return this.ControlIsVisible(control.Parent as FrameworkElement);
}
public bool TouchesControl(Vector2 touchPosition)
{
foreach (ControlRegion region in this.controlBounds.Values)
{
if (touchPosition.X >= region.Left && touchPosition.X <= region.Right &&
touchPosition.Y >= region.Top && touchPosition.Y <= region.Bottom)
{
return true;
}
}
return false;
}
public class ControlRegion
{
public float Left { get; set; }
public float Right { get; set; }
public float Top { get; set; }
public float Bottom { get; set; }
}
}
(edit) Updated example to work with parent elements changing Visibility.
Due to the way interop with XNA works, you will always get the touch input processed both by XNA and Silverlight - to some extent, XNA gets the priority, so the Silverlight acts on top of that. What you could do, if you need to ignore specific gesture locations (e.g. where Silverlight buttons are located), you could check the gesture position:
if (TouchPanel.IsGestureAvailable)
{
if (TouchPanel.ReadGesture().GestureType == GestureType.Tap)
{
if (TouchPanel.ReadGesture().Position == new Vector2(120, 120))
{
}
}
}
Is there a way to add a button control to a cell in inside a ListView in a WinForms app?
Here is a code of a class ListViewExtender that you can reuse. It's not a derived class of ListView, basically you just declare that a specific column is displayed as buttons instead of text. The button's text is the subItem's text.
It allows big sized list views without problems, does not use p/invoke, and also works with horizontal scrollbars (some code proposed as answers here don't or are quite slow with a great number of items). Note it requires the extended ListView to have FullRowSelect set to true and view type set to Details.
This is a sample code that uses it:
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent(); // you need to add a listView named listView1 with the designer
listView1.FullRowSelect = true;
ListViewExtender extender = new ListViewExtender(listView1);
// extend 2nd column
ListViewButtonColumn buttonAction = new ListViewButtonColumn(1);
buttonAction.Click += OnButtonActionClick;
buttonAction.FixedWidth = true;
extender.AddColumn(buttonAction);
for (int i = 0; i < 10000; i++)
{
ListViewItem item = listView1.Items.Add("item" + i);
item.SubItems.Add("button " + i);
}
}
private void OnButtonActionClick(object sender, ListViewColumnMouseEventArgs e)
{
MessageBox.Show(this, #"you clicked " + e.SubItem.Text);
}
}
}
Here is the ListViewExtender code and associated classes:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
namespace WindowsFormsApplication1
{
public class ListViewExtender : IDisposable
{
private readonly Dictionary<int, ListViewColumn> _columns = new Dictionary<int, ListViewColumn>();
public ListViewExtender(ListView listView)
{
if (listView == null)
throw new ArgumentNullException("listView");
if (listView.View != View.Details)
throw new ArgumentException(null, "listView");
ListView = listView;
ListView.OwnerDraw = true;
ListView.DrawItem += OnDrawItem;
ListView.DrawSubItem += OnDrawSubItem;
ListView.DrawColumnHeader += OnDrawColumnHeader;
ListView.MouseMove += OnMouseMove;
ListView.MouseClick += OnMouseClick;
Font = new Font(ListView.Font.FontFamily, ListView.Font.Size - 2);
}
public virtual Font Font { get; private set; }
public ListView ListView { get; private set; }
protected virtual void OnMouseClick(object sender, MouseEventArgs e)
{
ListViewItem item;
ListViewItem.ListViewSubItem sub;
ListViewColumn column = GetColumnAt(e.X, e.Y, out item, out sub);
if (column != null)
{
column.MouseClick(e, item, sub);
}
}
public ListViewColumn GetColumnAt(int x, int y, out ListViewItem item, out ListViewItem.ListViewSubItem subItem)
{
subItem = null;
item = ListView.GetItemAt(x, y);
if (item == null)
return null;
subItem = item.GetSubItemAt(x, y);
if (subItem == null)
return null;
for (int i = 0; i < item.SubItems.Count; i++)
{
if (item.SubItems[i] == subItem)
return GetColumn(i);
}
return null;
}
protected virtual void OnMouseMove(object sender, MouseEventArgs e)
{
ListViewItem item;
ListViewItem.ListViewSubItem sub;
ListViewColumn column = GetColumnAt(e.X, e.Y, out item, out sub);
if (column != null)
{
column.Invalidate(item, sub);
return;
}
if (item != null)
{
ListView.Invalidate(item.Bounds);
}
}
protected virtual void OnDrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
{
e.DrawDefault = true;
}
protected virtual void OnDrawSubItem(object sender, DrawListViewSubItemEventArgs e)
{
ListViewColumn column = GetColumn(e.ColumnIndex);
if (column == null)
{
e.DrawDefault = true;
return;
}
column.Draw(e);
}
protected virtual void OnDrawItem(object sender, DrawListViewItemEventArgs e)
{
// do nothing
}
public void AddColumn(ListViewColumn column)
{
if (column == null)
throw new ArgumentNullException("column");
column.Extender = this;
_columns[column.ColumnIndex] = column;
}
public ListViewColumn GetColumn(int index)
{
ListViewColumn column;
return _columns.TryGetValue(index, out column) ? column : null;
}
public IEnumerable<ListViewColumn> Columns
{
get
{
return _columns.Values;
}
}
public virtual void Dispose()
{
if (Font != null)
{
Font.Dispose();
Font = null;
}
}
}
public abstract class ListViewColumn
{
public event EventHandler<ListViewColumnMouseEventArgs> Click;
protected ListViewColumn(int columnIndex)
{
if (columnIndex < 0)
throw new ArgumentException(null, "columnIndex");
ColumnIndex = columnIndex;
}
public virtual ListViewExtender Extender { get; protected internal set; }
public int ColumnIndex { get; private set; }
public virtual Font Font
{
get
{
return Extender == null ? null : Extender.Font;
}
}
public ListView ListView
{
get
{
return Extender == null ? null : Extender.ListView;
}
}
public abstract void Draw(DrawListViewSubItemEventArgs e);
public virtual void MouseClick(MouseEventArgs e, ListViewItem item, ListViewItem.ListViewSubItem subItem)
{
if (Click != null)
{
Click(this, new ListViewColumnMouseEventArgs(e, item, subItem));
}
}
public virtual void Invalidate(ListViewItem item, ListViewItem.ListViewSubItem subItem)
{
if (Extender != null)
{
Extender.ListView.Invalidate(subItem.Bounds);
}
}
}
public class ListViewColumnMouseEventArgs : MouseEventArgs
{
public ListViewColumnMouseEventArgs(MouseEventArgs e, ListViewItem item, ListViewItem.ListViewSubItem subItem)
: base(e.Button, e.Clicks, e.X, e.Y, e.Delta)
{
Item = item;
SubItem = subItem;
}
public ListViewItem Item { get; private set; }
public ListViewItem.ListViewSubItem SubItem { get; private set; }
}
public class ListViewButtonColumn : ListViewColumn
{
private Rectangle _hot = Rectangle.Empty;
public ListViewButtonColumn(int columnIndex)
: base(columnIndex)
{
}
public bool FixedWidth { get; set; }
public bool DrawIfEmpty { get; set; }
public override ListViewExtender Extender
{
get
{
return base.Extender;
}
protected internal set
{
base.Extender = value;
if (FixedWidth)
{
base.Extender.ListView.ColumnWidthChanging += OnColumnWidthChanging;
}
}
}
protected virtual void OnColumnWidthChanging(object sender, ColumnWidthChangingEventArgs e)
{
if (e.ColumnIndex == ColumnIndex)
{
e.Cancel = true;
e.NewWidth = ListView.Columns[e.ColumnIndex].Width;
}
}
public override void Draw(DrawListViewSubItemEventArgs e)
{
if (_hot != Rectangle.Empty)
{
if (_hot != e.Bounds)
{
ListView.Invalidate(_hot);
_hot = Rectangle.Empty;
}
}
if ((!DrawIfEmpty) && (string.IsNullOrEmpty(e.SubItem.Text)))
return;
Point mouse = e.Item.ListView.PointToClient(Control.MousePosition);
if ((ListView.GetItemAt(mouse.X, mouse.Y) == e.Item) && (e.Item.GetSubItemAt(mouse.X, mouse.Y) == e.SubItem))
{
ButtonRenderer.DrawButton(e.Graphics, e.Bounds, e.SubItem.Text, Font, true, PushButtonState.Hot);
_hot = e.Bounds;
}
else
{
ButtonRenderer.DrawButton(e.Graphics, e.Bounds, e.SubItem.Text, Font, false, PushButtonState.Default);
}
}
}
}
The ListView itself (or ListViewItem) does not function as a container of any kind so no way to add controls directly, however it is doable. I have used this extended ListView with a lot of success: Embedding Controls in a ListView.
This is the BEST custom listview control for WinForms.
ObjectListView
To make the extender of Simon Mourier working is missing the following line:
extender.AddColumn(buttonAction);
This is, it should look like:
ListViewExtender extender = new ListViewExtender(listSummary);
ListViewButtonColumn buttonAction = new ListViewButtonColumn(2);
buttonAction.Click += OnButtonActionClick;
buttonAction.FixedWidth = true;
extender.AddColumn(buttonAction);
Maybe this could be of interest?
http://www.codeproject.com/KB/list/extendedlistviews.aspx
No, a standard Windows Forms ListView doesn't support embedded controls. You could try to build your own custom control, or you could use something like http://www.codeproject.com/KB/list/EXListView.aspx.
No and yes, ListView itself does not support such functionality, but you can create a button on top of it, so that it appears to the user as integral part of the listview. (I suppose this is what the ExtendedListView mentioned above does too).
Maybe it worths mentioning, the list view control might be designed in WPF as an usercontrol/custom control with buttons in its ListViewItems, and then use this control in the WinForms application, in an ElementHost control.
I accidentally come across a discussion before, hope this help: http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/ee232cc4-68c5-4ed3-9ea7-d4d999956504/
You could use a GlacialList. It allow you to put ANY control inside a list cell and it's simple to use. You will just need to join a GlacialList.dll document to the reference part of your Solution. If you click the link it will show you how it works and how to use it and download it.
If you have a System.IO.FileNotFoundException on the InitializeComponent() just download source code from the above link, compile and use this .dll (inside bin/Debug subfolder) to your project .
Here is an example of what it looks like:
This looks like the simplest answer I have come across... just added an ItemCommand to the ListView.
See this link: handle-the-button-click-event-from-an-asp-net-listview-control