How to implement Hold in Listbox? - windows-phone-7

If hold the listbox, I want to get listbox index.
This is my code:
<ListBox Margin="0,0,-12,0"
Hold="holdlistbox"
x:Name="listbox"
SelectionChanged="listbox_SelectionChanged"
SelectedIndex="-1">
</ListBox>
private void holdlistbox(object sender, System.Windows.Input.GestureEventArgs e)
{
//How to get ListBox index here
}
If anyone knows help me to do this.

e.OriginalSource will get you the actual control that was held (the top-most control directly under your finger). Depending on your ItemTemplate and where you hold then this could be any of the controls in the item. You can then check the DataContext of this control to get the object that is bound to that item (going by your comment this will be an ItemViewModel object):
FrameworkElement element = (FrameworkElement)e.OriginalSource;
ItemViewModel item = (ItemViewModel)element.DataContext;
You can then get the index of this item in the items collection:
int index = _items.IndexOf(item);
If you want to get the ListBoxItem itself you will need to use the VisualHelper class to search the parent heirarchy. Here is an enxtension method that I use to do this:
public static T FindVisualParent<T>(this DependencyObject obj) where T : DependencyObject
{
DependencyObject parent = VisualTreeHelper.GetParent(obj);
while (parent != null)
{
T t = parent as T;
if (t != null)
{
return t;
}
parent = VisualTreeHelper.GetParent(parent);
}
return null;
}
I'm not sure if you need this (I couldn't be sure from your comment) but you can then do the following to get the context menu:
FrameworkElement element = (FrameworkElement)e.OriginalSource;
ListBoxItem listItem = element.FindVisualParent<ListBoxItem>();
ContextMenu contextMenu = ContextMenuService.GetContextMenu(listItem);
This assumes that the ContextMenu is attached to the ListBoxItem, if not then you need to search for a different control in the parent heirarchy.

var selectedIndex = (sender as ListBox).SelectedIndex;

Related

Create bindable properties for Treeview in Xamarin Forms

