WPF Listboxitem event trigger show popup - wpf

I am pretty much stuck on this and need some insight. When the user mouseover's a listboxitem I want to show some details regarding the item on which the mouse is currently over (hope I am making sense :( )
To demonstrate what I am wanting to achieve please see the sample code
public class Customer
{
public String FirstName { get; set; }
public Image CustomerPhoto { get; set; }
public Customer(String firstName, Image customerPhoto)
{
this.FirstName = firstName;
this.CustomerPhoto = customerPhoto;
}
}
public class Customers : ObservableCollection<Customer>
{
public Customers()
{
Image simpleImage = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(#"c:\image.jpg",UriKind.RelativeOrAbsolute);
bi.EndInit();
simpleImage.Source = bi;
Add(new Customer("Customer", simpleImage));
}
}
XAML
<ListBox ItemsSource="{StaticResource customers}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now when the user hovers over the listbox item, I want to show the customerphoto in a popup.
Many Thanks
P.S: code was "cooked up" while writing this post, so is for demo only. There will be multiple items in the listbox, hovering over each item must show the photo associated with that object.

Why not just use the ToolTip? In WPF, ToolTips don't have to be text-only
<TextBlock.ToolTip>
<ToolTip>
<Image Source="{Binding CustomerPhoto}" />
</ToolTip>
</TextBlock.ToolTip>

Related

ListBox bound to ObservableCollection not refreshing on view loaded

I have the following XAML containing a ListBox bound to an ObservableCollection
<ListBox
Margin="0,5"
Grid.Row="1"
Grid.ColumnSpan="3"
Visibility="{Binding ArePicturesAvailable, Converter={StaticResource BoolToVisConv}}"
SelectedItem="{Binding SelectedPicture}"
ItemsSource="{Binding Pictures, NotifyOnSourceUpdated=True}"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Margin="8"
Height="{Binding Size.Height}"
Width="{Binding Size.Width}"
Source="{Binding FullPath, Converter={StaticResource RelativeToFullConv}}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Since there is noticeable delay in populating the ListBox, I am attempting to defer this until the ListBox's containing view has loaded using Dispatcher.BeginInvoke as illustrated below:
public class PictureMarkerEditorViewModel
{
private PictureSelectorViewModel _pictureSelectorViewModel;
public string PhotoCollectionDirectory { get; set; }
protected ISymbolEditor GetEditorImpl(ISymbolInfo symbolInfo)
{
var picSymbolInfo = (PictureMarkerSymbolInfo)symbolInfo;
_pictureSelectorViewModel = new PictureSelectorViewModel(picSymbolInfo);
var editor = new PictureMarkerSymbolEditor(_pictureSelectorViewModel, picSymbolInfo);
editor.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
var photos = GetPhotoCollection();
_pictureSelectorViewModel.Pictures.AddRange(photos);
}));
//var photos = GetPhotoCollection();
//_pictureSelectorViewModel.Pictures.AddRange(photos);
return editor;
}
public IEnumerable<Picture> GetPhotoCollection()
{
if (string.IsNullOrEmpty(PhotoCollectionDirectory))
return null;
if (!Directory.Exists(PhotoCollectionDirectory))
throw new ArgumentException("Cannot show images from invalid directory " + PhotoCollectionDirectory + ".");
var files = Directory.GetFiles(PhotoCollectionDirectory, "*.png", SearchOption.AllDirectories);
return files.Select(f => new Picture(Path.GetFileName(f), f, ImageUtils.GetDimensions(f)));
}
}
where PictureSelectorViewModel.Pictures is simply an ObservableCollection of Picture:
public class PictureSelectorViewModel
{
private readonly ObservableCollection<Picture> _pictures= new ObservableCollection<Picture>();
public ObservableCollection<Picture> Pictures
{
get
{
return _pictures;
}
}
}
and Picture is a simple class containing Name and FullPath properties:
public class Picture
{
public string Name { get;set}
public string FullPath {get; set;}
public Size Size {get;set;}
}
I simply cannot get the list populated after it has loaded. If I populate the Pictures collection before the view is loaded (the commented part of the code, I see the images.
Any one know why?
TIA.

Tile view for ListView in WPf

How to simulate a tile view for a ListView in WPF?
I was trying the example shown here. But I can't get to the right solution... But I don't want to use that solution as I it's too much specific. So how will be the way to accomplilsh that?
EDIT: I'm trying this now and seems to work...
<ListBox ItemsSource="{Binding Path=ListObservableUsers, ElementName=AdminWindow}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<Image Source="{Binding Path=Picture}"></Image>
<Label Content="{Binding Path=Dni}"></Label>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Where the ElementName=AdminWindow comes from <Window .... x:Name="AdminWindow"
And I created my own ObservableCollection<MyUser>
public class MyUser
{
public MyUser(int id, string dni, Bitmap picture)
{
Id = id;
Dni = dni;
Image img = new Image();
FPhiMultipleSources.FromBitmapImage(img, picture);
Picture = img.Source;
}
public int Id { get; set; }
public string Dni { get; set; }
public ImageSource Picture { get; set; }
}
...
public UCAdminMain()
public UCAdminMain()
{
ListObservableUsers = new ObservableCollection<MyUser>();
InitializeComponent();
uiCurrent = SynchronizationContext.Current;
// Create users to add with its image
....
ListObservableUsers.Add(...);
}
And now I'm trying to put them inside a wrap panel. With no luck right now... Any ideas?
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
try to use a wrappanel
An ItemsControl with a WrapPanel as the ItemsContainer would probably be a good fit for what you are trying to do.

Get name of selected listbox item (WPF C#)?

all. I have an app that scans a picture folder and displays the images along with their names in a listbox. Each image and image name (displayed in a textblock next to the image) is stored in a horizontal stackpanel inside the listbox.
I've been trying all afternoon to find a way of displaying the image name in a textbox when the user selects it in the listbox. Sounds very simple, and I'm sure it is, but I can't seem to get it to work.
Can anyone point me in the right direction as to the best way of doing this? Thanks.
Here is my xaml if it helps:
<Grid>
<ListBox ItemsSource="{Binding AllImages}" Margin="0,0,262,0" Name="listBox1" MouseLeftButtonDown="listBox1_MouseLeftButtonDown">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Image}" Width="50" Height="50" Margin="6"/>
<TextBlock Text="{Binding Name}" Margin="6" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Height="23" HorizontalAlignment="Left" Margin="265,148,0,0" Name="textBox1" VerticalAlignment="Top" Width="198" />
</Grid>
And my code behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public class MyImage
{
private ImageSource _image;
private string _name;
public MyImage(ImageSource image, string name)
{
_image = image;
_name = name;
}
public override string ToString()
{
return _name;
}
public ImageSource Image
{
get { return _image; }
}
public string Name
{
get { return _name; }
}
}
public List<MyImage> AllImages
{
get
{
List<MyImage> result = new List<MyImage>();
string filePath = #"D:\Projects\Visual Studio 2010\WpfApplication5\WpfApplication5\bin\Debug\ImageFolder";
string[] files = Directory.GetFiles(filePath);
foreach (string filename in files)
{
try
{
result.Add(
new MyImage(
new BitmapImage(
new Uri(filename)),
System.IO.Path.GetFileNameWithoutExtension(filename)));
}
catch { }
}
return result;
}
}
}
Take a look at this question.
How do I bind a Listview SelectedItem to a Textbox using the TwoWay mode?
In your case use
<TextBox Height="23"
HorizontalAlignment="Left"
Margin="265,148,0,0"
Name="textBox1"
VerticalAlignment="Top" Width="198"
Text="{Binding SelectedItem.Name, ElementName=listBox1}"/>
To retrieve the selected image from code, you have at least 3 options (I assume your images are represented by a class ImageItem)
Set IsSynchronizedWithCurrentItem to true on your ListBox, and use the following code to retrieve the selected item:
ICollectionView view = CollectionViewSource(AllImages);
ImageItem selectedImage = (ImageItem)view.CurrentItem;
Bind the SelectedItem of the ListBox to a property in your DataContext:
<ListBox .... SelectedItem="{Binding SelectedImage}">
Access the SelectedItem property directly from code-behind:
ImageItem selectedImage = (ImageItem)listBox1.SelectedItem;
Of course, if you just want to show the name in a TextBlock, you can use Russell Troywest's solution

