Silverlight 4 and LisBox's SelectedItem when using DataTemplate as ItemTemplate - silverlight

I'm using tow listboxes for drag n drop where user can drag items from source listbox and drop on the target. I'm using a DataTemplate for the ListBoxItems of my ListBox Controls.
I need to give the user ability to move up/down items in the target listbox after they been moved from source. I have two button "Move Up" & "Move Down" to do that but when the user clicks on one of the button, it returns me the null object as selectedItem.
here is my code
private void moveUp_Click(object sender, RoutedEventArgs e)
{
ListBoxItem selectedItem = lstmenuItems.SelectedItem as ListBoxItem;
if (selectedItem != null)
{
int index = lstmenuItems.Items.IndexOf(selectedItem);
if (index != 0)
{
lstmenuItems.Items.RemoveAt(index);
index -= 1;
lstmenuItems.Items.Insert(index, selectedItem);
lstmenuItems.SelectedIndex = index;
}
}
}
I'm sure its to do with the ItemTemplate. here is the xaml for listbox
<ListBox x:Name="lstmenuItems" Height="300" MinWidth="200" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Code}"/>
<TextBlock Text="{Binding RetailPrice, StringFormat=£\{0:n\}}" />
</StackPanel>
<!-- Product Title-->
<TextBlock Text="{Binding Description1}" Width="100" Margin="2" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
Any ideas how can I access the selected Item and how can I move it up/down?
Thanks in advance

The selectedItem variable will contain a null because the SelectedItem property doesn't return the type ListBoxItem. The SelectedItem property returns an object it received from the collection supply its ItemsSource property.
Change to :-
object selectedItem = lstmenuItems.SelectedItem;
and that should get you a little further.
That said consider having the ItemsSource bound to an ObservableCollection and manipulate the collection instead.

Related

how to remove custome items from observablecollection in silverlight

i binded one observable cllection to one listbox in silverlight.when i click one item in listbox and click delete button ,how to remove that particular item remove from the listbox without linq using mvvm.i passed commandparameter of the button is listbox itemid.
<ListBox ItemsSource="{Binding School1,Mode=TwoWay}" DisplayMemberPath="SchoolName" Name="listBox1" >
<Button Content="Delete" Command="{Binding deletecommand}" CommandParameter="{Binding Path=SelectedItem.ID,ElementName=listBox1}" Name="button2" />
so what is the code for remove particular item from observable collection
public void delete(object parameter)
{
School1.Remove(...)
}
Bind the ListBox's SelectedItem to a property and use that in your Remove():
<ListBox ItemsSource="{Binding School1, Mode=TwoWay}"
DisplayMemberPath="SchoolName"
SelectedItem={Binding SelectedSchool}
Name="listBox1"
/>
public void delete(object parameter)
{
if (SelectedSchool != null)
School1.Remove(SelectedSchool);
}
Also note that your question is somewhat of a duplicate: Clearing selecteditem of listbox (which is bound to collection of objects) with MVVM

WPF: weird problem in dataBinding with TabControl

I'm trying to use DataBinding for dynamically populating a TabControl but have a problem. dataBinding runs fine but I would like the content of each TabItem to be independent one from the other. Here is my XAML code:
<TabControl
DockPanel.Dock="Left"
ItemsSource="{Binding OpenChats}"
Name="tabChats"
VerticalAlignment="Top"
Width="571">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding Name}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBox />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
TabItems are created with different headers (as I want) but when the user types something in the TextBox inside the ContentTemplate, the same text is maintained in different tabItems and I don't want this.
What am I doing wrong?
I had same problem. This answer helped me. My solution was to remove focus from textbox when tab changed. When focus from textbox is removed, new content is set to binded property as expected.
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DependencyObject focusedElement = (FocusManager.GetFocusedElement(tabControl) as DependencyObject);
if (focusedElement != null)
{
DependencyObject ancestor = VisualTreeHelper.GetParent(focusedElement);
while (ancestor != null)
{
var element = ancestor as UIElement;
if (element != null && element.Focusable)
{
element.Focus();
break;
}
ancestor = VisualTreeHelper.GetParent(ancestor);
}
}
}
or use
Text="{Binding UpdateSourceTrigger=PropertyChanged}"
on textbox binding.
The TextBox in the ContentTemplate has no Binding. Try
<TabControl.ContentTemplate>
<DataTemplate>
<TextBox Text="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
Adjust the bindingpath if necessary

WPF Scroll & focus changing problem

