I have a WPF Image Control in my project that loads from internet (lazy loading), i want to show a initial image in Image Control until main image load. plz help me
<DataTemplate DataType="{x:Type local:MyData}">
...
<Image Width="50" Height="50" Source="{Binding Path=profile_image_url_https, FallbackValue=profile_image_url_https}" HorizontalAlignment="Left">
...
</DataTemplate>
You might be able to make it work using TargetNullValue on the binding, only set the image property when it is loaded.
e.g.
<BitmapImage x:Key="DefaultImage" UriSource="Images/Error.ico" />
<Image Source="{Binding TestBitmapImage,
TargetNullValue={StaticResource DefaultImage}}" />
private BitmapImage _TestBitmapImage = null;
public BitmapImage TestBitmapImage
{
get { return _TestBitmapImage; }
set
{
if (_TestBitmapImage != value)
{
_TestBitmapImage = value;
PropertyChanged.Notify(() => this.TestBitmapImage);
}
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var img = new BitmapImage();
img.DownloadCompleted += (s, dcea) =>
{
TestBitmapImage = img;
};
img.BeginInit();
img.UriSource = new Uri("http://www.gravatar.com/avatar/c35af79e54306caedad37141f13de30c?s=128&d=identicon&r=PG");
img.EndInit();
}
Related
I have an issue with a WPF application that I'm writing. I have a window that I load with profile pictures for the user to choose from when setting up an account within the application. Each picture is loaded into a user control, and placed in a stackpanel, so that when the user clicks the picture, it triggers the code in the user control, and automatically sets their profile picture without any more clicking needed. This window loads on 64-bit systems just fine. However, when loading on a 32-bit system, the entire application crashes. The faulting module is wpfgfx_v0400.dll. I don't know why it's crashing. Please help.
Here's the error in the Event Viewer:
Here's the XAML on the frontend of the window in question:
<Window x:Class="RandomApplication.Windows.ChooseProfilePic"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:RandomApplication.Windows"
mc:Ignorable="d"
WindowStartupLocation="CenterScreen"
ContentRendered ="On_ContentRendered"
Title="Choose A Picture" Height="515" Width="500" Background="Black" ResizeMode="CanMinimize">
<Grid Background="Black">
<ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Auto" Height="420" VerticalAlignment="Top" Margin="0,5,0,0">
<StackPanel>
<StackPanel Name="HeadsPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
<StackPanel Name="AbstractPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
<StackPanel Name="ShapesPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
<StackPanel Name="MiscPanel" Orientation="Horizontal" Height="100" VerticalAlignment="Top"/>
</StackPanel>
</ScrollViewer>
<Button Name="CancelButton" VerticalAlignment="Bottom" Style="{DynamicResource RedButton}" Click="CancelButton_Click">Cancel</Button>
<Border Name="LoadingBorder" Background="Black">
<TextBlock Name="LoadingLabel" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0,150" FontSize="20" FontWeight="Bold">
<Run>Loading Pictures</Run>
<LineBreak></LineBreak>
<Run>Please Wait...</Run>
</TextBlock>
</Border>
</Grid>
Here's the code behind the window:
namespace RandomApplication.Windows
{
public partial class ChooseProfilePic : Window
{
private readonly BackgroundWorker _loadPictureWorker = new BackgroundWorker();
public ChooseProfilePic()
{
InitializeComponent();
Topmost = true;
_loadPictureWorker.DoWork += LoadImages;
_loadPictureWorker.RunWorkerCompleted += LoadImages_Completed;
}
private void On_ContentRendered(object sender, EventArgs e)
{
_loadPictureWorker.RunWorkerAsync();
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
DialogResult = false;
Close();
}
private void LoadImages(object sender, DoWorkEventArgs e)
{
try
{
var headsImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Heads\";
var abstractImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Abstract\";
var shapesImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Shapes\";
var miscImagePath = AppDomain.CurrentDomain.BaseDirectory + #"Images\Profile Pics\Misc\";
List<string> headsImageList = GetImages(headsImagePath);
List<string> abstractImageList = GetImages(abstractImagePath);
List<string> shapesImageList = GetImages(shapesImagePath);
List<string> miscImageList = GetImages(miscImagePath);
Application.Current.Dispatcher.Invoke(() =>
{
LoadViewingPanel(headsImageList, HeadsPanel);
LoadViewingPanel(abstractImageList, AbstractPanel);
LoadViewingPanel(shapesImageList, ShapesPanel);
LoadViewingPanel(miscImageList, MiscPanel);
});
}
catch (Exception ex)
{
CustomMessageBox.Show("Could not load images. :-(", "Image Retrieval Failed", MessageBoxButton.OK,
MessageBoxImage.Error);
Helper.WriteException(Helper.ErrorLogs + "Error Loading Images.txt", ex);
}
}
private void LoadImages_Completed(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
CustomMessageBox.Show("Could not load images. :-(", "Image Retrieval Failed", MessageBoxButton.OK,
MessageBoxImage.Error);
Helper.WriteException(Helper.ErrorLogs + "Error Loading Images.txt", e.Error);
}
else LoadingBorder.Visibility = Visibility.Hidden;
}
public List<string> GetImages(string imagePath)
{
var that = GetAllFiles(imagePath);
return that.ToList();
}
private void LoadViewingPanel(List<string> list, StackPanel panel)
{
foreach (var imageString in list)
{
Helper.WriteLineToFile(Helper.ErrorLogs + "2nd Info Loading Images.txt", imageString);
var thisUri = new Uri(imageString, UriKind.RelativeOrAbsolute);
var pic = new ProfilePic {ProfilePicImage = {Source = new BitmapImage(thisUri)}};
panel.Children.Add(pic);
}
}
private IEnumerable<string> GetAllFiles(string path)
{
return Directory.EnumerateFiles(path, "*.jpg").Union(
Directory.EnumerateDirectories(path).SelectMany(d =>
{
try
{
return GetAllFiles(d);
}
catch
{
return Enumerable.Empty<string>();
}
}));
}
}
}
I've researched what could cause issues with this particular dll, but none of it seems to relate to my issue.
So, I figured out the issue. Apparently, the size of the images that I was trying to load was too big. The images were all 2048x2048 pixels, which made them anywhere from 180 KB to 380 KB in size. Apparently this is too much. I resized all of the pictures to 100x100 pixels (as I was only ever presenting them to the user as 100x100), which brought the file sizes down to 7 - 10 KB each. After that, they loaded just fine with no crashing issues.
I´m working on a big project in wpf that uses Caliburn Micro.
I have done a view that should view a movie.
I´m trying to bind MediaElement Source to my file that I have in my ViewModel.
My View looks like this:
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Items}">
<ContentControl cb:View.Model="{Binding}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</controls:ExtendedTreeView>
<MediaElement Source="media" Visibility="{Binding IsIndexVisible, Converter={StaticResource InvertBoolToHiddenConverter}}" />
And in my viewmodel:
public override void NavigateEnter()
{
//base.NavigateEnter();
if (CanExpand)
{
base.Expand();
return;
}
if (SelectedItem == null) return;
var media = new MediaElement();
media.LoadedBehavior = MediaState.Manual;
media.Source = new Uri(#"C:/Users/v80770/Desktop/Movies/ATTV_bog.mpg");
media.Play();
}
private Uri _mediaUri;
public Uri MediaUri
{
get
{
return _mediaUri;
}
set
{
_mediaUri = value;
NotifyOfPropertyChange(() => MediaUri);
}
}
public override void NavigateEnter()
{
//base.NavigateEnter();
if (CanExpand)
{
base.Expand();
return;
}
if (SelectedItem == null) return;
var test = (#"C:/Users/v80770/Desktop/Movies/ATTV_bog.mpg");
var mediauri = new Uri(test);
_mediaUri = mediauri;
IsIndexVisible = false;
}
But when I start my project nothing shows at all.
You need to bind the Uri as Source for Media Element. The Source Dependency Property expects type of Uri. You can verify it here.
<MediaElement Source="{Binding MediaUri}" />
Where MediaUri is defined as
public Uri MediaUri {get;set; }
I'm trying to achieve one Login button which changes to a Please wait... mode once pressed. I was thinking about some StoryBoard animation inside button or GIF image animation. Seems I'm pretty new to WPF and after several search attempts, I'm unable to find a fully working idea.
Login button idea
What would be the best way to do the above thing? Is there any way to eliminate the GIF image and create the same using some Path or something similar? Also note that I want this behavior of button to be triggered on Button.Click event.
Just simply add WpfAnimatedGif from your visual studio Tools -> NuGet Package Manager->Package Manager Console. There you find the Package adder window and type pm > Install-Package WpfAnimatedGif. After a few seconds package should be added. Now firstly, you have add namespace xmlns:gif="http://wpfanimatedgif.codeplex.com" then design your Button.
<Window x:Class="WpfApplication1.MainWindow" Name="root"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gif="http://wpfanimatedgif.codeplex.com"
Width="500" Height="500" DataContext="{Binding ElementName=root}">
<StackPanel>
<Button Name="BtnLogin" Width="100" Height="30" Content="Login" Background="Red" Margin="0,0,0,5" Click="Button_Click"/>
<Button Width="100" Height="30" Background="Red">
<Grid>
<Image gif:ImageBehavior.AnimatedSource="{Binding DataContext.LoadingImage}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock Text="Please Wait" Padding="30,0,0,0" HorizontalAlignment="Right" VerticalAlignment="Center"/>
</Grid>
</Button>
</StackPanel>
</Window>
The following .cs file is below and when you need to stop loading image, just assign LoadingImage = null;
public partial class MainWindow : Window,INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
private ImageSource _LoadingImage;
public ImageSource LoadingImage
{
get { return _LoadingImage; }
set
{
_LoadingImage = value;
OnPropertyChanged("LoadingImage");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
LoadingImage = GetBitmapImage("/aaaa.gif");
}
public static BitmapImage GetBitmapImage(String location)
{
BitmapImage image = null;
try
{
Uri iconUri = new Uri("pack://application:,,,/" + ";component" + location, UriKind.RelativeOrAbsolute);
image = new BitmapImage(iconUri);
}
catch (Exception ex)
{
}
return image;
}
}
I am creating a set of images dynamically and putting them into a Stack Panel like this :-
Image image = new Image();
image.Name = "image_" + iCounter;
image.Height = 100;
image.Width = 100;
image.Source = bitmap;
image.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
image.Stretch = Stretch.Fill;
image.VerticalAlignment = VerticalAlignment.Top;
//image.MouseDown += new MouseButtonEventHandler(image_MouseDown);
image.ToolTip = "Right-Click for Options";
image.ContextMenu = GetContextMenu();
Separator separator = new Separator();
separator.Name = "separator_" + iCounter;
AddImagesStackPanel.Children.Add(image);
AddImagesStackPanel.Children.Add(separator);
iCounter++;
Then in the Context Menu I have this code :-
private System.Windows.Controls.ContextMenu GetContextMenu()
{
System.Windows.Controls.MenuItem mi1;
System.Windows.Controls.MenuItem mi2;
System.Windows.Controls.ContextMenu _contextMenu = new System.Windows.Controls.ContextMenu();
mi1 = new System.Windows.Controls.MenuItem();
mi1.Header = "Show Normal Size";
mi1.Click += new RoutedEventHandler(ContextMenuItem1_Click);
mi2 = new System.Windows.Controls.MenuItem();
mi2.Header = "Remove image";
mi2.Click += new RoutedEventHandler(ContextMenuItem2_Click);
_contextMenu.Items.Add(mi1);
_contextMenu.Items.Add(mi2);
return _contextMenu;
}
Now I wish to get the selected item when the user right clicks on an image and I have this code :-
private void ContextMenuItem2_Click(object sender, RoutedEventArgs e)
{
object obj = e.OriginalSource;
string imageName = ((System.Windows.Controls.Image)obj).Name;
string[] split = imageName.Split('_');
imageUploads.RemoveAt(Convert.ToInt32(split[1]));
DisplayImagesInStackPanel(imageUploads);
}
But obj does not contain the name of the image since its a RoutedEventArgs. Is there any way I can get the selected item in the context menu?
After discussing this in the comments this should work:
// The binding source.
private readonly ObservableCollection<BitmapImage> _imageList = new ObservableCollection<BitmapImage>();
public ObservableCollection<BitmapImage> ImageList
{
get { return _imageList; }
}
How to display this and set up the ContextMenu:
<ItemsControl ItemsSource="{Binding ImageList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding}" Width="100" Height="100"
HorizontalAlignment="Left" Stretch="Fill"
VerticalAlignment="Top" ToolTip="Right-Click for Options">
<Image.ContextMenu>
<ContextMenu>
<MenuItem Header="Show Normal Size" Click="Image_CM_ShowNormalSize_Click"
Tag="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget}"/> <!-- The placement target is the object to which the context menu belongs, i.e. the image -->
<MenuItem Header="Remove Image" Click="Image_CM_RemoveImage_Click"
Tag="{Binding RelativeSource={RelativeSource AncestorType=ContextMenu}, Path=PlacementTarget.DataContext}"/> <!-- The DataContext of the Image is the BitmapImage, which should be removed from the list -->
</ContextMenu>
</Image.ContextMenu>
</Image>
<Separator/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
What the handlers might look like:
private void Image_CM_ShowNormalSize_Click(object sender, RoutedEventArgs e)
{
Image img = (sender as FrameworkElement).Tag as Image;
img.Width = (img.Source as BitmapImage).PixelWidth;
img.Height = (img.Source as BitmapImage).PixelHeight;
}
private void Image_CM_RemoveImage_Click(object sender, RoutedEventArgs e)
{
BitmapImage img = (sender as FrameworkElement).Tag as BitmapImage;
// If the image is removed from the bound list the respective visual elements
// will automatically be removed as well.
ImageList.Remove(img);
}
But obj does not contain the name of the image since its a RoutedEventArgs.
True, but the obj at that point is a MenuItem, if you drill one level down, you can get the image.
Is there any way I can get the selected item in the context menu?
Normally one would load the model classes (Image in your case) through the binding of ItemSource of the Menu (or MenuItem if they are to be submenus) and if one takes that route they can pull the originating item off of the DataContext such as in my case the item was an MRU class item.
private void SelectMRU(object sender, RoutedEventArgs e)
{
var mru = (e.OriginalSource as MenuItem).DataContext as MRU;
var name = mru.Name;
...
}
Because you do things by hand you should load the Tag property of the MenuItem with the Image in question
mi1.Tag = {Image instance in question};
then extract on the event.
var image = (e.OriginalSource as MenuItem).Tag as Image;
I have my little designer tool (my program).
On the left side I have TreeView and on the right site I have Accordion.
When I select a node I want to dynamically build Accordion Items based on Properties from DataContext of selected node.
Selecting nodes works fine, and when I use this sample code for testing it works also.
XAML code:
<layoutToolkit:Accordion x:Name="accPanel"
SelectionMode="ZeroOrMore"
SelectionSequence="Simultaneous">
<layoutToolkit:AccordionItem Header="Controller Info">
<StackPanel Orientation="Horizontal" DataContext="{Binding}">
<TextBlock Text="Content:" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</layoutToolkit:AccordionItem>
</layoutToolkit:Accordion>
C# code:
private void treeSceneNode_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (e.NewValue != e.OldValue)
{
if (e.NewValue is SceneNode)
{
accPanel.DataContext = e.NewValue; //e.NewValue is a class that contains Name property
}
}
}
But the problem occurs when I'm trying to achive this using DateTemplate and dynamically build AccordingItem, the Binding is not working:
<layoutToolkit:Accordion x:Name="accPanel"
SelectionMode="ZeroOrMore"
SelectionSequence="Simultaneous" />
and DataTemplate in my ResourceDictionary
<DataTemplate x:Key="dtSceneNodeContent">
<StackPanel Orientation="Horizontal" DataContext="{Binding}">
<TextBlock Text="Content:" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
and C# code:
private void treeSceneNode_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (e.NewValue != e.OldValue)
{
ResourceDictionary rd = new ResourceDictionary();
rd.Source = new Uri("/SilverGL.GUI;component/SilverGLDesignerResourceDictionary.xaml", UriKind.RelativeOrAbsolute);
if (e.NewValue is SceneNode)
{
accPanel.DataContext = e.NewValue;
AccordionItem accController = new AccordionItem();
accController.Header = "Controller Info";
accController.ContentTemplate = rd["dtSceneNodeContent"] as DataTemplate;
accPanel.Items.Add(accController);
}
else
{
// Other type of node
}
}
}
Are you missing this?
accController.Content = e.NewValue;
Also, I don't think you need to use DataContext="{Binding}"; the DataContext will inherit anyway.