WPF Listbox Images from a database - wpf

(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}" />

Related

CheckBox content from two fields of a custom Object in XAML/WPF

In the below code:
RectifiedString is property of a class say 'X'.
i.e List<StringDetails> RectifiedString { get; set; }.
StringDetails has fields: InitialString, FinalString, isSelected. I want to have a checklistListBox with the list of rectified strings. However, the content of the CheckBox is a string which is a combination of InitialString & FinalString.I am trying to get something like the first box, but I am getting the second box.
<ListBox Grid.Row="6"
ScrollViewer.VerticalScrollBarVisibility="Auto" ItemsSource="{Binding RectifiedString}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox>
<CheckBox.Content>
<StackPanel>
<Label Content="Initial String"/>
<TextBlock Text="{Binding InitialString}"/>
<Label Content="Final String"/>
<TextBlock Text="{Binding FinalString}"/>
</StackPanel>
</CheckBox.Content>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
Note :
I have taken care of the scope of Class X.
When I replace the Binding on textblocks with static strings, they work fine except that it has additional padding around the textblock.
In the image, there is a small correction. I am not shown the Initial String in any of the three items in the list. I am shown the correct final string though. Basically, it is only binding one textblock only - the final string in this case.
Another problem that I was facing: I am unable to bind the isChecked Property of the CheckBox with the isSelected property of RectifiedString. It is showing me errors if I add isChecked="{Binding isSelected}" inside the <CheckBox>
Tried this and it works on my pc. If i'm not wrong you said you had a class like:
public class StringDetails
{
public string InitialString
{ get; set; }
public string FinalString
{ get; set; }
}
And let's say you have your list initialized like
RectifiedString = new List<StringDetails>() {new StringDetails { InitialString = "AAA", FinalString= "BBB" }, new StringDetails { InitialString = "BBB", FinalString = "AAA" } };
You should check your "stringDetails" names because it works.
You could post your codebehind/MVVM code so we can take a look there.

WPF Binding property of an Object contained within Another Object contained in a List

I have a ListBox showing some information about Cars. So, I have ViewModel with:
private ObservableCollection<Car> _cars;
public ObservableCollection<Car> CarsList
{
get
{
return _cars;
}
set
{
_cars= value;
OnPropertyChanged("CarsList");
}
}
I have implemented PropertyChanged, and I get my list of cars just fine. I load my CarsList from within my ViewModel (not from Window).
My Car object has Name, Country, Url and Image object like below:
public class Car
{
public string Name { get; set; }
public string Country { get; set; }
public Image Image { get; set; }
}
public class Image
{
public string Url { get; set; }
}
I need to bind Name, Country and Image.Url to text boxes in my ListBox. I did this like:
<ListBox Name="lbEvents" ItemsSource="{Binding Path=CarsList}">
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<StackPanel>
<TextBlock Name="txtCarName" Text="{Binding Path=Name}" />
<TextBlock Name="txtCarCountry" Text="{Binding Path=Country}"/>
<!-- How do I bind this properly? -->
<Image Name="imgCarImage" Source="{Binding Path=Car.Image.Url}" />
</StackPanel>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Problem is that my Car Name and Country are properly displayed in ListBox for each Car. But Car.Image.Url shows nothing. I am new to WPF, how do I bind properly the Image.Url to the ImageBox?
Just as Name and Country are properties of the Car class, so is Image. Look at the way you are binding to Name and Country, you don't specify it as Car.Name, so why do that for Image? Just do it as Image instead of Car.Image.

Can anybody provide any simple working example of the Conductor<T>.Collection.AllActive usage?