Bind to Uri in WPF

I am binding a list of urls to a ListBox (MVVM) and found that if the model is a string[] everything works fine but if it's a List<Uri> then no items are displayed in my ListBox. I assume this is because WPF doesn't know how to convert a Uri into a string but
I'd figure it would just call ToString() which is what I want
I don't know how to tell WPF how to do the right thing
Here's my XAML:
<ListBox Height="200" ItemsSource="{Binding Path=UrlsFound, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate DataType="String">
<TextBlock Text="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now as long as UrlsFound is a string[] the binding works, but if I refactor to make it a List<Uri> nothing is displayed in the ListBox. I changed the DataType="String" to "Uri" but that didn't help
There must be something else wrong as I've copied your XAML and it works.
Here's my code-behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
urlsFound.Add(new Uri("http://www.google.com"));
urlsFound.Add(new Uri("http://www.google.com"));
urlsFound.Add(new Uri("http://www.google.com"));
this.DataContext = this;
}
private List<Uri> urlsFound=new List<Uri>();
public List<Uri> UrlsFound
{
get { return urlsFound; }
set { urlsFound = value; }
}
}

WPF Listbox Images from a database

(How long have we been using OpenIDs? I don't seem to have one connected to any provider and no FAQ on the planet seems to tell you what to do when you lose your OpenID. I've had to create a new account. Argh!)
I'm trying to fill a (carousel) listbox from a database, but I can't get the images to display. Every single example on the net assumes you have two or three jpegs in a folder instead of in memory :(
My item class is:
public class PicCollection : ObservableCollection<CarouselItem>
{
public PicCollection()
{
}
}
public class CarouselItem
{
public int ItemID { get; set; }
public string ItemName { get; set; }
public string ItemDesc { get; set; }
public Image ItemImage { get; set; }
public CarouselItem(int NewItemID, string NewItemName, string NewItemDesc, Image newItemImage)
{
this.ItemID = NewItemID;
this.ItemName = NewItemName;
this.ItemDesc = NewItemDesc;
this.ItemImage = newItemImage;
}
}
I fill a PicCollection successfully from the db(using a byte array for the image), and try to display the name and image with
<DataTemplate x:Key="TestDataTemplate2" >
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="CarName"
Text="{Binding ItemName}"
Padding="15,15"
Foreground="Yellow" />
<Image Source="{Binding Source=ItemImage}"
Stretch="Fill" />
</StackPanel>
</DataTemplate>
Listbox is simply:
<ListBox Name="lstTest" ItemsSource="{StaticResource TestDataSource}"
ItemTemplate="{StaticResource TestDataTemplate2}"></ListBox>
ItemName displays ok, ItemImage does not. I've tried {Binding ItemImage} as well. Most examples use {Binding Path=ItemImage} but that's where the ItemImage would be a string containing the path, not the actual image itself.
I'm pulling my hair out. Nothing I do makes the images appear. If I create an image control and manually assign the contents of an ItemImage, however, it displays fine. What am I doing wrong?
Your ItemImage property is an Image (control). Make it an ImageSource, such as a System.Windows.Media.Imaging.BitmapImage. Then you can bind <Image Source="{Binding ItemImage}" />.
Since your "ItemImage" property is already an image, you might be able to get away with just using a ContentControl to display the image directly:
<ContentControl Content="{Binding Image}" />

Resources