How to set XamDataTree Icon to Bitmap instead of file name - c#

I've set the XamDataTree image, but I don't want to copy the image folder to my debug folder every time. Instead I want to add the image to my project resources and use it from there. Currently no image is shown because it expects a path to an image where I give it an actual bitmap. The Icon property in the TreeNode is set in another part of the code.
This is my Xaml code:
<ig:XamDataTree
Grid.Row="1"
Name="MyTree"
ScrollViewer.CanContentScroll="True"
ItemsSource="{Binding ComparedContents}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
>
<ig:XamDataTree.CheckBoxSettings>
<ig:CheckBoxSettings CheckBoxVisibility="Visible" />
</ig:XamDataTree.CheckBoxSettings>
<ig:XamDataTree.CollapsedIconTemplate>
<DataTemplate>
<Image Source="{Binding Path=Icon}"/>
</DataTemplate>
</ig:XamDataTree.CollapsedIconTemplate>
<ig:XamDataTree.ExpandedIconTemplate>
<DataTemplate>
<Image Source="{Binding Path=Icon}"/>
</DataTemplate>
</ig:XamDataTree.ExpandedIconTemplate>
<ig:XamDataTree.GlobalNodeLayouts>
<ig:NodeLayout
Key="Children"
DisplayMemberPath="Text"
TargetTypeName="Model.TreeNode"
>
</ig:NodeLayout>
</ig:XamDataTree.GlobalNodeLayouts>
</ig:XamDataTree>
This is my model, each Property has a private store for the value and fires an event if it changes.
public class TreeNode : INotifyPropertyChanged
{
public Label Text;
public System.Drawing.Image Icon;
public ObservableCollection<TreeNode> Children;
}

Assuming you embedded the image into your application, you can use a pack uri to load the image into the node template. Instead of using an Image type on your Icon property you should use Uri and set it equal to something like this:
Icon = new Uri("pack://application:,,,/Resources/Images/icon.png");
You need to modify the binding in your templates a bit because the DataContext of this template is going to be a XamDataTreeNodeDataContext. This object has a Data property which will be your TreeNode object. Your binding should be updated to:
<Image Source="{Binding Path=Data.Icon}"/>

Related

C# IOException Cannot locate resource

I have a C# project where I have some PNG files in a Images directory.
The structure of the project can be simplified to:
|
ViewModel.cs
View.xaml
|
[Images]
\
MapImageLayer16.png
In my view I bind to an object containing a string property ImagePath, pointing to ../Images/MapImageLayer16.png, and another string property Name:
<ListBox x:Name="DataLayerList" ItemsSource="{Binding LayersFiltered, Mode=OneWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=ImagePath}" Height="16"/>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now, the name comes trough fine. However, the image fails with the following description:
Failed to convert value '/Images/MapImageLayer16.png' (type 'String') to the target type using converter 'TargetDefaultValueConverter'. The fallback value will be used if it's available. IOException:'System.IO.IOException: Cannot locate resource 'images/mapimagelayer16.png'.
I tried all sorts of things by now:
changed the string value to ../Images/MapImageLayer16.png
changed the string value to pack://application:,,,/Images/MapImageLayer16.png
switched from string to Uri
Nothing works! How can I get the PNGs to show?
This is a common error when we forget to set the properties of the image as a Resource (on VisualStudio, Rightclic on the image > Properties > Build Action : Resource & Copy to OutputDirectory : Do not copy)
You also need to bind a BitmapImage, and not a string, to the Xaml Image control. In your CS code, the ImagePath must become :
public BitmapImage Source => new BitmapImage(new Uri(ImagePath, UriKind.Relative));
with ImagePath = "/Images/MapImageLayer16.png"
This looks like a typical WPF resource error to me. Open the {projectname}.csproj file and add this (adjust if necessary if the structure is not correct)
<ItemGroup>
<Resource Include="Images\MapImageLayer16.png" />
</ItemGroup>
Not in "PropertyGroup" but in "Project" as it can be seen here

Trying to Understand UWP Data Binding

