Set LongListSelector - c#

I'm developing a Windows Phone app to practice my knowledge within the control LongListSelector. One of the pages in the app, the middle one has this code:
<!--Panorama item two-->
<phone:PanoramaItem x:Name="tasksPage" Header="Tasks">
<!--Double line list with image placeholder and text wrapping using a floating header that scrolls with the content-->
<phone:LongListSelector Margin="0,-38,-22,2" ItemsSource="{Binding Items}" LayoutMode="List">
<phone:LongListSelector.ListHeaderTemplate>
<DataTemplate>
<Grid Margin="12,0,0,38">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBlock Text="second item"
Style="{StaticResource PanoramaItemHeaderTextStyle}"
Grid.Row="0"/>
</Grid>
</DataTemplate>
</phone:LongListSelector.ListHeaderTemplate>
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="12,2,0,4" Height="105" Width="432">
<!--Replace rectangle with image-->
<Border BorderThickness="1" Width="99" Height="99" BorderBrush="#FFFFC700" Background="#FFFFC700"/>
<StackPanel Width="311" Margin="8,-7,0,0">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Margin="10,0" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="{StaticResource PhoneFontSizeLarge}" />
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="10,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PanoramaItem>
Could someone please explain briefly what the DataBindings is and how to use them (I have done some research). Could I for instance bind the LongListSelector to a list in IsolatedStorage?
I have create a ListBox before in another app, loading content from IsolatedStorage into it, but I don't know if this is the right approach. Right now the items in the LongListSelector has a yellow image right left to it - can i do the same if I'm loading the content programatically from IsolatedStorage?
I know this might be a couple or three questions, but I think they're fairly simple to answer for someone experienced.
Thanks!

Your LongListSelector has a number of items inside. They are added there through data binding by binding the ItemsSource to items which are a part of Items collection. This collection can be a List<T> or more often ObservableCollection<T> because that way, if properly implemented, the changes in ObservableCollection will reflect in your LongListSelector. The T is the type of your item - for example, a class called Book. This collection needs to be defined as a part of the DataContext object, which you set on the whole page or a part of page.
Now, as I mentioned, the Items collection is probably full of items - objects defined to have certain properties. In your case, those properties are LineOne and LineTwo, which are probably strings.
You cannot directly bind to items in isolated storage. You first need to load those items into memory. Let's assume you have a list of items serialized to JSON or XML format in your isolated storage, which is one popular way of keeping the list in isolated storage. You need to load them into a collection (deserialize) and then bind to LongListSelector. It is the right approach, yes.
The yellow image/rectangle/border defined on the left is static, but it can be there, of course. It will simply be rendered there as a part of every item you have in your LongListSelector and it will not depend on the object which you bind to.
I suggest you read the following articles/questions and answers which may explain the concept of binding to a list easier for you to understand:
MSDN - Quickstart: Data binding to controls for Windows Phone
Stack Overflow - WP8 working with XML and LongListSelector
GeekChamp - The New LongListSelector control in Windows Phone 8 SDK
in depth

Simplest explanation (overlysimplified!) is that data binding is binding a property of an object to another property a control above, there's:
<TextBlock Text="{Binding LineOne}" ... />
That is functionally equivalent to something like this:
TextBlock t = new TextBlock();
SomeObject o = new SomeObject() { LineOne = "The value of line 1" };
t.Text = o.LineOne;
// and then a propertychange listener to update t.text if o.lineone ever changes
o.PropertyChanged += (s,e) => { if (e.PropertyName == 'LineOne') t.Text = o.LineOne; };
You can't bind directly to something in isolated storage, but you can have an object load its content from isolated storage, expose those items through an Items property and then set that as the data context of the LLS.
In cases like LongListSelector (or other ItemsControl types) the itemscontrol's ItemsSource property is bound to some collection of objects (like an ObservableCollection<T>, which makes its items update whenever the collection updates. And then a template inside the ItemsControl has bindings to the properties of the individual items in the collection.

