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..!
Related
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.
I am working on a windows store 8.1 app, I have added Grids in MainPage.xaml using List in MainPage.xaml.cs
MainPage.xaml
<GridView Margin="20" x:Name="main" SelectionMode="None" IsItemClickEnabled="True" ItemClick="main_ItemClick">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Background="Red" Width="250" Height="200">
<Grid.RowDefinitions>
<RowDefinition Height="150"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Image Grid.Row="0" Stretch="UniformToFill" Source="{Binding ImageLocation}"/>
<TextBlock Text="{Binding Title}" Grid.Row="1" FontSize="28" />
<TextBlock Text="{Binding SubTitle}" Grid.Row="2" FontSize="16" />
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
MainPage.xaml.cs
protected override void OnNavigatedTo(NavigationEventArgs e)
{
List<data> myList = new List<data>();
myList.Add(new data()
{
ImageLocation = #"Assets/network.png",
iName = "NetWork",
SubTitle ="Network",
Title = "Network"
});
myList.Add(new data()
{
ImageLocation = #"Assets/fb.png",
iName = "Facebook",
SubTitle = "Facebook",
Title = "Facebook"
});
main.ItemsSource = myList;
}
private void main_ItemClick(object sender, ItemClickEventArgs e)
{
Frame.Navigate(typeof(ListView));
}
I want that when someone click on any of the grids, a TextBlock in ListView page show which grid was clicked in MainPage .
This will be a challenge to explain without showing you in code, but here goes...
Hopefully you have created two pages so far. MainPage.xaml that holds your GridView. And a DetailsPage.xaml that will have the layout to show one item.
In the code-behind of MainPage.xaml, like you have in your sample code, you handle the ItemCLick of the GridView, but you want to get the Id of the item clicked, not the item itself. The reason for this is that you want to pass a string, and not a complex object.
In your handler, the event args (e) has a property called ClickedItem that will be the item you are binding to. Let's pretend it's a UserObject you are binding to. In your handler do something like this:
var user = e.ClickedItem as UserObject;
this.Frame.Navigate(typeof(DetailPage), user.Id.ToString());
So, what's happening here? Almost the same code you had before. Except you are navigating to the type of the second page instead of anything else. You are also passing in (the second argument in the Navigate method) the exact record you want to show.
Then in your DetailPage.xaml code-behind you ned to override the OnNavigatedTo method. This method is what is invoked when the Navigation framework directs to the page. It's has a NavigationPararmeter passed to it that you can use to extract the key you passed.
I think it's actually args.Parameter you want to use. You can parse it to an integer and use that to fetch the individual record you have somehow in memory in your application.
var id = int.Parse(args.Parameter);
var user = YourFactory.GetUser(id);
The reason I shifted from this is how you do it to "I think this is how it works" is because although the basic framework operates like this, most developers do not use it like this. Most developers implement something like Prism.StoreApps which introduces not only a lightweight MVVM framework, but also a sophisticated NavigationService that lets you inject parameters directly into an auto-associated view model.
But based on the simplicity of your question, try not to pay attention to that last bit. I explained the basic workflow using the in-box framework. It works just fine, and it will get the job done. When you are ready to write a more advanced implementation you can investigate Prism.StoreApps
More info: http://msdn.microsoft.com/en-us/library/windows/apps/xx130655.aspx
Best of luck!
I'm having problem with binding Collection do ListView.
public static ObservableCollection<ParagonViewClass> mparagonViewList = new ObservableCollection<ParagonViewClass>();
public ObservableCollection<ParagonViewClass> paragonViewList
{
get
{
return mparagonViewList;
}
}
In method, when user add new item, I'm adding it to list:
paragonViewList.Insert(0, newPar);
Also tried with mparagonViewList.Insert(0, newPar);
Itemssource in xaml file:
<ListView Grid.Row="1" Name="paragonListView1" ItemsSource="{Binding paragonViewList}" .../>
#EDIT: Listview have DataTemplate (Grid with labels - im prettu sure that binding is ok, becouse it works with just simply setting myListVIew.ItemsSource = myLis;)
It looks like when I click on product to add to listview it does insert to database, but I cannot see that product on listview. Probably there's little stupid problem, but I cant really find it ;)
Thanks for any answers!
Looking at the code you supplied, it is hard to figure out what you are doing wrong, if anything. So, I have thrown together a little sample application that works (from the WPF point of view anyway).
My model is called ItemModel, rather than ParagonViewClass, and is defined as follows
public class ItemModel
{
public ItemModel() { }
public string Text { get; set; }
}
My Xaml is
<Window x:Class="StackOverflow._20799346.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:common="clr-namespace:StackOverflow.Common;assembly=StackOverflow.Common"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="350" Width="525">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Top">
<Button Content="Add Item" Click="AddItem_OnClick" />
</StackPanel>
<ListView ItemsSource="{Binding Path=Items}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type common:ItemModel}">
<TextBlock Text="{Binding Path=Text}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DockPanel>
</Window>
Note the DataContext being bound to RelativeSource Self, allowing the code behind to be used as the ViewModel. I usually prefer to create a separate ViewModel class but this approach has its advantages as one can event directly from a control into the ViewModel, rather than mucking around with commands.
The code behind, now the view model, looks like
public partial class MainWindow : Window
{
private ObservableCollection<ItemModel> items;
public MainWindow()
{
InitializeComponent();
}
public ObservableCollection<ItemModel> Items { get { return items ?? (items = new ObservableCollection<ItemModel>()); } }
private void AddItem_OnClick(object sender, RoutedEventArgs e)
{
Items.Add(new ItemModel() { Text = Items.Count.ToString(CultureInfo.CurrentCulture) });
}
}
I have utilised a lazy load technique on the Items property. It will only be instantiated when it is accessed. For simplicity, when the Add Item button is clicked, I am adding a new item with its text set to the count of the Items collection.
You should be able to past this code into a new WPF application project, fix the namespacing in the xaml file and run it.
Now, as hinted at above by Rohit Vats, the Items property does not require a Setter. The ObservableCollection itself notifies the WPF binding subsystem when an item has been added or removed via both the INotifyPropertyChanged and INotifyCollectionChanged interfaces, both of which it implements.
I know this does not directly answer your question but with out further information (ie code) about the original problem, it is not possible to know what is going wrong.
Hopefully the example helps.
NOTE: I have removed exception management for brevity.
I need to databind into a element inside my custom class. i've given the ItemSource as the ObservableCollection of telerik:RadTransitionControl via an attached property. However, I need to provide the image member as the source to Image control. I tried the following method and was unsuccessful.
<Grid Background="Black">
<telerik:RadTransitionControl x:Name="radControl" adRotator:AdRotatorExtensions.ItemChangeDelay="0:0:3"
adRotator:AdRotatorExtensions.CurrentSelectedIndex="0"
adRotator:AdRotatorExtensions.IndexChanged="{Binding TopItemCommand, Mode=OneWay}"
adRotator:AdRotatorExtensions.ItemsSource="{Binding Path=ImagePaths}"
VerticalAlignment="Center"
HorizontalAlignment="Center" Width="650">
<telerik:RadTransitionControl.Transition>
<telerik:MotionBlurredZoomTransition />
</telerik:RadTransitionControl.Transition>
<telerik:RadTransitionControl.ContentTemplate>
<DataTemplate>
<Image Source="{Binding Path=ImagePaths.AdImage}" />
</DataTemplate>
</telerik:RadTransitionControl.ContentTemplate>
</telerik:RadTransitionControl>
</Grid>
an ImagePaths object is already set as the DataContext for the item. this means that the binding is already pointing (so to speak) at an instance of the object. so, when you tell it to bind on ImagePaths.AdImage it does not know how to find the property you are looking for. Good news is, all you have to do is provide the path on the object-- remove the ImagePaths part (and the dot) and you should be good to go.
for example...
class something
{
public string someImage {...}
}
<DataTemplate> <!--------- the data context of this item is an instance of
my "something" class, so i need to set the path
to be the property on the object --->
<Image Source="{Binding Path=someImage}" />
</DataTemplate>
here is a very helpful article on debugging bindings in WPF
for more info here is an excellent article on MSDN
here is a datatemplate article from Dr. WPF
Update: I've updated the code based on your help so far, and still no luck. When the application loads the ListBox has no items. I assign junk values to Customers in the windows's contructor, and then am also trying to set the ListBox's DataContext as follows:
CustomerList.DataContext = Customers;
--- Original Question (with updated code) ---
I'm having trouble with databinding in a WPF project.
I have a class, Customer, as follows:
public class Customer
{
public String Name { get; set; }
public String Email { get; set; }
}
In my XAML's code behind I have a collection of customers as follows:
public List<Customer> Customers { get; set; }
I'm trying to bind each customer to a ListBox with a ListItemTemplate displaying the customer's information (name/email) in TextBoxes along with a button which locks/unloacks the TextBoxes (sets the IsEnabled property to true or false).
What's the best way to go about this?
So far I've been tryingt he following with no success.
In the XAML I currently have the following (ignoring the toggle part for now, I'm just trying to get the collection itself to be listed.):
<Window.Resources>
<CollectionViewSource x:Key="Customers" Source="{Binding Path=Customers, Mode=TwoWay}"/>
<DataTemplate x:Key="Customer">
<StackPanel Orientation="Horizontal">
<TextBox Content="{Binding Name}" />
<TextBox Content="{Binding Email}" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox ItemsSource="{Binding Source={StaticResource Customers}}"
ItemTemplate="{StaticResource ResourceKey=Customer}"
Name="CustomerList"
Height="300" />
</StackPanel>
You need to change
ItemsSource="{Binding Source=Customers}"
to
ItemsSource="{Binding Source={StaticResource Customers}}" DataContext="{StaticResource Customers}"
Code similar to the updated one works for me after changing
<TextBox Content="{Binding Name}" />
to
<TextBox Text="{Binding Name}" />
As TextBox doesn't have Content property(like a Label), the former refused to compile in VS.
Well, it is set to Text in definition:
[ContentPropertyAttribute("Text")]
public class TextBox : TextBoxBase, IAddChild
But I thought it is only used between the brackets(<TextBox>Like so</TextBox>)?
Could this be the source of the problem?
Try setting the ItemsSource of your CustomerList as follows: ItemsSource="{Binding}". You've set the DataContext of the ListBox to the list of customers, you need to set the ItemsSource to the same collection, hence, the direct binding.
Another thing that you can do, in case you prefer to use the CollectionViewSource, is to set the DataContext of your window to the same class DataContext=this, because without this, the resource definition won't be able to locate the "Customers" collection that you defined in the code behind. If you do this, however, you don't need CustomerList.DataContext = Customers; because you're directly assigning the ItemsSource to a static resource, not relatively to the DataContext.
One more thing. I think you should give the CollectionViewSource and the corresponding collection in the code behind different names. This isn't going to cause a runtime issue, but it makes it hard to maintain the code ;)
Hope this helps :)