I have listbox with items from observablecollection.
<ListBox Name="listBoxData"
DataContext="{Binding Source={StaticResource MainWindowViewModelDataSource}}"
ItemTemplate="{DynamicResource BookTemplate}"
ItemsSource="{Binding Books, UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedBook, Mode=TwoWay}">
Question is how to wire double click action on selected item?
I do not avoid code behind approach (which is currently empty, all my logic is inside mvvm).
Your final line is a little confusing... to me, it says 'a code behind solution is ok', but then you mention MVVM, so I'm not sure. Either way, here is a simple answer for you. Declare the ListBox:
<ListBox SelectionChanged="ListBox_SelectionChanged" />
And then in the code behind, assuming single selection mode:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBoxItem listBoxItem = (ListBoxItem)e.AddedItems[0];
listBoxItem.PreviewMouseDoubleClick += ListBoxItem_PreviewMouseDoubleClick;
listBoxItem = (ListBoxItem)e.RemovedItems[0];
listBoxItem.PreviewMouseDoubleClick -= ListBoxItem_PreviewMouseDoubleClick;
}
private void ListBoxItem_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
// Selected item was double clicked
}
If you want the MVVM way, then you can just move the code from the ListBox_SelectionChanged handler to the SelectedBook setter and the ListBoxItem_PreviewMouseDoubleClick handler to the view model. However, it's not such a good idea handling UI events in the view model. It's better to use Attached Properties to handle them for you, but that's another story.
Related
I have following ListView
<ListView Name="listAccounts" Width="300" AllowDrop="True" SelectionMode="Single" CanDragItems="True" CanDrag="True" CanReorderItems="True" Background="{ThemeResource myBackground}" DragItemsStarting="listAccounts_DragItemsStarting" Drop="listAccounts_Drop">
and defined my event handlers as
private void listAccounts_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
e.Data.SetData("itemIndex", (e.Items[0] as AccountList).Text.ToString());
}
private async void listAccounts_Drop(object sender, DragEventArgs e)
{
string itemIndexString = await e.Data.GetView().GetTextAsync("itemIndex");
}
I don't know what else I can do. I want to realize the movement of the list items in the same list.
I went over to the official Windows 10 samples, looked for the drag-drop sample and trimmed it down (like removing the drag from target to source). Turns out you don't even have to handle any events to make re-ordering in a single ListView work.
<ListView x:Name="TargetListView"
Grid.Row="2" Grid.Column="1" Margin="8,4"
CanReorderItems="True" CanDrag="True" AllowDrop="True"
/>
Check your ObservableCollection after reordering items and you'll notice it's correct. If you want to track the re-ordering, you'll have to check the CollectionChanged event on your ObservableCollection, as there is no event on the ListView to do this.
If you want to support drag & drop accross multilple listviews, I'd say have another look at the sample.
When I tab into a ListBox control, the first item gets focused. When I have a label and set the target property to the ListBox (as shown in the code below) and then use the dedicated Alt shortcut then it will focus not the first item but the listbox itself (listbox border becomes dotted). What is the best way to avoid this unwanted behavior? Is there a way to disable focusing on the listbox itself and only allow focusing on the items?
Example code:
<Label Content="_Label" Margin="0,10,0,88" Name="MyLabel" Target="{Binding ElementName=MyListBox}" Height="Auto" />
<ListBox Width="100" Name="MyListBox" Margin="46,0,639,0" />
Behavior:
By setting Target you explicitly asked focus to move to listBox. In case you want to put it on first listBox item, you have to do it manually.
One way would be to hook GotFocus event and set focus to next available item using TravelRequest object which wil put it on first listBox item.
XAML:
<ListBox Width="100" Name="MyListBox" Margin="46,0,639,0"
GotFocus="MyListBox_GotFocus"/>
Code behind:
private void MyListBox_GotFocus(object sender, RoutedEventArgs e)
{
if (e.OriginalSource == sender)
{
TraversalRequest request = new TraversalRequest(FocusNavigationDirection.Next);
MyListBox.MoveFocus(request);
}
}
I want to populate a listbox after inputting text into a text box and clicking Submit. Seems simple I know, but I'm new to Data Binding and WPF...
Here's my code so far... I don't know if the XAML is correct, and of course I have nothing in the event code behind... any help would be appreciated.
XAML:
<ListBox ItemsSource="{Binding ElementName=accountaddTextBox, Path=SelectedItem.Content, Mode=OneWay, UpdateSourceTrigger=Explicit}" Height="164" HorizontalAlignment="Left" Margin="12" Name="accountListBox" VerticalAlignment="Top" Width="161" />
Code behind:
private void okBtn_Click(object sender, RoutedEventArgs e)
{
}
Your current binding is telling the ListBox to find an object named accountaddTextBox, and bind to its SelectedItem.Content. I am assuming that accountaddTextBox is a TextBox, and SelectedItem is not a valid property on TextBox, so your binding is invalid.
It would be far better to bind your ListBox to an ObservableCollection<string> that is located in your code-behind or ViewModel, and have your button add a new object to that collection. Since it is an ObservableCollection, the UI will automatically update
For example,
<ListBox ItemsSource="{Binding SomeObservableCollection}" />
private void okBtn_Click(object sender, RoutedEventArgs e)
{
SomeObservableCollection.Add(accountaddTextBox.Text);
}
In my WP7 application I have ListBox control that binds with List<ItemTemplate> collection. On each ListBoxItem I have Click event which navigates to DisplayItem.xaml. Each ItemTemplate object has Id property which has to be passed to DispalyItem.xaml. I know that I can pass this value from Click EventHandler to DisplayItem.xaml using QueryString but how do I pass it from ListBox item to EventHandler ?
<ListBox x:Name="listBoxItems">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Ellipse Fill="red" Width="30" Height="30"></Ellipse>
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding Status}" FontSize="35" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<HyperlinkButton Content="{Binding ItemContent}" Name="itemButton" Click="itemButton_Click"/>
</StackPanel>
<toolkit:ContextMenuService.ContextMenu>
<toolkit:ContextMenu>
<toolkit:MenuItem Header="edit"/>
<toolkit:MenuItem Header="delete"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Id property is not mentioned in the above code because I just simply didnt know where to place it. Generally I want to know how can I get Id property back to the click EventHandler ? I'm sorry if this question is basic for you but I'm new to that and i wasn't sure how to google that.
If you're really new to Windows Phone 7, you may want to stop using the "Click" event and instead use the ListBox.SelectionChanged event. If you are bound to List<MyObject>, you could do the following:
In your XAML:
<ListBox SelectionChanged="NavigateToMyDetail" ... >
Then in the code behind, you would have something like this:
private void NavigateToMyDetail(object sender, SelectionChangedEventArgs e)
{
// Make sure that the ListBox change wasn't due to a deselection
if(e.AddedItems != null && e.AddedItems.Count == 1)
{
MyObject selectedItem = (MyObject)e.AddedItems[0];
// Now you have access to all your MyObject properties
// and you can pass that to your new page as a parameter
NavigationService.Navigate(new Uri("DisplayItem.xaml?ItemID=" + selectedItem.id.ToString(), UriKind.Relative));
}
}
And you can get that ID with the following code (probably in your "OnNavigatedTo" method).
string myItemID = null;
if(this.NavigationContext.QueryString.ContainsKey("ItemID"))
myItemID = NavigationContext.QueryString["ItemID"];
Hope that helps. The other way to try to get it is to give your ListBox a x:Name and then references it in your Click handler like:
private void MyClickHandler(object sender, System.Windows.RoutedEventArgs e)
{
MyObject selectedObject = (MyObject)MyListBoxName.SelectedItem;
}
There is a much simpler solution if you use data binding with an MVVM viewmodel behind it.
Simply bind you view to a property in the view model for the listbox "Source" and then also do the same for the ListBox "SelectedItem" or "SelectedIndex" properties, then you will have all you need accessible where ever you needed.
Only think to be aware of (as I'm uncertain if it ever got fixed) is to fixed the selected index property when an item has been selected, if you do not reset it to -1 then if the user returns to the list they cannot select the same item. (do this in the codebehind for the click event)
Also if you use MVVM and databinding you can enact an action from the change of the Selected item rather than using Code behind to drive the direction, always an option to keep things simple (but not mandatory)
I have also came to my own solution. I'm not sure If its correct bit its certainly solving my problem for now.
I found this CommandParameter property of object HyperlinkButton. I bound my MyObject.Id property value to it.
<HyperlinkButton Content="{Binding ItemContent}" Click="itemButton_Click" CommandParameter="{Binding Id}" />
Then in my EventHandler i said:
private void itemButton_Click(object sender, RoutedEventArgs e)
{
HyperlinkButton butt = sender as HyperlinkButton;
NavigationService.Navigate(new Uri("/ViewItem.xaml?itemId=" + butt.CommandParameter.ToString(), UriKind.Relative));
}
It works as I need it to work but I'm not sure If i should use it in my applications in the future.
This is my XAML code:
<ListBox ItemsSource="{Binding}" Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Width="370">
<TextBlock Text="{Binding AuthorName}" x:Name="author" MouseEventLeftDown="click"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And the Click Handler
private void click(object sender, RoutedEventArgs e)
{
if(author.Text.Equals("Hi"))
{
// Do Something Special
}
}
The error is:
Error: The name 'author' does not exist in the current context
But I don't understand what is causing this error or why it is occurring.
Your TextBlock with the Name author doesn't exist in the scope of your click handler because it's in a DataTemplate. What's happening is that the author TextBlock is created once for every one of your data items (Presumably an Author class or a Book class of some kind), so you literally can have dozens of controls named author.
You are better off casting your sender in your click handler to a text box and then checking its text property. Something like this:
private void click(object sender, RoutedEventArgs args)
{
var textBox = sender as TextBox;
if(textBox == null)
return;
if(textBox.Text.Equals("hi"))
{
// Do Something Crazy!
}
}
It's probably better to use a UI element designed for touch, such as a HyperlinkButton or a Button. You can style these any way you would like to - especially if you use Expression Blend - but it is good design to include some visual feedback about the Touch.
Also - I'm not sure about your == code - you're comparing the sender (a UI element) against some string expression?
First off, your TextBlock is defined in a DataTemplate; try x:Name instead of Name on your TextBlock.
Secondly it might be quite tricky to click your TextBlock since you will have to press an exact pixel in your TextBlock. To make it easier to click your TextBlock you might want to put a Background on your TextBlock, so it will be a lot easier to click. You can even make the background transparent:
Background="Transparent"
use the gesture listener for create an event handler like "tap" or double" or whatever.
Use this...
private void click(object sender, RoutedEventArgs e)
{
var author = (TextBlock)sender;
if (author.Text.Equals("Hi"))
{
// Do Something Special
}
}