Related

XAML SampleData Binding to Values of a List of Strings

OK, so I've searched and searched and searched, and I can't find an answer to this specific angle of my question. I know how to bind to a List, and how to make it auto-updating by making it an ObservableCollection instead of a List. However, with just a list of Strings, how the heck to I bind to the value of each List element?
<DataTemplate x:Key="PageTiles">
<Grid Background="{StaticResource PhoneAccentBrush}"
Margin="6,0,6,12">
<StackPanel VerticalAlignment="Bottom">
<TextBlock Text="{Binding}"
Margin="6,0,0,6" />
</StackPanel>
</Grid>
</DataTemplate>
Here's the LongListSelector that pulls from the list:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0" VerticalAlignment="Top" Height="60">
<phone:LongListSelector Margin="0,0,-12,0"
ItemsSource="{Binding PageTitles}"
LayoutMode="Grid"
GridCellSize="150,150"
ItemTemplate="{StaticResource PageTiles}"
SelectionChanged="LongListSelector_SelectionChanged">
</phone:LongListSelector>
</Grid>
Now, I've used a similar layout before to do tiles based off a List of classes that have string properties, but never with a List of strings, and I can't find anything to guide me in the right direction.
So it turns out #har07 was right. The Text="{Binding}" I'd put in the text value was valid, my cell size was just too large for it to show in the 60 high grid that I'd made. Reduced the height of it to less than the stack panel's height and bam, there it was. I didn't even do that on purpose, that's just how I'd left it while I didn't know what to put in there, and because I hadn't recompiled to get the associations fixed, it wasn't finding anything to put in as elements.
So, to recap, to get the values of a List directly instead of something that's part of that value, a simple "{Binding}" does the trick. Lesson learned: double check your size values before running for help XD.

WinRT hierarchical data displaying

I need to display hierarchical data like:
public class Element
{
public string Name { get; private set; }
public Element[] Elements { get; private set; }
}
It would be just vertical panel with rectangle (with Name) for each element. If element is clicked, its child elements are displayed below it (element is expanded). If one of them is clicked, its elements appear and so on.
I already googled this and found out that there is no HierarchicalDataTemplate and no treeview in WinRT.
So I started to do it by myself.
I created ItemsControl and DataTemplate DataTemplate1 for it. In DataTemplate1 I also create ItemsControl and set DataTemplate2 as ItemTemplate. In DataTemplate2, ItemTemplate is DataTemplate3 and so on. The last DataTemplate is without ItemsControl.
In buttons Click event I change Elements IsVisible property for any elements in DataModel (that is Element[]), so it is easy to perform any custom logic to expand/collapse elements.
<DataTemplate x:Key="DataTemplate2">
<StackPanel Visibility="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<Button Style="{StaticResource ItemButtonStyle}"
Click="MenuElement_Click">
<TextBlock Style="{StaticResource ItemTextBlockStyle}" Text="{Binding Name}"/>
</Button>
<ItemsControl ItemsSource="{Binding Elements}" ItemTemplate="{StaticResource DataTemplate3}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="DataTemplate1">
<StackPanel Visibility="{Binding IsVisible, Converter={StaticResource BooleanToVisibilityConverter}}">
<Button Style="{StaticResource ItemButtonStyle}"
Click="MenuElement_Click">
<TextBlock Style="{StaticResource ItemTextBlockStyle}" Text="{Binding Name}"/>
</Button>
<ItemsControl ItemsSource="{Binding Elements}" ItemTemplate="{StaticResource DataTemplate2}"/>
</StackPanel>
</DataTemplate>
It works fine, but the problem is that if I want to enable 10 levels of hierarchy, I have to copypast 10 datatemplates. And 11 level still will not be available.
I also tried to create DataTemplate in C# and manually apply DataTemplate for its ItemSource and so on, in recursive method.
But I found 2 problems.
I don't know actually how to create DataTemplate in metro (C#), because it has no VisualTree property. I can only make (var dt= new Datatemplate();) and I don't know how to change it.
If I read DataTemplate from XAML (var dateTemplateRoot = (DataTemplate)this.Resources["DataTemplate1"];)
I still can't find ItemsControl in it and change its DataTemplate.
Actually, I can use var content = dateTemplateRoot.LoadContent(); and then find ItemsControl by VisualTreeHelper, but I can't use content after that as DataTemplate (content has type DependencyObject).
So, actually I have 2 questions.
Is it a good approach to perform hierarchical dropdown list by "binding" all items and only switch Visibility property?
The second is - how to enable unlimited level of hierarchical nesting?
WinRT XAML Toolkit has a TreeView control now. Check it out: http://winrtxamltoolkit.codeplex.com/SourceControl/changeset/view/b0ee76bd6492#WinRTXamlToolkit/Controls/TreeView/TreeView.cs
Take care though - this is just a rough port from Silverlight Toolkit and might not work so well. Also if you are planning on releasing it as part of a Windows Store application - you would need to heavily restyle it unless your app is desktop-only since it is not very touch-friendly.