So, I made a really simple attempt to try out data binding from a property of a class that I have, but, for whatever reason, the code actually do anything. It's not throwing any errors, but something must not be working right. I'm just currently testing if it'll behave like I want it to, which, in this case, will set the opacity of a rectangle to zero. Here's the xaml for the Data Template that doesn't seem to want to respond correctly:
<HubSection x:Name="China" Width="440" Height="460" Background="#FF343434" Header="China" IsHeaderInteractive="True" Tapped="{x:Bind HubSectionTapped}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="50,0,0,0">
<DataTemplate x:DataType="data:MainPageView">
<Grid Height="460" Width="410" VerticalAlignment="Bottom" x:Name="ChinaBackground">
<Image Source="Assets/chinaFlag.bmp" x:Name="ChinaFlag"/>
<Rectangle x:Name="ChinaSelected_Rect" Width="410" Height="30" VerticalAlignment="Bottom" Fill="BlueViolet" Opacity="{x:Bind Opacity1}"/>
</Grid>
</DataTemplate>
</HubSection>
And here's the code behind:
public MainPageView TheMainPageView;
public MainPage()
{
this.InitializeComponent();
timer = new DispatcherTimer();
timer.Tick += Timer_DyanmicResize;
timer.Tick += Timer_SelectionIndicator;
timer.Start();
TheMainPageView = new MainPageView ();
}
And finally, here's the class MainPageView that's referenced:
public class MainPageView
{
public int Opacity1 {get; set;}
public int Opacity2 {get;set;}
public int Opacity3 { get; set; }
public MainPageView()
{
this.Opacity1 = 0;
this.Opacity2 = 0;
this.Opacity3 = 0;
}
}
In the XAML I included the xmlns:data="using:TestApp.Models" (models is the folder in which the class MainPageView is housed). As I said, it's not throwing errors, but it's not doing anything either, so I'm a bit at a loss of where to start addressing this because there aren't any errors to trace back. Thanks in advance for any help you guys can provide
HubSection uses a DataTemplate to define the content for the section, content can be defined inline, or bound to a data source. When using binding in this DataTemplate, we need set DataContext property of HubSection to provide data source for the DataTemplate.
{x:Bind} does not use the DataContext as a default source—instead, it uses the page or user control itself. So it will look in the code-behind of your page or user control for properties, fields, and methods.
This is right when you use {x:Bind} directly in page or user control. While Inside a DataTemplate, there is a little difference.
Inside a DataTemplate (whether used as an item template, a content template, or a header template), the value of Path is not interpreted in the context of the page, but in the context of the data object being templated. So that its bindings can be validated (and efficient code generated for them) at compile-time, a DataTemplate needs to declare the type of its data object using x:DataType.
For more information about Data binding in UWP, please check Data binding in depth.
To fix your issue, you just need to set DataContext in HubSection like following:
<HubSection x:Name="China" Width="440" Height="460" Background="#FF343434" Header="China" IsHeaderInteractive="True" Tapped="{x:Bind HubSectionTapped}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="50,0,0,0" DataContext="{x:Bind TheMainPageView}">
<DataTemplate x:DataType="data:MainPageView">
<Grid Height="460" Width="410" VerticalAlignment="Bottom" x:Name="ChinaBackground">
<Image Source="Assets/chinaFlag.bmp" x:Name="ChinaFlag"/>
<Rectangle x:Name="ChinaSelected_Rect" Width="410" Height="30" VerticalAlignment="Bottom" Fill="BlueViolet" Opacity="{x:Bind Opacity1}"/>
</Grid>
</DataTemplate>
</HubSection>
Here when using {x:Bind} in HubSection, it uses the page itself as its data source as HubSection is in the page directly. So it can get TheMainPageView field in the code-behind. But for the {x:Bind} in DataTemplate, it can't as
its data source is the data object being templated not the page. So we need to provide this data object by setting DataContext property of HubSection.
Check you output window for errors but I imagine you might see a binding error in there. Opacity is a double, you are using an int so will get a type conversion error.

Binding BitmapImage UriSource

