I'am new to tweetinvi, and now i'm stuck with databinding. it's doable to retrieve tweets and i can show up the last one in a TextBlock in my XAML. but now i like to have it in a list or gridview.
code to retrieve tweets
var homeTimelineTweets = authenticatedUser.GetHomeTimeline();
foreach (var tweet in homeTimelineTweets)
{
textBlock.Text = tweet.Text;
//textBlock.Text = tweet.CreatedBy.ScreenName;
//textBlock.Text = tweet.CreatedBy.Name + ", " +tweet.Text;
//textBlock.Text = tweet.Text;
}
Code for Xaml
<ListView>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="textBlock"
HorizontalAlignment="Left"
TextWrapping="Wrap"
Text="TextBlock"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
i know i have to set x:bind and x:data ... but i can figure out how?
Related
I am a beginner in Windows phone programming.
I want to bind the data from API to my XAML elements using that Binding Attributes. Please let me know how can we bind multilevel classes objects in it.
Here's my scenario.
List<Sample> SearchResult = new List<Sample>()
{
new Sample(){
Name="ABC",
modelProperty = new SampleDetail(){
articleNo="1", videoURL = "https://www.youtube.com/watch?v=abc",
colors = new List<ColorsDemo>(){
new ColorsDemo {
Name = "Red",
colorProperty= new ColorDemoProperty{ name = "ABC",article_no = "Art1",
image = new Uri("http://img.youtube.com/vi/e60E99tUdxs/default.jpg",UriKind.RelativeOrAbsolute)
}
}
}
}
}
And now, I want to bind the Name of ColorsDemo class into my textblock. See what I have done to bind in XAML like this:
<TextBlock x:Name="PName" Grid.Row="0" Margin="100,0,0,0" Tap="ProductName_Tap" HorizontalAlignment="Center" VerticalAlignment="Center" Width="350" TextWrapping="Wrap" Foreground="Black" Text="{Binding Path=modelProperty.colors.Name}" FontSize="30"></TextBlock>
From your code, i see that colors is a List of ColorDemo objects. So when you say {Binding Path=modelProperty.colors.Name}it does not tell which list item to bind to. The correct usage should be {Binding Path=modelProperty.colors[0].Name}. This tells the control to bind to the name of the first color item (as index is 0).
To bind all the colors. You should use a Listview and bind the colors in it. So you should be able to do something like this.
<ListView ItemSource={Binding Path=modelProperty.colors}>
<ListView.ItemTemplate>
<TextBlock x:Name="PName" Grid.Row="0" Margin="100,0,0,0" Tap="ProductName_Tap" HorizontalAlignment="Center" VerticalAlignment="Center" Width="350" TextWrapping="Wrap" Foreground="Black" Text="{Binding Path=Name}" FontSize="30"></TextBlock>
</ListView.ItemTemplate>
</ListView>
I am working on a Windows Phone 8.1 app in XAML and C#.
I have a listview, whose item source is set to a CollectionViewSource called MusicSource. On the backend in C#, I have an ObservableCollection called source and the following code populates it by getting getting all the music files on the phone, groups it by artist and then puts them in the CollectionViewSource, which shows them in the listview:
var folders = await folder.GetFoldersAsync();
if (folders != null)
foreach (var fol in folders)
await getMusic(fol);
var files = await folder.GetFilesAsync();
foreach (var file in files)
{
MusicProperties musicProperties = await file.Properties.GetMusicPropertiesAsync();
this.source.Add(new Music((musicProperties.Artist.Length > 0) ? musicProperties.Artist : "Custom", (musicProperties.Title.Length > 0) ? musicProperties.Title : file.Name, (musicProperties.Album.Length > 0) ? musicProperties.Album : "Custom Album", file.Path));
}
itemSource = AlphaKeyGroup<Music>.CreateGroups(source, CultureInfo.CurrentUICulture, s => s.Artist, true);
this.MusicSource.Source = itemSource;
The following is the XAML side of it:
<Page.Resources>
<DataTemplate x:Key="GroupTemplate">
<Grid Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1">
<TextBlock x:Name="SongTitle" Text="{Binding Title}"
Style="{ThemeResource ListViewItemTextBlockStyle}"/>
<TextBlock x:Name="ArtistName" Text="{Binding Album}"
Style="{ThemeResource ListViewItemContentTextBlockStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
<CollectionViewSource x:Name="MusicSource" IsSourceGrouped="true" />
<DataTemplate x:Key="headerTemplate">
<StackPanel HorizontalAlignment="Stretch" Width="{Binding ActualWidth, ElementName=contentList}">
<TextBlock Text="{Binding Key}" />
</StackPanel>
</DataTemplate>
</Page.Resources>
<Grid>
<SemanticZoom>
<SemanticZoom.ZoomedInView>
<ListView
x:Name="contentList"
SelectionMode="Multiple"
ItemsSource="{Binding Source={StaticResource MusicSource}}"
ItemTemplate="{StaticResource GroupTemplate}">
<ListView.GroupStyle>
<GroupStyle HidesIfEmpty="True" HeaderTemplate="{StaticResource headerTemplate}"/>
</ListView.GroupStyle>
</ListView>
</SemanticZoom.ZoomedInView>
</SemanticZoom>
<Border
x:Name="SearchBorder"
Background="White">
<TextBox
x:Name="Search" TextChanged="TextBox_TextChanged" />
</Border>
</Grid>
So I get something like the following in the listview:
Michael Jackson
Bad
Dangerous
Thriller
Eminem
Not Afraid
The Monster
I have a textbox with the name search that is intended to search the listview.
What should happen is that as I type in the textbox, the listview scrolls to the nearest group whose group header matches the text in the textbox. So if I type "Em", the listview should immediately scroll downwards to the "Eminem" category of items.
How would I achieve this?
Also, is it possible to do the same thing, except scroll to the item whose songTitle attribute matches that of the text in the textbox?
Wow that is one hard problem. I've done something very similar in the past. Basically you want an AJAX solution to an ObservableCollection set. You can achieve this by writing a search function through your AlphaKeyGroup with the help from a Regular Expression match. This should return your element that it needs to scroll to.
As for getting to it to search each text change you need to attach a TextChanged Event to the textbox like so:
<TextBox x:Name="my_search" TextChanged="my_search_TextChanged" Grid.Row="0" />
When it finds a match, you want to scroll to that element with
contentList.ScrollIntoView(matching_element);
Okay, posted the Windows Phone 8.1 Solution : ListView Searching Project
Highlights included the Searching Routine that are added to the GroupKey class.
public T FindMatch(string pattern, GetKeyDelegate getKey)
{
Regex rgx = new Regex(pattern, RegexOptions.IgnoreCase);
foreach (T item in this.Items)
{
string key = getKey(item);
Match match = rgx.Match(key);
if (match.Success)
return item;
}
return default(T);
}
Set ICollectionView.Filter callback to filter your listview everytime the TextChanged event is raised like so:
private void TextBox_TextChanged(object sender, TextChangedEven)
{
ICollectionView view = lvTest.ItemsSource as ICollectionView;
string txtToSearch = searchTextBox.Text;
view.Filter = (p) => { return ((Music)p).ArtistName.Contains(txtToSearch); };
view.Refresh();
}
That way you avoid having to decide where to set the current item when it matches more than one Artist name.
I cannot bind my sample data to textblocks in stackpanel, which I defined in resources. I think that I use style in wrong way, because I receive toString() method instead of class binded fields.
That's my resources with defined style:
<UserControl.Resources>
<ItemsPanelTemplate x:Key="VirtualizingStackPanelTemplate">
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl.Resources>
Here is my method in which i add listview programatically:
long rowCount = ContentGridFullView.RowDefinitions.LongCount();
if (rowCount > 8) return;
var c1 = new RowDefinition { Height = new GridLength(1, GridUnitType.Star) };
ContentGridFullView.RowDefinitions.Add(c1);
rowCount = ContentGridFullView.RowDefinitions.LongCount();
TextBlock tb = new TextBlock {Text = "TEXTBLOCK ITEM = " + (rowCount - 1), FontSize = 40};
Viewbox vb = new Viewbox { Child = tb };
if (rowCount > 8) return;
Grid.SetRow(vb, Convert.ToInt32(rowCount-1));
Grid.SetColumn(vb, 1);
ListView lb = new ListView();
lb.Style = Resources["ListBoxTemplate"] as Style;
lb.ItemsPanel = (ItemsPanelTemplate) Resources["VirtualizingStackPanelTemplate"];
var products = new ObservableCollection<Product>() { new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC"), new Product("ASDASDSADAS", "VCBVCBVCBVCBC") };
lb.ItemsSource = products;
ContentGridFullView.Children.Add(lb);
ContentGridFullView.Children.Add(vb);
Grid.SetRow(lb, Convert.ToInt32(rowCount - 1));
Grid.SetColumn(lb, 2);
And my short class that I want to bind:
public class Product
{
public string Title { get; set; }
public string Desc { get; set; }
public Product(string title, string desc)
{
Title = title;
Desc = desc;
}
public override string ToString()
{
return "I see that message instead of Title and Desc";
}
}
Can someone tell me what's wrong with this code? Thank you.
Create your Observable collection as a property (getter/setter):
ObservableCollection<Product> _products;
public ObservableCollection<Product> products
{
get{return _products;}
set
{
_products=value;
PropertyChanged("products");
}
}
The property changed event will be need to indicate that the collection has changed,its needed when your using ObservableCollection. You'll need to read more about it.You can add items to the products collection by using :
products.Add(Product_object)
And your xaml code will have the itemsSource as follows:
<ListView x:Key="ListBoxTemplate" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Visible" ItemsSource="{Binding products}">
<ListView.ItemTemplate>
<DataTemplate>
<!--<ListBoxItem Background="DarkOrchid" Margin="1,1, 5,5" Height="400" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch">-->
<StackPanel>
<TextBlock FontSize="30" Text="{Binding Title}"/>
<TextBlock FontSize="20" Text="{Binding Desc}"/>
</StackPanel>
<!--</ListBoxItem>-->
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The following statement is important in your xaml code so that your xaml code will know where to look for the data.
DataContext="{Binding RelativeSource={RelativeSource Self}, Path=x}
First try and create a static list and check if data is getting initialized properly and then you can try creating listviews dynamically. But the code above will be the same thing you will have to do create dynamic listviews.
I already have a ListBox in my Code and now I added a new one:
<ListBox x:Name="Diaryresult"
Foreground="Black"
Margin="19,0,0,8">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Binding {name}"
FontSize="24" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I am populating this list with following code:
XElement diary = XElement.Parse(e.Result);
IEnumerable<XElement> diaryelements = diary.Elements("diaryelement");
List<Produkt> diaryprodukte = new List<Produkt>();
foreach (XElement diaryelement in diaryelements)
{
Produkt p = new Produkt();
p.name = diaryelement.Element("diaryshortitem").Element("description").Element("name").Value;
p.shortfacts = diaryelement.Element("diaryshortitem").Element("data").Element("kj").Value + " KJ - "
+ diaryelement.Element("diaryshortitem").Element("data").Element("kcal").Value + "kcal";
diary.Add(p);
Debug.WriteLine("Added "+p.name);
}
Diaryresult.ItemsSource = diaryprodukte;
Diaryresult.Visibility = System.Windows.Visibility.Visible;
But, it doesn't show up. Does anyone see the trick?
Your binding tag isn't correct. "Binding {Name}" doesn't means anything for XAML. {Binding Name} means to databind the property Name of your context which is what you're trying to do.
Replace:
<TextBlock Text="Binding {name}" FontSize="24" />
With:
<TextBlock Text="{Binding name}" FontSize="24" />
Also you need to add the element to the list:
dairyprodukt.Add(p);
And, remember to call your NotifyPropertyChanged() once done in order to notify the UI Thread of the changes. I mean, you're using Diaryresult.Visibility = System.Windows.Visibility.Visible; is this your way to notify your UI, are you using MVVM or CodeBehind?
It doesn't look like you are adding your Produkt to dairyprodukte. dairyprodukte is still an empty list when you bind it.
try
foreach (XElement diaryelement in diaryelements)
{
Produkt p = new Produkt();
p.name = diaryelement.Element("diaryshortitem").Element("description").Element("name").Value;
p.shortfacts = diaryelement.Element("diaryshortitem").Element("data").Element("kj").Value + " KJ - "
+ diaryelement.Element("diaryshortitem").Element("data").Element("kcal").Value + "kcal";
diary.Add(p);
Debug.WriteLine("Added "+p.name);
diaryprodukte.Add(p);
}
Can someone see what I need to change here? I am displaying an observablecollection of AddressTypeClass items. The object items show up in the listbox instead of the data. I can see the data in the objects in debug mode.
THE XAML.CS FILE:
DataContext MyTableDataContext = new MyTableDataContext();
ObservableCollection<AddressTypeClass> theOC = new ObservableCollection<AddressTypeClass>(new MyTableDataContext().AddressTypes.AsEnumerable()
.Select(lt => new AddressTypeClass
{
AddressTypeID = lt.AddressTypeID,
AddressType = lt.AddressType,
})
.ToList());
this.listBox1.ItemsSource = theOC;
THE XAML FILE:
<ListBox Name="listBox1" Margin="8" Height ="200" Width ="150" FontSize="12" Foreground="#FF2F3806" ItemsSource="{Binding AddressType}" IsSynchronizedWithCurrentItem="True" >
</ListBox>
You need to add an ItemTemplate to your ListBox, e.g.
<ListBox Name="listBox1" Margin="8" Height ="200" Width ="150" FontSize="12" Foreground="#FF2F3806" ItemsSource="{Binding AddressType}" IsSynchronizedWithCurrentItem="True" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Path=AddressType}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You can impove your code by using my ObservableComputations library. In your code you manualy update theOC every time MyTableDataContext.AddressTypes dbSet (I assume you are using EntityFramework) changes (new item or remove) or properties (AddressType.AddressTypeID, AddressType.AddressType) changes. Using AddressType you can automate that process:
DataContext MyTableDataContext = new MyTableDataContext();
ObservableCollection<AddressTypeClass> theOC = MyTableDataContext.AddressTypes.Local
.Selecting(lt => new AddressTypeClass
{
AddressTypeID = lt.AddressTypeID,
AddressType = lt.AddressType,
});
this.listBox1.ItemsSource = theOC;
theOC is ObservableCollection and reflects all the changes in the MyTableDataContext.AddressTypes.Local collection and properties mentioned in the code above. Ensure that all properties mentioned in the code above notify of changes through the INotifyProperytChanged interface.