clearing a mapItemsControl.Itemtemplate WP7 Maps

hi im recurringly updating this map and i noticed its acumulating items rather than just refreshing all items for example
Im assing items to it by mapz.ItemsSource = App.ViewModel.LocationItems;
how do i clear the existing items in mapz before this ?
<my:Map x:Name="myMap" Height="480" Width="444" CredentialsProvider="NON YE BIZ"
Grid.ColumnSpan="1" LogoVisibility="Collapsed" CopyrightVisibility="Collapsed" Margin="5,0,10,0" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" >
<my:MapItemsControl x:Name="mapz" ItemsSource="{Binding LocationItems}" Width="450">
<my:MapItemsControl.ItemTemplate>
<DataTemplate>
<my:Pushpin Name="MyPushPin" Location="{Binding Target_Coordinate}" Content="{Binding Target_NickName}"/>
</DataTemplate>
</my:MapItemsControl.ItemTemplate>
</my:MapItemsControl>
</my:Map>
Simply call LocationItems.Clear(). If LocationItems is a ObservableCollection, the map with clear off the already rendered items.
No reason at all to access the UI directly when using data bindings.
The ItemTemplate defines the look-and-feel and general behavior of a control - it is not the control itself. Therefore, you have to look at the collection itself, and not the template. To clear the existing ItemCollection, you need this:
mapz.Items.Clear();

Populate WPF DataGrid dynamically

