Updating Image when the selection in ListBox changes - WPF - c#

What I am trying to achieve is change the source of Image when I change the selection in Listbox.
I have a method called GetImageLink that fetches a web URL for the current selection and assigns it to ReferenceImageLink property. (I checked, link is updated when selection changes). But when I try to use this as a source for the Image it does nothing. The image is perpetually blank from start. Can someone please point me in the right direction? I am new to WPF so it is kind of a little confusing to me.
public static string ReferenceImageLink { get; set; }
private async void VariantListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ReferenceImageLink = null;
var selecteditem = sender as ListBox;
string item = selecteditem.SelectedItem as string;
await GetImageLink(item);
BitmapImage referenceBMP = new BitmapImage();
referenceBMP.BeginInit();
//ReferenceImageLink property changes as ListBox selection change, GetImageLink takes care of it.
referenceBMP.UriSource = new Uri(ReferenceImageLink, UriKind.Relative);
referenceBMP.CacheOption = BitmapCacheOption.OnLoad;
referenceBMP.EndInit();
ReferenceImageBox.Source = referenceBMP;
}
<Image Name="ReferenceImageBox" HorizontalAlignment="Left" Height="189" Margin="558,51,0,0" VerticalAlignment="Top" Width="230" />
Screenshot of the WPF app

making UriKind.Absolute solved my problem. Thanks
referenceBMP.UriSource = new Uri(ReferenceImageLink, UriKind.Absolute);

Related

Trying to render a ListViewItem to a bitmap inside a UserControl is crashing

I'm working on a Universal App in which I'm trying to generate a bitmap from a selection so that I can show a fancy animation of the selected object moving from inside a SettingsFlyout, to a new location on the screen while the SettingsFlyout with the listview is transitioned away to a "details" one.
I've seen this code suggested elsewhere but it doesn't seem to work. I get a System.ArgumentException followed by "Value does not fall within the expected range." at the RenderAsync call. any Idea why that's happening? stepping through the code reveals the ListViewItem is properly found, but rendering it doesn't work. I saw another mention of ItemContainerGenerator but it generated a NullReferenceException.
private async void AnimateSelection(object sender, SelectionChangedEventArgs e)
{
var container =
(sender as ListView).ContainerFromItem((sender as ListView).SelectedItem);
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(container as FrameworkElement);
// go on to animate this by copying it to another grid
}
Anybody tried this before? What I want to do is to simple copy the Selected Item of a listview and use it on another Grid. let me know if I need to edit the question with more information.
EDIT:
Upon a suggestion from another dev , I tried rendering the pageRoot stackpanel and another TextBox from the same page and that failed too. I think the issue is with the render itself - can I substitute this code with something else?
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(container as FrameworkElement);
EDIT:
dev suggested dispatcher could be an issue, turns out dispatcher is handled differently in Universal Apps, so I tried to use it through that - no change
var container =
(sender as ListView).ContainerFromItem((sender as ListView).SelectedItem);
await this.dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
{
var bitmap = new RenderTargetBitmap();
await bitmap.RenderAsync(container as FrameworkElement);
var vm = this.DataContext as PersonViewModel;
vm.TransitionImageSource = bitmap;
});
Without a repro of your code I can't say what's wrong but there's nothing fundamentally wrong with your approach.
The following works:
Create a new blank universal app.
Share the MainPage between both targets
Add this XAML:
<StackPanel>
<TextBlock>Some text</TextBlock>
<Button Click="ChangeColor_OnClick">change color</Button>
<ListBox x:Name="ListBox">
<ListBoxItem>item 1</ListBoxItem>
<ListBoxItem>item 2</ListBoxItem>
<ListBoxItem>item 3</ListBoxItem>
</ListBox>
<Button Click="TakeScreenshot_OnClick">take screenshot</Button>
<Button Click="TakeScreenshotOfSelected_OnClick">take screenshot of just selected item</Button>
<Image x:Name="DisplayedScreenshot" Height="200" />
</StackPanel>
Add this code behind:
private void ChangeColor_OnClick(object sender, RoutedEventArgs e)
{
var rand = new Random();
this.Background = new SolidColorBrush(new Color { A = 255, R = (byte)rand.Next(1, 255), G = (byte)rand.Next(1, 255), B = (byte)rand.Next(1, 255) });
}
private async void TakeScreenshot_OnClick(object sender, RoutedEventArgs e)
{
RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(this as FrameworkElement);
this.DisplayedScreenshot.Source = rtb;
}
private async void TakeScreenshotOfSelected_OnClick(object sender, RoutedEventArgs e)
{
RenderTargetBitmap rtb = new RenderTargetBitmap();
await rtb.RenderAsync(this.ListBox.SelectedItem as UIElement);
this.DisplayedScreenshot.Source = rtb;
}
I solved this issue by changing the SettingsFlyout to a UserControl and faking the effects of the SettingsFlyout which breaks the standard behaviour in the process. Looks like this is not really an Answer but there certainly IS a problem with SettingsFlyout and needs to be investigated thoroughly
Thanks Matt