It's a bit strange, but I really can't find a working example anywhere.
By the way, I'm using a ViewModel-first approach (in WPF) if this is important.
Thank you in advance.
If you have a look at the discussion here you will see that the intent of AllActive is to compose several Views/ViewModels into a containing ViewModel. Judging from your previous comments it seems as if this is what you were expecting but I figured I'd at least reference it here.
You then mention activating 3 different ViewModels at different regions of the View. The way I've handled this in the past is to have separate properties for binding/referencing the ViewModels in the View, and then just adding all of them to Items to get the Conductor behavior.
public sealed class MyViewModel : Conductor<Screen>.Collection.AllActive
{
public MyViewModel(IMagicViewModelFactory factory)
{
FirstSubViewModel = factory.MagicallyGiveMeTheViewModelIWant();
SecondSubViewModel = factory.MagicallyGiveMeTheViewModelIWant();
ThirdSubViewModel = factory.MagicallyGiveMeTheViewModelIWant();
Items.Add(FirstSubViewModel);
Items.Add(SecondSubViewModel);
Items.Add(ThirdSubViewModel);
}
public Screen FirstSubViewModel { get; private set; }
public Screen SecondSubViewModel { get; private set; }
public Screen ThirdSubViewModel { get; private set; }
}
And in MyView you would have something like this. Of course you could put these ContentControls wherever you want to in the view.
<StackPanel>
<ContentControl x:Name="FirstSubViewModel" />
<ContentControl x:Name="SecondSubViewModel" />
<ContentControl x:Name="ThirdSubViewModel" />
</StackPanel>
Another common use for AllActive is when you have a list of items. But the items are complex enough to warrant having their own View/ViewModels that require activation. In that case you would not have to have separate properties for the views as you would just set the x:Name of the list control to Items.
You can do implement like below, use TreeViewModel at the place of TabViewModel
ShellView
<DockPanel>
<Button x:Name="OpenTab"
Content="Open Tab"
DockPanel.Dock="Top" />
<TabControl x:Name="Items">
<TabControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding DisplayName}" />
<Button Content="X"
cal:Message.Attach="DeactivateItem($dataContext, 'true')" />
</StackPanel>
</DataTemplate>
</TabControl.ItemTemplate>
</TabControl>
</DockPanel>
ViewModel
public class ShellViewModel : Conductor<IScreen>.Collection.AllActive {
System.Collections.Generic.List<TabViewModel> tabViewModelCollection = new System.Collections.Generic.List<TabViewModel>();
public void ActiveAllTab() {
foreach (var tabViewModel in tabViewModelCollection)
{
ActivateItem(tabViewModel);
}
}
}

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.

Binding data to ComboBox WPF

I am newbie to WPF, and needs help to bind data into the ComboBox. The xaml file contains the tag below.
<UserControl x:Class="SKAT.Postfordeler.Client.UI.View.ChooseInboxView"
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"
mc:Ignorable="d"
d:DesignHeight="42" d:DesignWidth="598">
<Grid>
<StackPanel Orientation="Horizontal">
<ComboBox Name="_currentInbox" Width="180" Margin="5" Height="22" DataContext="{Binding}" />
<Label Content="Et job kører allerede i denne indbakke (1500 ud af 1700 poster behandlet)" Name="_currentProcess" Margin="5" Height="25" />
</StackPanel>
</Grid>
//Inbox class , this class was implemented in seperate project
namespace SKAT.Postfordeler.Shared.DataTypes
{
[DataContract]
public class Inbox
{
[DataMember]
public String Id { get; set; }
[DataMember]
public String Folder { get; set; }
[DataMember]
public Rule Rules { get; set; }
}
}
//This code is located in the controller, the Activate method will fire when the MainWindow was executed
public void Activate()
{
var configuration = _configurationManager.GetConfiguration();// this method gets the xaml file settings
_chooseInboxView.FillInboxes(configuration.Inboxes); // Inboxes data binds to combobox
}
and in the View code behind, I created a method to bind the data which contains a type of list
public void FillInboxes(List<Inbox> inboxes)
{
DataContext = inboxes;
}
But it won't works,Any help please?
I assume your Inbox class consists of two properties (for simplicity), but there may be any number of them:
public class Inbox
{
public int ID { get; set; }
public string Text { get; set; }
}
You write a DataTemplate, for example:
<Grid.Resources>
<DataTemplate x:Key="InboxTemplate">
<WrapPanel>
<TextBlock Text="{Binding Path=ID}"/>
<TextBlock>:</TextBlock>
<TextBlock Text="{Binding Path=Text}"/>
</WrapPanel>
</DataTemplate>
</Grid.Resources>
Then correct your ComboBox declaration like:
<ComboBox Name="_currentInbox" Width="180" Margin="5" Height="22" ItemsSource="{Binding}" ItemTemplate="{StaticResource InboxTemplate}" />
Finally you set DataContext of your ComboBox to your List<Inbox>:
public void FillInboxes(List<Inbox> inboxes)
{
_currentInbox.DataContext = inboxes;
}
EDIT: As you've asked for a simpler solution, you can just override ToString() method of your Inbox class:
protected override string ToString()
{
return ID.ToString() + ":" + Text;
}
Instead of DataContext={Binding} you should have ItemsSource={Binding}.
The data context for any frameworkelement in the visual tree is by default {Binding}.
<ComboBox Name="_currentInbox"
SelectedItem="Hoved"
Width="180"
Margin="5"
Height="22"
DisplayMemberPath="Name"
ItemSource="{Binding}" />
Also for the combobox to display text of the items correctly I suppose you need DisplayMemberPath too. I assumed the property from Inbox class that you need to display is Name. Please replace with your relevant property name.
If your Inbox class is like,
public class Inbox
{
public int ID { get; set; }
public string Text { get; set; }
}
And if you do not want to change your xmal, the code behind method should be like this,
public void FillInboxes(List<Inbox> inboxes)
{
_currentInbox.DisplayMemberPath = "Text"; // To display the 'Text' property in the combobox dropdown
//_currentInbox.DisplayMemberPath = "ID"; // To display the 'ID' property in the combobox dropdown
_currentInbox.DataContext = inboxes;
}

Resources