I'm trying to develop my first Windows Store application.
I'm using the Hub Application template.
I want to display an Image from a Url in the first section of my HubPage:
<HubSection ... >
<DataTemplate>
<Grid ... >
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
...
</Grid.RowDefinitions>
<Image Name="UserProfileImage" Margin="100, 0, 100, 0" Grid.Row="0" VerticalAlignment="Top">
<Image.Source>
<BitmapImage UriSource="{Binding ImageUrl}"></BitmapImage>
</Image.Source>
</Image>
</Grid>
</DataTemplate>
</HubSection>
And in my HubPage.xaml.cs:
[DefaultValue("http://images6.fanpop.com/image/photos/34200000/more-dumb-images-of-philip-j-fry-futurama-34257101-1440-900.png"")]
public string ImageUrl { get; set; }
But nothing is shown. If I set manually in the xaml file an image url it works fine...
The problem is, that the Binding mechanism does not know where to look for the ImageUrl property.
You can either set the DataSource of the tag or any of it's parents to an instance of the class, where the property is defined.
Or you use more information in each Binding statement. To bind to yourself, just use
UriSource="{Binding RelativeSource={RelativeSource Self}, Path=ImageUrl}"
or
UriSource="{Binding ImageUrl, RelativeSource={RelativeSource Self}}"
see also WPF Bind to itself
Edit:
You also need to have a notification mechanism on your variable you are binding to. Either make it a DependencyProperty or use a PropertyChanged event (either through INotifyPropertyChanged and call PropertyChanged on changes in the setter with the name of the property, or create an event called <name of property>Changed and invoke this event on changes.
Unfortunately it seems that BitmapSource.UriSource cannot be databound (or more specifically, it can only be bound once and further changes ignored). See discussion here.
In your code you're using <DataTemplate> which means the parent control of this will be either <ListView> or something like that.
Your code reflects very few things about your scenario.
I suggest you to bind ImageSource instead of string
Instead working on XAML part, I suggest you to edit your code-behind part.
I'm briefing the sample here. relate this, with your case and do needful.
Example:-
// BlankPage.xaml ----
// eg. I've a listView and i want to display
// image dynamically in DataTemplate
<ListView x:Name="lstView">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding bmp}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Now, define a model class to give itemsSource to ListView.
// In BlankPage.xaml.cs file
public class model
{
public ImageSource bmp { get; set; }
}
Now, say for example I'm assigning itemsSource to ListView in Page_Loaded event.
// in BlankPage.xaml.cs file
// declare this BlankPage's Loaded event in BlankPage's Constructor
// and define the event handler like this
void BlankPage2_Loaded(object sender, RoutedEventArgs e)
{
model m1 = new model()
{
bmp = new BitmapImage(new Uri("ms-appx:///Assets/TechVista(300x300).png", UriKind.Absolute))
};
// here "ms-appx:///Assets/TechVista(300x300).png" should be the Full-System-Path where image is located.
// and according to that declare the UriKind as Relative or Absolute or other.
List<model> lstModels = new List<model>();
lstModels.Add(m1);
// you can add as many models as you want here.
// for reference I'm adding only one here.
lstView.ItemsSource = lstModels;
}
It will work for sure.
For more exact answer, elaborate little more here.
Hope that helps..!

How to display a placeholder image in a list box that have bonded data?

On windows phone 8 I have made a list box bandied with a web server data which are an image and a text sometimes the server returns only text as their are no image uploaded by the user. I need to display a placeholder image.
<ListBox Grid.Row="1" ItemsSource="{Binding places}" Name="mrx" Margin="0,10,0,0" Loaded="mrx_Loaded">
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel Orientation="Horizontal" Margin="10,0,10,8">
<StackPanel Margin="10,0,10,8">
<TextBlock Text="{Binding name}" Foreground="Black" FontWeight="Bold" FontSize="40"/>
<Image Source="{Binding url}" Width="100" Height="100"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here how I access url:
public BitmapImage h { get; set; }
public BitmapImage url
{
get { return h; }
set
{
if (h == null)
{
h.UriSource = new Uri("profile-placeholder.gif", UriKind.RelativeOrAbsolute);
}
}
}
If your h == null when there is no image returned then there is easier way to do what you want - use TargetNullValue in Binding:
<Image Source="{Binding url, TargetNullValue='/Example;component/Resources/placeholder.png'}" Width="100" Height="100"/>
In above case be sure to set BuildAction of placeholder.png as Resource. (Example here is your project name, Resources is a path to the file). You can also bind directly to your h in this case.
If you insist on using designed property then:
I'm not sure how the rest of your code looks like, but but when you have defined binding like this:
<Image Source="{Binding url}" Width="100" Height="100"/>
When the item is being loaded the Getter of url is fired. So using Setter to repleace null with Bitmapimage won't help here (of course if you are not running Setter somewhere else, but defining Setter without value - kind a weird, implement it different or provide separate method.
Check if that would help:
public BitmapImage url
{
get
{
if (h == null)
return new BitmapImage() { UriSource = new Uri("/Projectname;component/path/profile-placeholder.gif", UriKind.Relative) };
return h;
}
}
Setting UriSource depends also how your file is defined in your project (Build Action), you can take a look here.
according to me you can try 2 options
1) make a image failed event of the image and when its called then set the default image as source.
2) put the image view inside a grid with background as the default image so if url comes then it will overlap the default image and show you user image and if it fails then the background of the image will be there as default image.
I hope this might help ......
Add a default image in your assets. Set this image path string as a default value to the "url" that you use for binding. and when you get a web response and parse it, check if there is a valid url path string for an image. If there is a valid url string parsed for the image, then assign it to "url" field else If there is no valid url string for the image, do not set it to the url field. The"url" string field will any way contain the default image that you set.
Hope this helps you. Thanks.
See Conditional text formatting XAML WP8
You should bind to url and set conditional trigger if url is null
<Image Source = "{Binding url} " Width="100" Height="100"/>
Here, instead of binding image source to URL directly, bind it to property having URL as a global variable and initiate URL to placeholder URL.
Example:
private string yourURL= "/Resources/Images/placeholder.png";
public string YourURL
{
get
{
return yourURL;
}
set
{
if (value != yourURL)
{
yourURL= value;
}
}
}
and statement will be like:
<Image Source="{Binding YourURL}" Width="100" Height="100"/>

