I have a huge amount of images (10000 +) all of which I know are JPEGS (from the file header of FF D8)
basically I search a database which gives me matching filenames for the search. I then want to show these images in a list view.
my problem is that none of the images have extensions and when I try to load the image into the list view I get the following error:
No imaging component suitable to complete this operation was found
I believe this is because it cant determine the file type to open it.
I am attempting to bind to a path property using a value converter to return the BitmapImage which will be displayed in the list view Image control.
the converter is here:
public class PathToImageSourceConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (File.Exists(value.ToString()))
{
//these files are JPEGs but without an extension
return new BitmapImage(new Uri(value.ToString()));
}
else return new BitmapImage();
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The WPF control in XAML is here:
<!-- The list view containing the images, bound to the logos collection in the background -->
<ListView x:Name="lstImages"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Shoeprints}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
SelectedIndex="{Binding SelectedImageIndex}">
<!-- Use a wrap panel so that the images appear side by side instead of one in each row -->
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<!-- Sets the template for the data to be displayed -->
<ListView.ItemTemplate>
<DataTemplate>
<!-- Defines the actual image being displayed -->
<Image Width="50"
Height="50"
Margin="5"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
Source="{Binding ShoePrintImagePath, Converter={StaticResource PathToImageSourceConverter}}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
and ShoePrintImagePath is a string property in the ShoePrints class. I know that the rest of this works as I have successfully bound to other properties in this class in this list vew but I cant work this out for images.
C#
VS 2012
WPF
Xaml
Related
I have a collection of functions that I want to plot them on canvas. So I think the correct data type to plot these functions is Polyline.
So I need a converter to convert these functions into collection of polylines and finally show them in canvas.
Here is XAML code.
<ItemsControl ItemsSource="{Binding WaveCollection,
RelativeSource ={RelativeSource FindAncestor, AncestorType={x:Type Window}},
Converter={StaticResource PlotterConverter}}" Margin="10,10,0,239" HorizontalAlignment="Left" Width="330">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="GhostWhite" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
And here is part of the converter which converts waveforms into polylines. The binding mode is one way.
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var collection = value as IEnumerable<Waveform>;
return new ObservableCollection<Polyline>(GetPlots(collection));
}
However when I put break point, I notice that it only fires once when the program starts. The collection is empty yet so nothing especial happens, but after that, when I add items to collection nothing happens. No event fires. Why?
To make sure I also added this code to converter to see if it really fires or not but nothing happened.
var collection = value as ObservableCollection<Waveform>;
collection.Clear(); // this is supposed to clear collection. if binding works correct!
//...
Note that I also binded this collection into listview to show information of waves which works fine when the collection updates.
Edit:
I guess the problem is this part return new ObservableCollection<Polyline>... which changes the collection in first run and will mess up binding?
Instead of converting the whole ObservableCollection at once, use a converter that takes one item at a time.
In this case, this means that you specify the type of control each item shall be displayed as by defining the ItemsControl's ItemTemplate in XAML:
<ItemsControl ItemsSource="{Binding WaveCollection,
RelativeSource ={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" Margin="10,10,0,239" HorizontalAlignment="Left" Width="330">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="GhostWhite" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Polyline Points="{Binding, Converter={StaticResource PlotterConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
The PlotterConverter will now be passed each item on its own, so all it needs to do is convert a Waveform object to an object of type PointCollection (since the Polyline's Points property is of type PointCollection):
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var item = value as Waveform;
return new PointCollection(GetPlot(item));
}
Of course, the GetPlot method needs to be adapted as well.
I need to create a WPF ListBox that supports two features:
Content Converter Binding:
The items in the ListBox need to be passed to a converter that converts the items to a text format.
Display items in a way that lets users select and copy text from ListBox items
I need the text of each ListBox item to be selectable. Users want to use their mouse to drag-to-select parts of the elements so they can copy the text to their clipboard.
I implemented [this copy/paste solution][1] but it does not let a user select parts of the ListBox item text, rather it supports copying the entire text.
I'm able to create a ListBox using the converter, but I can not figure out how to put the converted text into a control that lets users select the displayed text. Here is what I have:
<ListBox Name="FinishedTestErrorsListBox"
FontSize="12"
ItemsSource="{Binding Path=SelectedComparisonResult.TestFailItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding Converter={StaticResource testFailItemConverter}}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I've tried adding a TextBox to the DataTemplate as shown below...
<TextBlock Text="{Binding Converter={StaticResource testFailItemConverter}}"/>
... but this creates a runtime error caused by sending the wrong type of object to the converter. I know here I'm not setting up the converter binding properly, though I don't have a good grasp on how I should setup the binding here or why this causes errors.
So, my question is:
What content container can I use to let users select text from the individual ListBox items?
Thank you for any help,
Charlie
EDIT
Here's the converter code...
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
ITestFailItem i = (ITestFailItem)value;
return i.Itemize();
}
EDIT 2
The following runtime error is throw when the ListBox is first initialized:
An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: Provide value on 'System.Windows.Baml2006.TypeConverterMarkupExtension' threw an exception
EDIT 3
The culprit is a line of code I'd omitted from the original snippet as I thought it was irrelevant - I've learned a good lesson along the way!
Extension Question
Why does the following snippet cause an error? How can I achieve the desired affect of making the textbox span the entire containing grid?
<TextBox Width="*"
Text="{Binding Path=., Converter={StaticResource testFailItemConverter}}"/>
Try this. TextBlocks don't support text selection, but TextBoxes do. You just have to make it read-only so the user can't modify the text, and change its border thickness and background so they look like labels:
<ListBox Name="FinishedTestErrorsListBox"
FontSize="12"
ItemsSource="{Binding Path=SelectedComparisonResult.TestFailItems}">
<ListBox.Resources>
<converter:TestFailItemConverter x:Key="testFailItemConverter" />
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=.,
Converter={StaticResource testFailItemConverter},
Mode=OneWay}"
BorderThickness="0"
Background="Transparent"
IsReadOnly="True"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Have You tried TextBox? You can select text inside textbox. Path have to be changed to Path=.
<TextBox Text="{Binding Path=., Converter={StaticResource testFailItemConverter}}" />
There is not much code to work with, but this code works for me:
xaml:
<Window x:Class="StackOverflowTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:StackOverflowTest"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<s:TestFailItemConverter x:Key="testFailItemConverter" />
</Window.Resources>
<Grid>
<ListBox Name="FinishedTestErrorsListBox"
FontSize="12"
ItemsSource="{Binding Path=SelectedComparisonResult.TestFailItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<!--<ContentControl Content="{Binding Converter={StaticResource testFailItemConverter}}"/>-->
<TextBox Text="{Binding Path=., Converter={StaticResource testFailItemConverter}}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Model's code:
public class Dummy
{
public ObservableCollection<string> TestFailItems { get; set; }
public Dummy()
{
TestFailItems = new ObservableCollection<string>(new List<string> { "a", "b" });
}
}
public class Model
{
public Dummy SelectedComparisonResult { get; set; }
public Model()
{
SelectedComparisonResult = new Dummy();
}
}
Converter's code:
public class TestFailItemConverter: IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return "aa";
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value;
}
}
We're in the process of updating our gallery WPF application which contains our custom styled controls. The design is to have a toggle to show the XAML behind those custom controls, for easy reference and a guide for new colleagues.
The way I've currently implemented this is by creating two .xaml files, one containing just the controls, one with the controls and a textblock with the XAML coded used to implement those controls.
This is not something that's easily maintainable, since the quotes, >,< and other characters are not escaped in XAML strings. For reference this is what I have now in one of the 'Show code' views:
<TextBlock Visibility="Collapsed" Margin="5" Text="<controls:AutoCompleteTagBox
Name="AutoCompleteTagBoxWithStrings"
Margin="5"
ItemsSource="{Binding Names}"
FilterMode="Contains" />
<ListBox
ItemsSource="{Binding ElementName=AutoCompleteTagBoxWithStrings, Path=SelectedItems}"
Grid.Column="1"
BorderBrush="{StaticResource Blue}" BorderThickness="1" />"/>
As you can see, it doesn't look nice and once you update one of the controls you now have three places you need to change the XAML.
The next step is just to bind the TextBlock visibility and toggle it from 'Collapsed' to 'Visible'. But I want to know if there is a way to show the XAML in a textblock without having to hand write the string.
Thanks in advance for your advice!
Following from XAMIMAX's comment you could use an easy converter to save the xaml to a string using XamlWriter and strip the xmlns namespaces for brevity.
public class XamlConverter : IValueConverter
{
public readonly Regex xmlnsRegex = new Regex("xmlns=\".+\"");
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var source = value as FrameworkElement;
if (source != null)
{
//Save xaml and strip xmlns namespaces
var xaml = xmlnsRegex.Replace(System.Windows.Markup.XamlWriter.Save(source), "");
return xaml;
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Example usage
<StackPanel>
<StackPanel.Resources>
<converters:XamlConverter x:Key="Converter_Xaml"/>
</StackPanel.Resources>
<Button x:Name="SourceButton" Content="Click Me" Margin="10"/>
<TextBlock Text="{Binding ElementName=SourceButton, Converter={StaticResource Converter_Xaml}}" TextWrapping="Wrap"/>
</StackPanel>
I have a longlistselector for my windows phone 8 app:
<phone:LongListSelector x:Name="AppMenuList" Background="Transparent"
ItemTemplate="{StaticResource AppMenuListTemplate}"
IsGroupingEnabled="true" HideEmptyGroups="true"
LayoutMode="List" SelectionChanged="OnMenuItemTapped"
Margin="5,50,0,0"/>
With the following DataTemplate:
<phone:PhoneApplicationPage.Resources>
<DataTemplate x:Key="AppMenuListTemplate">
<Grid>
<StackPanel Orientation="Horizontal" Margin="0,5,0,0" Height="80" Width="800" Tap="vTapFeedback">
<TextBlock HorizontalAlignment="Left" Margin="0,20,0,20" Height="50"
Width="800" TextWrapping="NoWrap"
Text="{Binding MenuItemName}" VerticalAlignment="Center"
FontSize="32" Foreground="#115445" />
</StackPanel>
</Grid>
</DataTemplate>
</phone:PhoneApplicationPage.Resources>
From my C# code, I am setting the ItemsSource property for the longlistselector to display the list of items to the user. However all the items are of same color as specified in the TextBlock property Foreground.
I have a requirement in which I want the user to be able to tap every item of the list and perform some operation except the one. I want that it should be shown as disabled to the user by using a Gray color for it.
I am not able to accomplish this. Can anyone suggest how I can do this ?
There are three solutions that come to my mind:
you can use VisualTreeHelper to find your textbox and then change its Foreground Color
I've bound Foreground color to a property of Item Class, then when I change this property, Foreground changes automatically. I assume than you were able to bind your Text, then there should be no problem with binding Foreground. One thing you will probably need is a Converter.
you can define VisualStates in Style of your TextBlock.
EDIT - code sample after request
I've definded my Converter like this:
namespace myApp.Converters
{
public class BoolToBrush : IValueConverter
{
private Brush FalseValue = (Application.Current.Resources["TransparentBrush"] as Brush);
private Brush TrueValue = (Application.Current.Resources["PhoneAccentBrush"] as Brush);
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
return FalseValue;
else
return (bool)value ? TrueValue : FalseValue;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return value != null ? value.Equals(TrueValue) : false;
}
}
In my Item class I've a property Selected (bool in this case) to which Foreground (or Background) is bound. I use it in XAML (item or control) like this:
<UserControl.Resources xmlns:local="clr-namespace:myApp.Converters">
<local:BoolToBrush x:Key="boolToBrush"/>
</UserControl.Resources>
<Grid Name="myElement" Background="{Binding Path=Selected, Converter={StaticResource boolToBrush}}">
Of course you can define more coplex convertes - if you need more Brushes and so on.
On the other hand I would also consider using VisualStates.
Hope this helps a little.
I am working on my first Windows 8 RT application and started with the sample grid application. My goal is to change the style of one of these grid items.
I have been able to 'find' this item by using this:
if (dataItem.UniqueId.StartsWith("Group-1-Item-1"))
Then I created this style in C# (just as an example);
Style style = new Style (typeof(SampleDataItem));
Thickness thick = new Thickness(4,4,4,4);
style.Setters.Add(new Setter(Border.BorderThicknessProperty, new Thickness(100)));
However, now I have to apply this style to the specific data item - I have tried a lot of things, but I don't take they make much sense now that I look at them.
The data template for the dataItems for the Grid App project template is found in StandardStyles.xaml, and is referred to by the key "Standard250x250ItemTemplate".
If the idea is to vary the styling based on the content of the item, one approach might be to use a Binding.Converter, as shown here, to convert the value of the content in question to the desired style or style property.
For example, If I wanted to make any items in the default Grid App template have a green background if the item number was less than or equal to 3, and red if it was higher than 3, I would create the following converter class (in my case, I just added the class to the GroupedItemsPage.xaml.cs, just before the GroupedItemsPage partial class):
// Custom class implements the IValueConverter interface.
public class StyleConverter : IValueConverter
{
#region IValueConverter Members
// Define the Convert method to change a title ending with > 3
// to a red background, otherwise, green.
public object Convert(object value, Type targetType,
object parameter, string language)
{
// The value parameter is the data from the source object.
string title = (string)value;
int lastNum = (int.Parse(title.Substring(title.Length - 1)));
if (lastNum > 3)
{
return "Red";
}
else
{
return "Green";
}
}
// ConvertBack is not implemented for a OneWay binding.
public object ConvertBack(object value, Type targetType,
object parameter, string language)
{
throw new NotImplementedException();
}
#endregion
}
Once the class is defined, along with the desired Convert method, I add an instance to it in my App.xaml file, so it will be available to the item template in StandardStyles.xaml:
<!-- Application-specific resources -->
<local:StyleConverter x:Key="StyleConverter"/>
In StandardStyles.xaml, I made a copy of the Standard250x250ItemTemplate that binds from the Title property of the item, to my converter class, like so:
<DataTemplate x:Key="Standard250x250ItemTemplate_Convert">
<Grid HorizontalAlignment="Left" Width="250" Height="250">
<Border Background="{Binding Title,
Converter={StaticResource StyleConverter}}">
</Border>
<StackPanel VerticalAlignment="Bottom"
Background="{StaticResource ListViewItemOverlayBackgroundThemeBrush}">
<TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayForegroundThemeBrush}" Style="{StaticResource TitleTextStyle}" Height="60" Margin="15,0,15,0"/>
<TextBlock Text="{Binding Subtitle}" Foreground="{StaticResource ListViewItemOverlaySecondaryForegroundThemeBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
</StackPanel>
</Grid>
</DataTemplate>
the key piece being the binding of the Border element's Background property to the Title, with the Converter={StaticResource StyleConverter}, which wires the item template up to my converter. Note that in addition to binding the Background property, I also removed the nested Image element from the original version of the item template.
Finally, in GroupedItemsPage.xaml, I change the item template to my customized version:
<!-- Horizontal scrolling grid used in most view states -->
<GridView
x:Name="itemGridView"
...
Padding="116,137,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
ItemTemplate="{StaticResource Standard250x250ItemTemplate_Convert}"
...
ItemClick="ItemView_ItemClick">
Once that's done, I can run the project, and here's what I see:
Hope that helps!
For more info on Windows Store app development, register for Generation App.