change image.source when tapped

I'm a novice programmer so don't be brutal.
I'm making a game for Windows Store, and I want to animate a run cycle. I made many GIF animations but all have BLACK background, and I need it transparent. So I've decided to make a run cycle using DispatcherTimer. Everything works fine, but the images don't change :/
void timer_Tick(object sender, object e)
{
numer++;
if (numer > 8) numer = 1;
hero.Source.Equals("Assets/Anim/" + nazwa + numer + ".png");
}
Also, When I TAP a different image, it should change the image and other images, but it doesn't... what is wrong?
bool sun = true;
private void Image_Tapped(object sender, TappedRoutedEventArgs e)
{
sun = !sun;
if (sun == false)
{
Image1.Source.Equals("moon.png");
Image2.Source.Equals("ON.png");
}
else
{
Image1.Source.Equals("sun.png");
Image2.Source.Equals("OFF.png");
}
}
The xaml works fine, as the images are shown.
I have checked this question:
ImageTools on Windows Phone 8, changing ImageSource and DataContext
but I get loads of errors. I don't seem to understand how the property changed works.
it seems to be a small mistake. You are using the wrong method.
Image.Source.Equals()
is a boolean method that simply compares the current source with the "source" you give as arguement and will return true or false based on the comparison.
But what you want is to set the source of the image.
So you need to use:
Image1.Source = new BitmapImage(new Uri("moon.png", UriKind.RelativeOrAbsolute));
This will set the source of the Image to the new image you want.
Assuming that "moon.png" is in the main folder in your solution, the two solutions both work:
BitmapImage tn = new BitmapImage();
tn.SetSource(Application.GetResourceStream(new Uri(#"moon.png", UriKind.Relative)).Stream);
Image1.Source = tn;
Or
Image1.Source = new BitmapImage(new Uri("moon.png", UriKind.Relative));

Change canvas background - metro app

A note: I've just started approaching Windows 8 so, please be gentle. I want to set a background image to a canvas:
private void InsertImage(object sender, RoutedEventArgs e) {
var uri = new System.Uri("inkpen:///Assets/01.jpeg");
var photo_background = new ImageBrush {
ImageSource = new BitmapImage {
UriSource = uri
}
};
panelcanvas.Background = photo_background;
}
xaml:
<Canvas Name="panelcanvas" Background="White" Margin="47.5,57,327.5,153"/>
The background changes from white to black and the image doesn't load. How can I fix this?
Thank you.
The problem was the Uri
ms-appx:///Assets/01.jpeg
fixed it
http://msdn.microsoft.com/en-us/library/windows/apps/hh781215.aspx

WPF Dynamic Controls

I want to iterate through all the files in a folder and dynamically create images controls for each JPEG file found. Once complete I want a form filled with dynamically created image controls (think of just about any photo viewing software such as Picasa that has a thumbnail view).
I want to be able to reorder these dynamically created images controls on the form by implementing some sort of drag drop event handler. I will not know how many images I will encounter and therefore cannot hardcode event handlers for each image control that might or might not exist. So I am looking for a way to dynamically add event handlers to dynamically created controls.
The method used in the code below is almost what I am looking for. The problem with the method below is that if I don't know the name of the control I could not hard code the event handler.
public partial class RoutedEventAddRemoveHandler {
void MakeButton(object sender, RoutedEventArgs e)
{
Button b2 = new Button();
b2.Content = "New Button";
// Associate event handler to the button. You can remove the event
// handler using "-=" syntax rather than "+=".
b2.Click += new RoutedEventHandler(Onb2Click);
root.Children.Insert(root.Children.Count, b2);
DockPanel.SetDock(b2, Dock.Top);
text1.Text = "Now click the second button...";
b1.IsEnabled = false;
}
void Onb2Click(object sender, RoutedEventArgs e)
{
text1.Text = "New Button (b2) Was Clicked!!";
}
}
Note I am looking for a solution in c# code not XAML. That is a solution using code like this to add controls:
// What I want
Fields.Add(new Field() { Name = "Username", Length = 100, Required = true });
not like this:
// What I do not want
<TextBox Width="100" Canvas.Left="50" Canvas.Top="20" />
Thanks
I would not do so much in codebehind. Only to get the files.
I would get an ObservableCollection where the string is the FullName of the file.
Then I would present it in a ListBox or ListView having the ItemSource bound to the collection and defining å good ItemTemplate for the control.
In the template, you can use a Converter to create å Source for the Image in the template.
Adding a small sample just to save you the pain of image loading in WPF code-behind.
void OnButtonClick(object sender, RoutedEventArgs routedEventArgs)
{
var files = Directory.GetFiles(#"C:\img");
foreach (var file in files)
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.UriSource = new Uri(file);
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
var img = new Image { Source = bitmap };
img.MouseDown += OnImageMouseDown;
//Add img to your container
}
}
void OnImageMouseDown(object sender, MouseButtonEventArgs e)
{
var img = sender as Image;
//Operate
}

ListBox presenting only one item

I have a ListBox and a class with strings. Each time that a user clicks add button in the application, I create a new instance of the class and add it to the list which is binded to the ListBox. The first time I click the add button, the list box shows the first item, but the next time it doesn't show two items.
XAML - this is the ListBox:
<ListBox Name="ListBox_BinsRegion" Height="181" Margin="233,16,6,94" Width="253" Background="Transparent" BorderThickness="1" BorderBrush="Black" ScrollViewer.VerticalScrollBarVisibility="Auto" ItemsSource="{Binding}"/>
The code behind:
List<Class_ListViewItem> List_ListBoxItems = new List<Class_ListViewItem>();
private void Button_Add_Click(object sender, RoutedEventArgs e)
{
Class_ListViewItem item = new Class_ListViewItem();
item.WH = this.comboBox_WareHouseBinsRegionDefinition.SelectedItem.ToString();
item.XXFrom = textBox_XXFrom.Text;
item.XXTo = textBox_XXTo.Text;
item.YYFrom = textBox_YYFrom.Text;
item.YYTo = textBox_YYTO.Text;
item.Z = textBox_ZFrom.Text;
List_ListBoxItems.Add(item);
ListBox_BinsRegion.DataContext = List_ListBoxItems;
}
Where is my mistake?
WPF does not know when your collection is changing. The problem is here:
List<Class_ListViewItem> List_ListBoxItems = new List<Class_ListViewItem>();
you need to change the list to
ObservableCollection<Class_ListViewItem> List_ListBoxItems = new ObservableCollection<Class_ListViewItem>();
ObservableCollection (System.Collections.ObjectModel) throws an event when the collection is changed, so that WPF can update the listbox.
Also, you can remove the following line, or move it to the constructor of your control.
ListBox_BinsRegion.DataContext = List_ListBoxItems;
You should not change the DataContext of the control, instead set the binding to theList_ListBoxItems and make it a public property, and use an ObservableCollection or BindableCollection instead of list
When you assign the DataContext the second time, it doesn't technically change. This is because you are assigning it to the same collection. You should do something like this instead:
ObservableCollection<Class_ListViewItem> List_ListBoxItems = new ObservableCollection<Class_ListViewItem>();
public YourControl() {
InitializeComponent();
ListBox_BinsRegion.DataContext = List_ListBoxItems;
}
private void Button_Add_Click(object sender, RoutedEventArgs e)
{
Class_ListViewItem item = new Class_ListViewItem();
item.WH = this.comboBox_WareHouseBinsRegionDefinition.SelectedItem.ToString();
item.XXFrom = textBox_XXFrom.Text;
item.XXTo = textBox_XXTo.Text;
item.YYFrom = textBox_YYFrom.Text;
item.YYTo = textBox_YYTO.Text;
item.Z = textBox_ZFrom.Text;
List_ListBoxItems.Add(item);
}
Use an ObservableCollection<> rather than a List<>. This will update the binding automatically, with no need for the following line (which can be kind of slow)
ListBox_BinsRegion.DataContext = List_ListBoxItems;
You could either do what everyone else already suggested (using an ObservableCollection instead of the List) - or you could query the dependency property which is bound and find the corresponding Binding and refresh it manually.
I'd go for the ObservableCollection :)

Categories

Resources