I am having a problem with scrolling for my WPF application.
Here is the deal. My UI is the following:
The role of my application is to act as a central hub for many applications and launch them. An admin can launch a dump recorded by another user.
Therefore, I have a ListView, showing the application list, which is scrollable if needed.
I defined a GroupStyle in order to show expanders and emulate a Windows Explorer view.
Everything works fine, I just have a problem: when scrolling with the mouse wheel, the component in clear blue ("Launch mode") seems to be catching the focus and stop scrolling.
This means especially that if my mouse is anywhere out of this control, the scrolling is okay. But whenever the mouse enters this control, I can't scroll anymore.
I tried to modify the property Focusable and set it to False everywhere I could but nothing changed. I'd guess that it is finally not a focus problem.
Anybody has an idea on how to avoid the scrolling to be caught by the element?
Here is some (simplified, removed some useless properties so as to make it as clear as possible) XAML for the expander's content:
<StackPanel Orientation="Vertical" VerticalAlignment="Top" >
<ToggleButton>
<!-- ToggleButton Content... -->
</ToggleButton>
<!-- This is the custom component in which you can see "Launch mode" -->
<my:UcReleaseChooser >
<!-- Properties there. I tried to set Focusable to False, no impact... -->
</my:UcReleaseChooser>
</StackPanel>
And the code for UcReleaseChooser:
<StackPanel HorizontalAlignment="Stretch"
Focusable="False" ScrollViewer.CanContentScroll="False">
<ListBox ItemsSource="{Binding ListChosenReleases}" BorderBrush="LightGray" Background="AliceBlue"
HorizontalAlignment="Stretch" Focusable="False" ScrollViewer.CanContentScroll="False">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"
Focusable="False" ScrollViewer.CanContentScroll="False"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<DockPanel LastChildFill="True" HorizontalAlignment="Stretch"
Focusable="False" ScrollViewer.CanContentScroll="False">
<TextBlock DockPanel.Dock="Top"
HorizontalAlignment="Left" Text="{Binding Key}"
FontStyle="Italic"/>
<ListBox DockPanel.Dock="Bottom"
HorizontalAlignment="Right" ItemsSource="{Binding Value}"
BorderBrush="{x:Null}" Background="AliceBlue"
Focusable="False" ScrollViewer.CanContentScroll="False">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Focusable="False"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<-- Blah blah about style -->
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding Key}" Margin="3"
IsChecked="{Binding Path=IsSelected, Mode=TwoWay,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListBoxItem}}}"
Focusable="False" ScrollViewer.CanContentScroll="False"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
As you can see, the UcReleaseChooser contains a list of RadioButton lists. I tried to set Focusable & CanContentScroll to False everywhere it seemed appropriate, but the control keeps preventing the main UI to scroll...
I guess I should change another property... Any idea?
Thanks!
The problem is the ListBox, or more specifically, the ScrollViewer within the ListBox's template. This is getting your scroll events and consuming them before the outer ScrollViewer in the ListView even sees them.
I would advise replacing the ListBox with an ItemsControl if possible. However, that implies there will be no SelectedItem property. If you need that, I would suggest setting ScrollViewer.HorizontalScrollBarVisibility (or VerticalScrollBarVisibility) to Disabled. Failing that, I can only suggest re-templating ListBox to not contain a ScrollViewer at all.
I had an issue with a listbox stealing focus inside a scrollviewer (I have multiple listboxes inside the scrollviewer). So I created an attached property which denies the listbox the ability to scroll. So therefore the scrollviewer which is housing the listbox can scroll
Your control is a listbox, so this should work as is, but there is no reason the Extension should be limited to a Listbox; it just is to match my exact purpose.
public static class ListboxExtensions
{
public static DependencyProperty IgnoreScrollProperty = DependencyProperty.RegisterAttached("IgnoreScroll", typeof(bool), typeof(ListboxExtensions), new UIPropertyMetadata(false, IgnoreScrollChanged));
public static bool GetIgnoreScroll(DependencyObject dependencyObject)
{
return (bool)dependencyObject.GetValue(IgnoreScrollProperty);
}
public static void SetIgnoreScroll(DependencyObject dependencyObject, bool value)
{
dependencyObject.SetValue(IgnoreScrollProperty, value);
}
private static void IgnoreScrollChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var newValue = (bool)e.NewValue;
var oldValue = (bool)e.OldValue;
var frameworkElement = d as FrameworkElement;
if (frameworkElement == null) return;
if (!newValue || oldValue || frameworkElement.IsFocused) return;
var lb = frameworkElement as ListBox;
if (lb == null) return;
lb.PreviewMouseWheel += LbOnPreviewMouseWheel;
}
private static void LbOnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (!(sender is ListBox) || e.Handled) return;
e.Handled = true;
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent,
Source = sender
};
var parent = ((Control)sender).Parent as UIElement;
if (parent != null) parent.RaiseEvent(eventArg);
}
}
And then in your XAML, you just put this on the listbox:
<ListBox extensions:ListboxExtensions.IgnoreScroll="True">
Of course, remembering to include the namespace to your extensions in the top of the XAML:
xmlns:extensions="clr-namespace:UI.Extensions"

Binding a listbox SelectedItem to an Observable Collection?

