I have been working with WPF all of 2 days, coming from ASP.NET so bear with me!
I am populating a ComboBox with xml filenames from a directory and adding a icon to each item. I have everything working just fine but I am wondering if there is a "better", more "efficient" way of doing this. As I stated, I am just getting started with WPF and I want to go about things the "right" way. My working code is below, can or should I be going about this a different way? Thanks in advance for any pointers!
<ComboBox Height="24" HorizontalAlignment="Left" Margin="153,138,0,0" Name="cmbFiles" VerticalAlignment="Top" Width="200" //>
private void FillSrFileCombo()
{
string[] dirFiles = Directory.GetFiles(#"D:\TestFiles", "*.xml");
foreach (string datei in dirFiles)
{
string fileName = System.IO.Path.GetFileName(datei);
System.Windows.Controls.StackPanel stkPanel = new StackPanel();
stkPanel.Orientation = Orientation.Horizontal;
cmbFiles.Items.Add(stkPanel);
System.Windows.Controls.Image cboIcon = new Image();
BitmapImage bitMap = new BitmapImage();
bitMap.BeginInit();
bitMap.UriSource = new Uri(#"tag.jpg", UriKind.Relative);
bitMap.EndInit();
cboIcon.Source = bitMap;
cboIcon.Height = 15;
stkPanel.Children.Add(cboIcon);
System.Windows.Controls.TextBlock cboText = new TextBlock();
cboText.Text = " - " + fileName;
stkPanel.Children.Add(cboText);
}
}
I have answered a similar question an hour ago see here :http://stackoverflow.com/questions/9637514/add-usercontrol-to-listbox-wpf.
I will recap the most important parts here based on your example
In the XAML you need to create a "DataTemplate", that is the XAML representation of your file object - in your case an image + file name. You can create this Datatemplate as a resource and assign it to your ComboBox or simply create it in the combobox if you don't plan to reuse it
<ComboBox ItemsSource="{Binding Files}">
<ComboBox.ItemTemplate>
<StackPanel>
<Image Source="{Binding FileImage}" Height="16" Width="16"/>
<TextBlock Margin="5" Text="{Binding FileName}" />
</StackPanel>
</ComboBox.ItemTemplate>
</ComboBox>
In your Codebehind, you need to create a structure that represets the data you want to present in your combobox - let's say a "FileInfo" class. The FileInfo class needs to expose the "FileImage" and "FileName" as properties so you can bind to them (as seen above).
Next, you need to create a collection of such objects in the code-behind of the xaml you put your ComboBox in. The collection needs to be an ObservableCollection.
So you would have smth like this:
public class FileInfo
{
public ImageSource FileImage { get; set; }
public string FileName { get; set; }
}
and then in the MainWindow.xaml.cs
public ObservableCollection Files { get; private set; }
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
Files = new ObservableCollection();
foreach (string datei in dirFiles)
{
var fName = System.IO.Path.GetFileName(datei);
BitmapImage bitMap = new BitmapImage();
bitMap.BeginInit();
bitMap.UriSource = new Uri(#"tag.jpg", UriKind.Relative);
bitMap.EndInit();
Files.Add(new FileInfo(){FileName=fName, FileImage = bitMap});
}
}
You will still need to read a lot about why this will work. I recomend reading about DataTemplates DataBinding, ObservableCollection and in the end, read about MVVM, a pattern that ties all this stuff nicely and allows you to harness all the WPF power and decouple yor logic from the UI.
One way that you should consider for WPF/Silverlight/WP7 apps is the MVVM design pattern.
In this instance you would have a view model containing the collection of items for your ComboBox, and you would use a binding expression to set the ItemsSource of the ComboBox. You would then template the ComboBox to display your item images.
Look into data binding and data templating, the only C# code you should need here is to get the files (even though you could also do that in XAML using something like an ObjectDataProvider)
Related
Using xamarin forms trying to display an image using binding...followed a few online Q's already including the answer on this one https://stackoverflow.com/questions/30850510/how-to-correctly-use-the-image-source-property-with-xamarin-forms just cant seem to get the image to display...yes I knoW I can load the image by using <Image Source="Bud.jpeg"></Image> which works fine....but I would like to display it using binding....
eg..
xaml
<Image Source="{Binding imageTest}"></Image>
code
var imageTest = new Image { Aspect = Aspect.AspectFit };
imageTest.Source = ImageSource.FromFile("Guinness.jpg");
anyone any idea why? thanks
You can only bind to public properties
<Image Source="{Binding imageTest}" />
then declare a public property in your code-behind
public string imageTest { get; set; }
and then set the property value and BindingContext
imageTest = "Guinness.jpg";
this.BindingContext = this;
The first is the first, I'm very newbie on .NET, I was developed un Visual Basic 6, but now I'm trying to make an application to Windows Phone 8.0.
At this time I'm trapped with a (maybe simple) problem.
I have a xaml page with control, and it is part of LongListSelector thats implements an Observable Collection of "Prenda" class.
...
var prendasData = from r in db.Prendas select r;
PrendasItems = new ObservableCollection<Prenda>(prendasData);
llsPrendas.ItemsSource = PrendasItems;
...
The XAML portion is the code bellow, please, i know that severals things maybe are wrong, but I'm learning alone, be patient with me :D
<phone:LongListSelector x:Name="llsPrendas" Margin="0,0,-12,0" ItemsSource="{Binding Prendas}" SelectionChanged="llsPrendasSelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Width="100" Height="100" Margin="5,0,0,0" Source="{Binding PrendaImageURI}" ImageFailed="errcargaimg"/>
<StackPanel Orientation="Vertical">
<TextBlock FontWeight="Normal" Text="{Binding Nombre}" Margin="10,0,0,0" />
<TextBlock FontWeight="Normal" Text="{Binding Precio}" Margin="10,0,0,0" />
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
The problem is the Image Control. It doesn't show anything and if I debug it, the error the message is: "AG_E_NETWORK_ERROR", googled this error and I know that is (in this case) same as "File not found." But I'm sure thats file exists. because I seen it with IsoStoreSpy, at /Shared/Media/ShellContent/WP_XXX.jpg, i think that the root of the Isolated Storage is called isostore:/ and the complete URI must be: isostore:/Shared/Media/ShellContent/WP_XXX.jpg.
This string is saved as string column in the class, and I create a property thats use this string to make an Uri to use to bind the Source property of Image control at design time.
(portion of class declaration)
[Column]
public string Foto
{
get
{
return foto;
}
set
{
if (foto != value)
{
foto = value;
NotifyPropertyChanged("Foto");
}
}
}
public Uri PrendaImageURI
{
get
{
return new Uri(this.Foto, UriKind.Absolute);
}
}
I'm going crazy, because I cannot understand why it's doesn't work. Can somebody help me? (Sorry for my bad english)
You can not read from Isolated storage using URI, You have to read using IsolatedStorageFile class:
private static BitmapImage GetImageFromIsolatedStorage(string imageName)
{
var bimg = new BitmapImage();
using (var iso = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = iso.OpenFile(imageName, FileMode.Open, FileAccess.Read))
{
bimg.SetSource(stream);
}
}
return bimg;
}
You can find more details from below Posts:
How get image from isolated storage
How to load an image from isolated storage into image control on windows phone?
I solved it with Pratik Goyal help (thank you, very much!), making a BitmapImage Property in the class "Prendas", taking The Foto string data. Later I will take more careful with the exception control, but is a good start, I think.
public BitmapImage ImageFoto
{
get
{
return GetImageFromIsolatedStorage(Foto);
}
}
public BitmapImage GetImageFromIsolatedStorage(string imageName)
{
var bimg = new BitmapImage();
using (var iso = IsolatedStorageFile.GetUserStoreForApplication())
{
using (var stream = iso.OpenFile(imageName, FileMode.Open, FileAccess.Read))
{
bimg.SetSource(stream);
}
}
return bimg;
}
Just for the children:
Silverlight notifies this with an AG_E_NETWORK_ERROR / HRESULT=0x80131500. Which of course can't be found anywhere on the web and of course means jack and shit to me and not only to me.
Is the UI being notified of the PrendaImageURI property changing?
Try adding
NotifyPropertyChanged("PrendaImageURI");
when your Foto property is set.
I have this block of code as you can see in the screen print correctly loads the data you want and store the list of objects PopularVideos:
item { Title = Hey Porsche, Url = http://www.unnu.com/wp-content/plugins/wordpress-popular-posts/timthumb.php?src=http://www.unnu.com/wp-content/uploads/2013/03/019.jpg&h=65&w=275 } <>f__AnonymousType0<string,string>
item.Title "Hey Porsche" string
item.Url "http://www.unnu.com/wp-content/plugins/wordpress-popular-posts/timthumb.php?src=http://www.unnu.com/wp-content/uploads/2013/03/019.jpg&h=65&w=275" string
Need to load these objects in my list box with binding or has otherwise also can be. But the windows phone does not work with DataSource and DisplayMember.
My XAML:
<ListBox Name="listBoxPopular">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Name="imagem" Source="{Binding Path=Url}"/>
<TextBlock Text="{Binding Titulo}" Tap="HyperlinkButton_Tap" FontSize="30" Foreground="#FF159DDE" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PanoramaItem>
My Class is:
class PopularVideos
{
public PopularVideos() { }
public PopularVideos(string titulo, string url)
{
Titulo = titulo;
BitmapImage Img = new BitmapImage(new Uri(url));
}
public string Titulo { get; set; }
public Uri Url { get; set; }
}
and my codebehind is:
_popVideos = new List<PopularVideos>();
var data = e.Document.DocumentNode.SelectSingleNode("//div[#class='content']")
.Descendants("img")
.Select(img => new
{
Title = img.Attributes["alt"].Value,
Url = img.Attributes["src"].Value,
}).ToList();
foreach (var item in data)
{
PopularVideos pop = new PopularVideos(item.Title, item.Url);
_popVideos.Add(new PopularVideos(item.Title, item.Url));
}
listBoxPopular.ItemsSource = _popVideos;
This code works because they are carrying the images and links in the objects, just can not bring up in my list box.
Have a bindable ObservableCollection<Item> (preferrably in a ViewModel).
Use the ListBox.ItemsSource property to bind to said ObservableCollection<Item>. The standard binding rules apply.
Each of the items in ListBox will be a representation of the items in the core collection that is bound to the control, so bind to its properties the same way you would to anything else.
It's reply to comment:
Ok, please read once again the article that #Den send to you. And please remove DataContext Property from ListBox, add x:Name="myList" to ListBox and in code-behind: myList.DataContext = this; This is not the best solution, but it's easy to understand and firstly you need to understand it :) Best regards.
I have the following classes
ImageViewModel: INotifyPropertyChanged
{ ...
String Url;
}
AdViewModel: INotifyPropertyChanged
{ ...
ImageViewModel Image
}
The AdViewModel perodicaly changes the Image property (animated Ad).
When I have the following XAML:
<Grid>
<Image Source="{Binding Image.Url}"
Width="{Binding Image.Width}"
Height="{Binding Image.Height}" />
And set the Grids DataContext to an instance of AdViewModel everything works as expected. But I need to create the XAML in C# code to use it elsewhere. Creating a Grid and appending an Image as its child is easy, but how to a create the bindings?
try something along the lines of
AdViewModel vm = new AdViewModel;
Binding binding = new Binding
{
Path = new PropertyPath("Width"),
Source = vm.Image
};
nameOfGridInXaml.SetBinding(Image.WidthProperty, binding);
I found an easier way. I created the XAML as a UserControl, saved it in a file (Templates\SkyScrapper.xaml). Then instead of creating the controls in C# a just load the XAML File
var _Path = #"Templates\SkyScrapper.xaml";
var _Folder = Windows.ApplicationModel.Package.Current.InstalledLocation;
var _File = await _Folder.GetFileAsync(_Path);
var _ReadThis = await Windows.Storage.FileIO.ReadTextAsync(_File);
DependencyObject rootObject = XamlReader.Load(_ReadThis) as DependencyObject;
var uc = (UserControl)rootObject;
and set its DataContext
uc.DataContext = ad;
There is now no need to create the bindings in C#, they are defined in the XAML file.
I'm kinda new at both programming, and WPF. I know that this is pretty easy, but I nothing I've tried as worked so far.....
I want to fill a Listbox with images from a folder. I also need to know how to force my listbox from allowing scrolling to the side. So far I haven't stumbled upon anything that seems to work.
Here is my C# code that adds the files in chosen folder to a List Basically I want the Listbox to be use to keep a history log of the pictures that the user has chosen as backgrounds.
IList<Bitmap> HistoryImages = new List<Bitmap>();
foreach(String imagefile in Directory.GetFiles( #"C:\ProgramData\etc" ))
{
HistoryImages.Add( new Bitmap( imagefile) );
}
Found something that worked for me!
XAML Code:
<ListBox Name="ImageLog" Background="Transparent" IsEnabled="True"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
ItemsSource="{Binding Path=Image}" BorderThickness="0"
SelectionChanged="ImageLog_SelectionChanged_1">
</ListBox>
C# Code:
foreach(string myFile in Directory.GetFiles( #"C:\ProgramData\MyApp" ) )
{
System.Windows.Controls.Image myLocalImage = new System.Windows.Controls.Image(); ;
myLocalImage.Height = 200;
myLocalImage.Margin = new Thickness( 5 );
BitmapImage myImageSource = new BitmapImage();
myImageSource.BeginInit();
myImageSource.UriSource = new Uri( #"file:///" + myFile );
myImageSource.EndInit();
myLocalImage.Source = myImageSource;
filePath.Add( myFile );
ImageLog.Items.Add(myLocalImage);
}
This requires the basics of data binding and data templating. (If you read and understood all that you should be able to do it.)
About the scrolling, set ScrollViewer.HorizontalScrollBarVisibility as attached property on the ListBox to Disabled