Binding an Image in WPF MVVM

I am having some trouble binding in Image to my viewmodel. I finally got rid of the XamlParseException, but the image does not come up. I even hard coded the image in the ViewModel. Can someone see what I am doing wrong?
View:
<Image HorizontalAlignment="Left" Margin="0,0,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Bottom" Grid.Row="8" Width="200" Grid.ColumnSpan="2" >
<Image.Source>
<BitmapImage DecodePixelWidth="200" UriSource="{Binding Path=DisplayedImage, Mode=TwoWay}" />
</Image.Source>
ViewModel:
string _DisplayedImagePath = #"C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg";//string.Empty;
int _DisplayedImageIndex;
BitmapImage _DisplayedImage = null;
public BitmapImage DisplayedImage
{
get
{
_DisplayedImage = new BitmapImage();
if (!string.IsNullOrEmpty(_DisplayedImagePath))
{
_Rail1DisplayedImage.BeginInit();
_Rail1DisplayedImage.CacheOption = BitmapCacheOption.OnLoad;
_Rail1DisplayedImage.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
_Rail1DisplayedImage.UriSource = new Uri(_DisplayedImagePath);
_Rail1DisplayedImage.DecodePixelWidth = 200;
_Rail1DisplayedImage.EndInit();
}
return _Rail1DisplayedImage;
}
set
{
_Rail1DisplayedImage = value;
OnPropertyChanged("DisplayedImage");
}
}
Displaying an Image in WPF is much easier than that. Try this:
<Image Source="{Binding DisplayedImagePath}" HorizontalAlignment="Left"
Margin="0,0,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Bottom"
Grid.Row="8" Width="200" Grid.ColumnSpan="2" />
And the property can just be a string:
public string DisplayedImage
{
get { return #"C:\Users\Public\Pictures\Sample Pictures\Chrysanthemum.jpg"; }
}
Although you really should add your images to a folder named Images in the root of your project and set their Build Action to Resource in the Properties Window in Visual Studio... you could then access them using this format:
public string DisplayedImage
{
get { return "/AssemblyName;component/Images/ImageName.jpg"; }
}
UPDATE >>>
As a final tip... if you ever have a problem with a control not working as expected, simply type 'WPF', the name of that control and then the word 'class' into a search engine. In this case, you would have typed 'WPF Image Class'. The top result will always be MSDN and if you click on the link, you'll find out all about that control and most pages have code examples as well.
UPDATE 2 >>>
If you followed the examples from the link to MSDN and it's not working, then your problem is not the Image control. Using the string property that I suggested, try this:
<StackPanel>
<Image Source="{Binding DisplayedImagePath}" />
<TextBlock Text="{Binding DisplayedImagePath}" />
</StackPanel>
If you can't see the file path in the TextBlock, then you probably haven't set your DataContext to the instance of your view model. If you can see the text, then the problem is with your file path.
UPDATE 3 >>>
In .NET 4, the above Image.Source values would work. However, Microsoft made some horrible changes in .NET 4.5 that broke many different things and so in .NET 4.5, you'd need to use the full pack path like this:
<Image Source="pack://application:,,,/AssemblyName;component/Images/image_to_use.png">
For further information on pack URIs, please see the Pack URIs in WPF page on Microsoft Docs.
If you have a process that already generates and returns an Image type, you can alter the bind and not have to modify any additional image creation code.
Refer to the ".Source" of the image in the binding statement.
XAML
<Image Name="imgOpenClose" Source="{Binding ImageOpenClose.Source}"/>
View Model Field
private Image _imageOpenClose;
public Image ImageOpenClose
{
get
{
return _imageOpenClose;
}
set
{
_imageOpenClose = value;
OnPropertyChanged();
}
}
#Sheridan thx.. if I try your example with "DisplayedImagePath" on both sides, it works with absolute path as you show.
As for the relative paths, this is how I always connect relative paths, I first include the subdirectory (!) and the image file in my project.. then I use ~ character to denote the bin-path..
public string DisplayedImagePath
{
get { return #"~\..\images\osc.png"; }
}
This was tested, see below my Solution Explorer in VS2015..
)
Note: if you want a Click event, use the Button tag around the image,
<Button Click="image_Click" Width="128" Height="128" Grid.Row="2" VerticalAlignment="Top" HorizontalAlignment="Left">
<Image x:Name="image" Source="{Binding DisplayedImagePath}" Margin="0,0,0,0" />
</Button>

Categories

Resources