I have a Listbox in WPF with the SelectionMode set to Multiple, and can multiselect the items in the Listbox. However, the SelectedItem is not updating the Observable Collection it is bound to.
Is there a way to bind the multiple selected items from a ListBox to an Observable Collection?
i dont know mvvm way of doing this,
i have a working solution comibined of mvvm & codebehind.
CodeBehind
private void lstbox_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
var listBox = sender as ListBox;
if (listBox == null) return;
var viewModel = listBox.DataContext as Window1ViewModel;
if (viewModel == null) return;
viewModel.ListOfSelectedItems.Clear();
foreach (Window1ViewModel.States item in listBox.SelectedItems)
{
viewModel.ListOfSelectedItems.Add(item);
}
}
ViewModel
private ObservableCollection<States> _listofselecteditems;
public ObservableCollection<States> ListOfSelectedItems
{
get
{
return _listofselecteditems;
}
set
{
_listofselecteditems = value;
RaisePropertyChanged(() => ListOfSelectedItems);
}
}
Xaml
<ListBox x:Name="lstbox"
SelectionChanged="lstbox_SelectionChanged_1"
ItemsSource="{Binding StatesList,Mode=TwoWay}"
SelectionMode="Multiple" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox
IsChecked="{Binding Path=IsSelected,Mode=TwoWay}"
Content="{Binding StateName}" />
<TextBox Margin="8,0,0,0" Text="{Binding SOmeProperty}" IsEnabled="{Binding Path=IsSelected}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>

Focus DataTemplate in WPF

The behaviour I am looking for is that a selection of a Item in a ListView results in focusing the first focusable visualchild.
Problem: datatemplated data in a ItemsControler which does not get an initial focus.
In the example below there are 4 Strings which are then stuffed into a TextBox via Datatemplate.
Example:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ListView>
<ListView.Resources>
<DataTemplate DataType="{x:Type sys:String}" >
<TextBox Width="100" Text="{Binding Mode=OneWay}"/>
</DataTemplate>
</ListView.Resources>
<ListView.ItemsSource>
<x:Array Type="{x:Type sys:String}">
<sys:String>test</sys:String>
<sys:String>test</sys:String>
<sys:String>test</sys:String>
<sys:String>test</sys:String>
</x:Array>
</ListView.ItemsSource>
</ListView>
</Grid>
</Window>
I already tried some combinations of
FocusManager.FocusedElement="{Binding ElementName=[...]}"
pointless to say: without success.
Anyone a clou how I could get what I want without traversing the visual tree in c#?
It should be possible to do this, shouldn't it?
The FocusManager works sweet for this.
<DataTemplate x:Key="MyDataTemplate" DataType="ListBoxItem">
<Grid>
<WrapPanel Orientation="Horizontal" FocusManager.FocusedElement="{Binding ElementName=tbText}">
<CheckBox IsChecked="{Binding Path=Completed}" Margin="5" />
<Button Style="{StaticResource ResourceKey=DeleteButtonTemplate}" Margin="5" Click="btnDeleteItem_Click" />
<TextBox Name="tbText"
Text="{Binding Path=Text}"
Width="200"
TextWrapping="Wrap"
AcceptsReturn="True"
Margin="5"
Focusable="True"/>
<DatePicker Text="{Binding Path=Date}" Margin="5"/>
</WrapPanel>
</Grid>
</DataTemplate>
Using the binding syntax in C# will not work, because that is how bindings are described in XAML. It might work to create a new instance of System.Windows.Data.Binding, and set its properties to the equivalent of what you would set in XAML, but I'm not sure what ElementName that you would be able to bind to in order to get this working correctly.
The only other option that I can think of is to add a handler for the SelectionChanged event, and set the focus manually, but that doesn't sound like the solution that you want.
Upon further inspection, I don't think that a Binding solution is possible. FocusManager.FocusedElement is an IInputElement, which doesn't have any members related to binding. I think that you need to traverse the visual tree in order to find the first object that is focusable. Something like this should work:
// Event handler for the ListBox.SelectionChanged event
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListBox listBox = sender as ListBox;
ItemContainerGenerator = generator.listBox.ItemContainerGenerator;
ListBoxItem selectedItem =
(ListBoxItem)generator.ContainerFromIndex(listBox.SelectedIndex);
IInputElement firstFocusable = FindFirstFocusableElement(selectedItem);
firstFocusable.Focus();
}
private IInputElement FindFirstFocusableElement(DependencyObject obj)
{
IInputElement firstFocusable = null;
int count = VisualTreeHelper.GetChildrenCount(obj);
for(int i = 0; i < count && null == firstFocusable; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
IInputElement inputElement = child as IInputElement;
if(null != inputElement && inputElement.Focusable)
{
firstFocusable = inputElement;
}
else
{
firstFocusable = FindFirstFocusableElement(child);
}
}
return firstFocusable;
}

Resources