My program needs to take input from a fire alarm panel over a serial connection and populate a list based on it. When a new device is reported from the panel, the statement is parsed and the device is added to the device List.
That part of my program all works fine and dandy. The problem now is displaying the list of fire alarm devices to the user.
I am hoping to do this using a DataGrid (unless there's a better way?) but am not able to find a lot of helpful documentation on WPF DataGrids that is relevant to me. Most of what's out there seems to be displaying data from a database. Mine however, needs to update every time the panel spits out a new device description and the device List in my program is appended.
I see I can set AutoGenerateColumns to true and initially display my list just fine. BUT, I would like to customize the column headers. Also this doesn't update when the List is appended so I'm not sure how to "refresh" it.
When AutoGenerateColumns is false, I get no data displayed. When the program runs it shows me the correct number of rows corresponding to the number of items in my list, but no data. Wondering how/if I need to link each column with its corresponding device data member?
Lastly, how do you format a DataGrid to look pretty through re-sizes? I can set column width and all that, but what I want is a few of the columns to be fixed width, and the middle column to expand to fill remaining available area.
This is my first stab at WPF. Any help would be greatly appreciated!
Personaly i dont like DataGrid much. Yes they are easier to bind and they offer built-in resize and sorting options but they are not as flexible as an ItemsControl with a good DataTemplating on your Objects. Let me explain myself.
I tend to populate my ItemsControl with an ObservableCollection. Then, i use a DataTemplate in order to tell my ItemsControl how to display my custom items.
Your CustomObjects can be Modeles objects if your doing MVVM.
If your list is binded to an ObservableCollection, the Added and Removed items will appear dynamicly into your list, which is what i belive your trying to do.
For the column size, you could put a Grid specifying GridColumns width to fixed Width for some columns and * for others so they fill the remaining space.
Here's an alternative to the GridView
I use a ScrollViewer around my ItemControl so if the ItemsControl get too big, you can scroll it.
The ItemsControl's ItemSource is binded to your FireAlarms's ObservableCollection.
The WrapPanel in the ItemsControl will contain each DataTemplate. It's Width is binded to his parent (or ancestor if you will) which is an ItemsControl
<ScrollViewer
Grid.Row="x"
Grid.Column="y"
VerticalScrollBarVisibility="Auto"
Margin="5">
<ItemsControl
BorderBrush="DarkBlue"
BorderThickness="2"
ItemsSource="{Binding Path=FireAlarms}"
ItemTemplate="{StaticResource FireAlarmsTemplate}"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel
Orientation="Horizontal"
Width="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ItemsControl}},
Path=ActualWidth}"
>
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
Ok then you need a DataTemplate. You can put the DataTemplate in your windows's ressource or in a DataDictionnary. Lets say you have a class :
FireAlarm
{
Public String AlarmInfo1;
Public String AlarmInfo2;
Public String AlarmInfo3;
}
Here could be a nice DataTemplate to start with :
<DataTemplate x:Key="FireAlarms">
<Border
BorderBrush="SteelBlue"
Background="LightBlue"
BorderThickness="2"
Margin="10"
Padding="10">
<StackPanel
Orientation="Vertical"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="5"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label
Grid.ColumnSpan="3"
Grid.Row="0"
Content="{Binding Path=AlarmName}"
Margin="5,-5,5,10"
FontWeight="Bold"
FontSize="16"
HorizontalContentAlignment="Center"
HorizontalAlignment="Center">
</Label>
<TextBlock
Text="Alarm information 1" Grid.Row="1" Grid.Column="0" />
<TextBox
Text="{Binding Path=AlarmInfo1}"
Grid.Column="2"
Grid.Row="1"
>
</TextBox>
<TextBlock
Text="Alarm information 2" Grid.Row="2" Grid.Column="0" />
<TextBox
Text="{Binding Path=AlarmInfo2}"
Grid.Column="2"
Grid.Row="2"
>
</TextBox>
<TextBlock
Text="Alarm information 3" Grid.Row="3" Grid.Column="0" />
<TextBox
Text="{Binding Path=AlarmInfo3}"
Grid.Column="2"
Grid.Row="3"
>
</TextBox>
</Grid>
</StackPanel>
</Border>
</DataTemplate>
Ok I hope this is usefull for you. My Template will generate 1 square per alarm. If you'd rather have it in a Table like a GridView, you could modify this using a verticaly oriented stack panel and use a grid with variable // invariable column width but since you asked for anything usefull, i tough i'd guive you something fun to work with!
Enjoy!
Some time back I wrote a post Create DataGrid in WPF using code take a look at it, it will help you in creating data grid in dynamic scenarios like yours
If you a dynamic grid (meaning the number and design of the columns are unknown at design time), I do it with code-behind with binding. I generally use the MVVM pattern (if you not familiar with this, I really recommend reading into it since it is THE pattern when working with WPF).
1) You have to set Auto-Generate columns to false of course and give grid a name (here myDataGrid)
GridViewDataColumn newColumn= new GridViewDataColumn();
myDataGrid.Columns.Add(newColumn)
This will add the column to your grid. Now the column will be empty. Now it depends on your data how to fill it with data. If you bind to a known property on the items, do:
newColumn.Binding = new Binding("knownPropertyName");
In most cases though, you do not know the propertyname and bind to an element in the collection.
Then it would like more:
myDoubleCollection.Add(someDoubleValue); //do this for each item in the itemssource of the grid
int index=myDoubleCollection.Count-1;
newColumn.Binding = new Binding(string.Format("myDoubleCollection[{0}]",index));
So this works also.
Another thing to keep in mind is the deletion of columns. This requires some extra work.
That's a lot of questions rolled into one! I suggest you do a bit more background research before asking questions. I would recommend that your read this codeproject article I wrote about the WPF DataGrid a while back:
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx
It will answer most of your questions for you!
Take a look at the MVVM pattern, it'll be a huge help as you create this application.
What you want is an ObservableCollection in the ViewModel. You'll bind the ItemsSource property of the datagrid to this collection. Then have your columns bind to various properties on to display them. Whenever this ObservableCollection has an item appended, your front end should update automatically.
To have a column autosize, set the Width="*".
Here's a sample of a datagrid with MVVM
<DataGrid ItemsSource="{Binding FireAlarmCollection}" SelectedItem="{Binding SelectedFireAlarm, Mode=TwoWay}" AutoGenerateColumns="True" CanUserSortColumns="True" HorizontalScrollBarVisibility="Visible" CanUserResizeColumns="True">
</DataGrid>
As you continue your effort, post separate questions for each issue.