I needed to use a Treeview in my xamarin forms application, however the only existing TreeView on the net are not free (Syncfusion and Telerik).
So I found this very interesting project : https://github.com/AdaptSolutions/Xamarin.Forms-TreeView
the only problem that I found is that the ItemSource and SelectedItem properties are not bindable and therefor I can't use it on an MVVM Pattern. Which brings us to my question, How can I make them bindable.
I tried to follow this documentation : https://learn.microsoft.com/en-us/xamarin/xamarin-forms/xaml/bindable-properties
but still nothing. Can anyone help me with that please ? Thank you
UPDATE :
this is the TreeView class :
public class TreeView : ScrollView
{
#region Fields
private readonly StackLayout _StackLayout = new StackLayout { Orientation = StackOrientation.Vertical };
//TODO: This initialises the list, but there is nothing listening to INotifyCollectionChanged so no nodes will get rendered
private IList<TreeViewNode> _RootNodes = new ObservableCollection<TreeViewNode>();
private TreeViewNode _SelectedItem;
#endregion
#region Public Properties
public TreeViewNode SelectedItem
{
get => _SelectedItem;
set
{
if (_SelectedItem == value)
{
return;
}
if (_SelectedItem != null)
{
_SelectedItem.IsSelected = false;
}
_SelectedItem = value;
SelectedItemChanged?.Invoke(this, new EventArgs());
}
}
public IList<TreeViewNode> RootNodes
{
get => _RootNodes;
set
{
_RootNodes = value;
if (value is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += (s, e) =>
{
RenderNodes(_RootNodes, _StackLayout, e, null);
};
}
RenderNodes(_RootNodes, _StackLayout, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset), null);
}
}
#endregion
#region Constructor
public TreeView()
{
Content = _StackLayout;
}
#endregion
#region Private Static Methods
private static void AddItems(IEnumerable<TreeViewNode> childTreeViewItems, StackLayout parent, TreeViewNode parentTreeViewItem)
{
foreach (var childTreeNode in childTreeViewItems)
{
if (!parent.Children.Contains(childTreeNode))
{
parent.Children.Add(childTreeNode);
}
childTreeNode.ParentTreeViewItem = parentTreeViewItem;
}
}
#endregion
#region Internal Static Methods
internal static void RenderNodes(IEnumerable<TreeViewNode> childTreeViewItems, StackLayout parent, NotifyCollectionChangedEventArgs e, TreeViewNode parentTreeViewItem)
{
if (e.Action != NotifyCollectionChangedAction.Add)
{
AddItems(childTreeViewItems, parent, parentTreeViewItem);
}
else
{
AddItems(e.NewItems.Cast<TreeViewNode>(), parent, parentTreeViewItem);
}
}
#endregion
}
so what Im trying to do here is making RootNodes bindable as well as SelectedItem afterwards.
What I did is simply adding this, thinking it should work but obviously it does not :
public static readonly BindableProperty RootNodesProperty =
BindableProperty.Create(nameof(RootNodes), typeof(IList<TreeViewNode>), typeof(TreeView));
public IList<TreeViewNode> RootNodes
{
get => (IList<TreeViewNode>)GetValue(RootNodesProperty);
set
{
SetValue(RootNodesProperty, value);
_RootNodes = value;
if (value is INotifyCollectionChanged notifyCollectionChanged)
{
notifyCollectionChanged.CollectionChanged += (s, e) =>
{
RenderNodes(_RootNodes, _StackLayout, e, null);
};
}
RenderNodes(_RootNodes, _StackLayout, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset), null);
}
}
UPDATE 2 :
Here is what it looks like
Hope this helps
It seems you will not need to create custom ItemSource and SelectedItem in ScrollView, because Xamarin Foms has Bindable Layouts that contains ItemsSource and ItemTemplateSelector .
Bindable layouts enable any layout class that derives from the Layout class to generate its content by binding to a collection of items, with the option to set the appearance of each item with a DataTemplate. Bindable layouts are provided by the BindableLayout class, which exposes the following attached properties:
ItemsSource – specifies the collection of IEnumerable items to be displayed by the layout.
ItemTemplate – specifies the DataTemplate to apply to each item in the collection of items displayed by the layout.
ItemTemplateSelector – specifies the DataTemplateSelector that will be used to choose a DataTemplate for an item at runtime.
If you need to use ScrollView, sample code as follows:
<ScrollView>
<StackLayout BindableLayout.ItemsSource="{Binding User.TopFollowers}"
Orientation="Horizontal"
...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:CircleImage Source="{Binding}"
Aspect="AspectFill"
WidthRequest="44"
HeightRequest="44"
... />
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>

WPF Using of Frame

While I'm using frame in Mainwindow , initially i hide an item in Mainwindows.
When i pressed a button in frame Page1 , I want to make item in mainwindow as visible.But i can't do it.I tried to updatelayout() , refresh() functions but anything is changed.Anyone has a knowledge about this??
This code is in MainWindow
private void Window_Loaded(object sender, RoutedEventArgs e)
{
müsteributton.IsEnabled = false;
string yer = "Pages/kullanicigiris.xaml";
frame1.Source = new Uri(yer, UriKind.Relative);
frame1.Margin = new Thickness(-175, 0, 0, 0);
}
This code is in kullanicigiris page
private void Dispatcher_Tick(object sender, EventArgs e)
{
i++;
if (i == 2)
{
dispatcher.Stop();
frm1 = new MainWindow();
frm1.frame1 = null;
DependencyObject currParent = VisualTreeHelper.GetParent(this);
while (currParent != null && frm1.frame1 == null)
{
frm1.frame1 = currParent as Frame;
currParent = VisualTreeHelper.GetParent(currParent);
}
// Change the page of the frame.
if (frm1.frame1 != null)
{
frm1.frame1.Source = new Uri("Window1.xaml", UriKind.Relative);
frm1.müsteributton.IsEnabled = true;
}
}
}
Thanks.
You can define a DependencyProperty in the MainWindows.
<TextBlock x:Name="textBlock" Height="399" TextWrapping="Wrap" Text="Show/ Hide" VerticalAlignment="Top" Visibility="{Binding SetVisibility, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
public static readonly DependencyProperty SetVisibilityProperty =
DependencyProperty.Register("SetVisibility", typeof(Visibility), typeof(Mainfreampage), new
PropertyMetadata(Visibility.Visible, null));
public Visibility SetVisibility
{
get { return (Visibility)GetValue(SetVisibilityProperty); }
set { SetValue(SetVisibilityProperty, value); }
}
In your page click event, you can use the following code find the MainWindows and change the DependencyProperty value.
var mw = Application.Current.Windows
.Cast<Mainfreampage>()
.FirstOrDefault(window => window is Mainfreampage) as Mainfreampage;
mw.SetVisibility = Visibility.Hidden;
Your bug is here:
frm1 = new MainWindow();
You are creating a brand new window, and then making your changes in that window.
But: that's not the window the user's looking at!
Taking the approach you've embarked on, your frame code needs to keep track of the Window object it's actually being hosted in, and then use that reference for dealing with the update.
That said, that entire approach is flawed. The navigation should be modeled in a view model data structure, activated via an ICommand object, and optionally via timer (as you seem to be doing here). Frame source and button state can be manipulated through bindings to properties in your view model data structure.
But, at the end of the day, the code you've got should work fine, once you start using the correct Window object.

