I'm attempting to allow users to draw on a Canvas by collecting the points as they tap and drag. I'm using an MVVM approach and can successfully collect points, and populate a collection of lines on the View Model. However, I need to be able to display those line controls on a canvas so the user can see the line they are drawing.
My question is, how can I databind the View Models collection of Line controls to the canvas's Children collection?
This can be achieved using an ItemsControl:
<ItemsControl ItemsSource="{Binding CollectionOfLines}">
<!-- specify the panel that the items will be added to -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line X="{Binding ...}" Y="{Binding ...}" .../>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Related
In Xamarin.Forms 3.5 Microsoft introduced us to bindable layouts which can be used to dynamically fill layouts (e.g. StackLayout, Grid, etc.).
To use this in a grid with a single column is pretty straightforward:
<Grid BindableLayout.ItemsSource="{Binding Items}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label Text="{Binding MyProperty}"/>
</DataTemplate>
</BindableLayout.ItemTemplate>
</Grid>
Now my question is how this can be used to populate a grid with more than one column due to the fact that DataTemplate only allows one view as content. Sure I could but another Grid in it but this would totally nullify the value of bindable layout in a Grid.
Now my question is how this can be used to populate a grid with more than one column due to the fact that DataTemplate only allows one view as content.
From Bindable Layouts, we can see:
While it's technically possible to attach a bindable layout to any layout class that derives from the Layout class, it's not always practical to do so, particularly for the AbsoluteLayout, Grid, and RelativeLayout classes. For example, consider the scenario of wanting to display a collection of data in a Grid using a bindable layout, where each item in the collection is an object containing multiple properties. Each row in the Grid should display an object from the collection, with each column in the Grid displaying one of the object's properties. Because the DataTemplate for the bindable layout can only contain a single object, it's necessary for that object to be a layout class containing multiple views that each display one of the object's properties in a specific Grid column. While this scenario can be realised with bindable layouts, it results in a parent Grid containing a child Grid for each item in the bound collection, which is a highly inefficient and problematic use of the Grid layout.
If you still want to more column, I suggest you can use StackLayout, it can also meet your requirement.
<StackLayout BindableLayout.ItemsSource="{Binding persons}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding name}" />
<Label Text="{Binding age}" />
</StackLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
Checking this issue, seems that what you are trying to accomplish can't be done with a Bindable Layout using a Grid as a Element.
The documentation isn't as clear as it should, nevertheless.
You can subscribe to BindingContextChanged event and configure then all the items. You have to configure the grid definitions programatically after the event.
Which control in Xamarin can be utilized to do listing through a list of objects with the arrows left and right such as the one on the screenshot?
There is no such a control in Xmarin.forms .But you can implement it by yourself.
in xaml
<Grid VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.RowDefinitions>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.15*" />
<ColumnDefinition Width="0.7*" />
<ColumnDefinition Width="0.15*" />
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Image Source="xxx" x:Name="rightBtn"/>
</StackLayout>
<controls:CarouselViewControl Grid.Column="1" Orientation="Horizontal" InterPageSpacing="10" Position="{Binding myPosition}" ItemsSource="{Binding myItemsSource}" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<controls:CarouselViewControl.ItemTemplate>
<DataTemplate>
<local:MyView />
<!-- where MyView is a ContentView -->
</DataTemplate>
</controls:CarouselViewControl.ItemTemplate>
</controls:CarouselViewControl>
<StackLayout Grid.Column="2" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Image Source="xxx" x:Name="leftBtn"/>
</StackLayout>
</Grid>
You can use CarouselView . And change the position of it when you click right or left button .You can add a tap gesture recognizer on image or use ImageButton if you want to set button image by yourself. Or you can use default arrows of CarouselView .
If the arrows are a requirement and you don't have many items in your control (10 or less), the CarouselView is matching exactly your requirements. You can even show the arrows with the ShowArrows property.
https://github.com/alexrainman/CarouselView
Careful though cause this component doesn't recycle its views, that's why it's good only for a small number of views.
If you have a high number of views, you use this HorizontalListView with Carousel list layout:
https://github.com/roubachof/Sharpnado.Presentation.Forms#carousel-layout
What about the Xamarin.Forms CollectionView?
CollectionView has a flexible layout model, which allows data to be presented vertically or horizontally, in a list or a grid.
CollectionView supports single and multiple selection.
CollectionView has no concept of cells. Instead, a data template is used to define the appearance of each item of data in the list.
CollectionView automatically utilizes the virtualization provided by the underlying native controls.
CollectionView reduces the API surface of ListView. Many properties and events from ListView are not present in CollectionView.
CollectionView does not include built-in separators.
See documentation.
Databinding still confues me and I am not sure how to essential make these controls repeat for each bound piece of data I have.
<Grid>
<TextBlock FontSize="25" Text="this is a header"></TextBlock>
<TextBlock Height="30" HorizontalAlignment="Left" Margin="19,36,0,0" Name="txt" Text="line under the header" VerticalAlignment="Top" />
<TextBlock Height="30" FontSize="25" HorizontalAlignment="Left" Margin="306,9,0,0" Name="textBlock2" Text="530" VerticalAlignment="Top" Width="91" />
<TextBlock Height="30" HorizontalAlignment="Left" Margin="305,42,0,0" Name="textBlock3" Text="30" VerticalAlignment="Top" Width="91" />
</Grid>
If my data source would have a count of 50. I would expect to see 50 of these groupings(I probably need to get a scroll bar though).
Not sure how to do this though. I need some sort of datatemplate I guess? Also "line under the header" should be clickable and highlight.
I think you need to use the control named "ItemsControl". Not a derived class, not a ListBox, just plain simple ItemsControl.
Either in code or in XAML, you set the ItemsControl's ItemsSource property to any collection containing your items.
In XAML (either in VS or Blend, to do it WYSIWYG in Blend you must somehow provide design data) you set the ItemsControl's ItemTemplate to a DataTemplate that contains the XAML subtree you want to repeat for every item in your collection.
Inside the DataTemplate, replace "line under the header" with the Button control, with Content="line under the header", and style it however you want. Then, add CallMethodAction to your button. It only takes 2 clicks in Blend, the first one is on "Assets" window. Specify TargetObject="{Binding}" MethodName="actSubtitleClicked". This way, the framework will call the void actSubtitleClicked() method of the item where user clicked the "line under the header".
For best performance, you should also modify the ItemsControl's ItemsPanel template, replacing StackPanel with VirtualizingStackPanel (again, a few clicks in Blend, the first one is the right click, then "Edit additional templates / ItemsPanel / Edit a copy")
I am trying to use the list picker control for wp 7 and caliburn micro. I get the binding correct from the model with conventions, but when I press the the picker to see the page to select somethin gelse I get the message
PID:0E2108CA TID:0F790ABE 2012-04-30 18:02:20.7180 View Model not found. Searched: Microsoft.Phone.Controls, Microsoft.Phone.Controls.ListPickerPageViewModel.
PID:0E2108CA TID:0F790ABE 2012-04-30 18:02:20.7210 View Model not found. Searched: Microsoft.Phone.Controls.IListPickerPageViewModel, Microsoft.Phone.Controls.ListPickerPageViewModel.
and it loads a complete blank page (think its the ListPickerPage in the control toolkit)
it doesnt matter if its bound or not, i guess its some convention hooking in that I dont want.
To reproduce start a new project, hoock up a viewmodel and view, enter below in in your xaml
my xaml looks like this
<toolkit:ListPicker Header="Background" ExpansionMode="FullscreenOnly">
<sys:String>dark</sys:String>
<sys:String>light</sys:String>
<sys:String>dazzle</sys:String>
<toolkit:ListPicker.FullModeItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="16 21 0 20">
<TextBlock Text="{Binding}"
Margin="0 0 0 0"
FontSize="43"
FontFamily="{StaticResource PhoneFontFamilyLight}"/>
</StackPanel>
</DataTemplate>
</toolkit:ListPicker.FullModeItemTemplate>
</toolkit:ListPicker>
What I would like to happen is ofcourse that the property of my model should popuplate the fullscreen selection, and also it would be nice to set the initial selection based on a property on the model.
Some points I noted:
You have to provide an ItemsSource to the ListPicker - A collection of some sort from which it can display the items. In TextBlock text={Binding } - You have to bind some property, so that it can display.
I have, for this example, an IList<> that contains a set of objects that are also lists. for example, a league consists of a set of teams and those teams are comprised of players. What I want is a single list that has one scrollbar.
I have tried nested ListBox controls but that ends up being a stack of multiple scrollbars that acts horrible. Scrolling is just bad and it seems to hide the bottom of the team's player list.
Any help would be great!!
Rather than a ListBox, why not use an ItemsControl? A ListBox provides selection, if you do not need this, an ItemsControl is more lightweight and will load faster. Also, with an ItemsControl you have full control over the elements that host your items. This way, you can omit the ScrollViewer.
To render your items, try the following:
<ItemsControl ItemsSource={Binding League.Teams}>
<!-- use a StackPanel to host your elements -->
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!-- render each team -->
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- render each player within the team -->
<ItemsControl ItemsSource={Binding Players}>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<!-- render the player's name -->
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can disable scrollbars for a ListBox quite easily. Just add ScrollViewer.VerticalScrollBarVisibility="Disabled" to the XAML attributes for the inner ListBox.