Find child elements in a WPF ListView ItemTemplate

Given a populated ListView, how do I iterate through each bound template and pluck out the contained ComboBox (or any other control contained in DataTemplate)?
<ListView x:Name="lstCommands">
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="gridInputs">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Content="{Binding Path=Key}"/>
<ComboBox x:Name="cbInputCmd" Grid.Column="1" ItemsSource="{Binding Source={StaticResource inputData}}" Tag="{Binding Path=Key}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
Firstly, avoid doing so unless you really need to. If you absolutely must, you can use DataTemplate.FindName, where the templated parent is the ListViewItem generated by the ListView. To get the ListViewItem, use the ListView's ItemContainerGenerator.
Update: the reason I suggest avoiding this approach wherever possible is because it creates more tightly-coupled, brittle code. The OP didn't mention why he wanted to do what he was asking, but I suspect he could achieve his goal by more idiomatic means, such as with bindings.
is simple
just do this
<ListViewItem Name="mainiterm" Style="{ StaticResource inboxlst}" Selected="ListViewItem_Selected_1">
<Canvas Style="{StaticResource inboxcanvas}">
<Label Name="namelabel" Content="lalallala1" Style="{StaticResource inboxlabel1}" />
<Label Content="lalallala" Style="{StaticResource inboxlabel2}"/>
</Canvas>
</ListViewItem>
and vb
Dim r = mlistview.Items.GetItemAt(i)
Dim textYear As Label = Nothing
Dim s As Canvas = r.Content
Dim a As Label = s.Children.Item(1)
a.Content = "Disconnected"
a is a label, s is a cavas
you could try using the LogicalTreeHelper or VisualTreeHelper which lets you query an object for its children, but if you were binding your combo boxes to the item your list view is displaying you would not have to worry about 'getting' them at all.
Then you could just look at your item.
Any time you find yourself walking the visual or logical tree looking for elements which exist in your ui, so that you can get their values, ask yourself 'what am i missing here' 'why isnt my business (or view model) being updated with relevant data when the user interacts with the ui?'
For the example above I would build a view model that had two properties, a String (for your label) and a SelectedItem (that you could bind your combo box selected item to). its easier, more robust and it stops you having to trawl through the visual elements. one of the beautiful things about xaml/wpf is that it seperates your logic from your view. what you are suggesting will break this model. You will entangle the view with your logic and from there on it gets messy...

Categories