Windows phone user control change pivot selecteditem

I created my own UserControl, I added Button to it. Also I have Pivot where I added this UserControl. How can I change Pivot selecteditem in Button_Click event in my UserControl.
Binding:
Binding binding = new Binding("SelectedIndex");
binding.Source = historyControls[i].SelectedIndex;
Pivot_Second.SetBinding(Pivot.SelectedIndexProperty, binding);
void Button_Click()
{
SelectedIndex = desiredindex;
}
Make a property
private int _SelectedIndex;
public int SelectedIndex
{
get
{
return _SelectedIndex;
}
set
{
_SelectedIndex = value;
RaisedPropertyChanged("SelectedIndex");
}
}
then bind this property with selected index of your pivot.
I hope it will work.

How to Find the object of The ListItem in ListBox in Windows Phone7

I have a ListBox, here i am binding IList Like (Cities).
I want an event like OnItemDataBound in .NET in Windows Phone7.
Like when every city was binded (if 10 cities are this event will fire 10 times) this event will fire so that i have to do some more calculations on this event. In this event i have to find the object binded to the ListItem so that i can make some calculations. Is there any event in WP7 similar OnItemDataBound in .NET.
<ListBox Loaded="lstFlights_Loaded" Height="635" x:Name="lstFlights"
ScrollViewer.VerticalScrollBarVisibility="Auto" Grid.Row="1">
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="10" Margin="10">
<Border.Background>
<ImageBrush ImageSource="../Images/rowbg.png"></ImageBrush>
</Border.Background>
//Some data here
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
i am binding the data like below:
lstFlights.ItemsSource = objCities;
on Binding every city i want an event to populate some list items(like: i want to change the textblock text,etc) according to the City that binded to ListItem. To do this I need an event like OnItemDataBound in WP7. And I have list picker like below:
On SelectionChanged event also i want to change the list items.
And one more thing IList(objCities) is coming from the Service so I can't change that Object
so if i want to change any TextBlock in List Box i have do FindName and i have to assign calculated value for every city binded.
There is an CollectionChanged event in ObservableCollection collection for new elements added/removed.
ListBox provides some methods for accessing ListBoxItem. You can see them in list.ItemContainerGenerator class.
You can use it together to achieve needed results.
There is short example that shows how to make a red foreground to newly added items in some conditions (even or not):
ObservableCollection<string> items = new ObservableCollection<string>();
public MainPage()
{
InitializeComponent();
items.CollectionChanged += (s, e) =>
{
Dispatcher.BeginInvoke(() =>
{
if (e.NewItems != null)
{
foreach (var item in e.NewItems)
{
ListBoxItem listitem = (ListBoxItem)list.ItemContainerGenerator.ContainerFromItem(item);
if (DateTime.Parse(listitem.Content.ToString()).Second % 2 == 0)
{
listitem.Foreground = new SolidColorBrush(Color.FromArgb(255, 255, 0, 0));
}
}
}
});
};
list.ItemsSource = items;
}
private void AddButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
items.Add(DateTime.Now.ToLongTimeString());
}
private void RemoveButton_Click(object sender, System.Windows.RoutedEventArgs e)
{
Random rnd = new Random();
if (items.Count > 0)
{
int index = rnd.Next(0, items.Count);
items.RemoveAt(index);
}
}
}
How about using the ItemsChanged event of your ListBox's ItemContainerGenerator instead?
this.myListBox.ItemContainerGenerator.ItemsChanged += new System.Windows.Controls.Primitives.ItemsChangedEventHandler(ItemContainerGenerator_ItemsChanged);
void ItemContainerGenerator_ItemsChanged(object sender, System.Windows.Controls.Primitives.ItemsChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add)
...

how to access a ListBox inside a Pivot in windows phone 7?

i have a a Pivot that has a ListBox defined as its Pivot.ItemTemplate as the following.
<controls:Pivot x:Name="pivot">
<controls:Pivot.ItemTemplate>
<DataTemplate>
<ListBox x:Name="listBox">
...
</ListBox>
</DataTemplate>
</controls:Pivot.ItemTemplate>
</controls:Pivot>
how do i programmatically access the corresponding ListBox control corresponding to the Pivot.SelectedItem or Pivot.SelectedIndex?
i tried something similar to this link http://www.windowsphonegeek.com/tips/how-to-access-a-control-placed-inside-listbox-itemtemplate-in-wp7.
var count = VisualTreeHelper.GetChildrenCount(pivotItem);
for(int i=0; i < count; i++) {
var child = VisualTreeHelper.GetChild(pivotItem, i);
if(child is ListBox) {
//do something
} else {
Debug.WriteLine(child.GetType());
}
}
for some reason, i get System.Windows.Controls.Grid on the Debug.WriteLine.
the reason why i need to get a handle or access the ListBox inside the Pivot (that is currently on display/selected), is because i need to reset its view (scroll it back to the top). the ListBox is data bound to ObservableCollection, and when i update the collection, the scroll position needs to be placed back to the top; otherwise, everything works (data binding/visual display), except now the view is stuck in the middle or where the user currently is. if there's an easier way to do this without getting a handle on the ListBox, i'm open to that solution as well.
just in case anyone is interested, i tinkered and came up with something that works specifically for my case. the code is below. basically, i had to get the PivotItem first.
PivotItem pivotItem = pivot.ItemContainerGenerator.ContainerFromItem(myObject) as PivotItem;
i then created a local variable to store the ListBox (if it's found) and recursed the tree view model.
ListBox listBox = null;
Recurse(pivotItem, ref listBox);
and my Recurse function looks like the following.
private void Recurse(DependencyObject obj, ref ListBox listBox) {
if(obj is ListBox) {
listBox = obj as ListBox;
return;
}
var count = VisualTreeHelper.GetChildrenCount(obj);
for(int i=0; i < count; i++) {
var child = VisualTreeHelper.GetChild(obj, i);
Recurse(child, ref listBox);
}
}
try:
(Listbox)VisualTreeHelper.GetChild((pivot.SelectedItem as PivotItem), 0);
Looks like this was a while back, but this is what worked for me:
First get the PivotItem:
PivotItem pivotItem = Pivot.ItemContainerGenerator.ContainerFromItem(Pivot.SelectedItem) as PivotItem;
Then get the first child, a ListBox, from the PivotItem:
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject {
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++) {
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T) {
return (T)child;
} else {
var result = FindFirstElementInVisualTree<T>(child);
if (result != null)
return result;
}
}
return null;
}
Then call:
ListBox listBox = FindFirstElementInVisualTree<ListBox>(pivotItem);
use StackPanel inside your ListBox
this link may help you
http://blogs.msdn.com/b/oren/archive/2010/11/08/wp7-silverlight-perf-demo-1-virtualizingstackpanel-vs-stackpanel-as-a-listbox-itemspanel.aspx

Resources