I have a Window with ListBox on the left Side and TextBox on the right Side. The Textbox is binding to the Selected Item of the ListBox. The Textbox has a SaveContentCommand.
If you leave the Textbox with Enter or the Tab the SaveContentCommand is executed correct. But if i use the mouse to select something else the selecteditem is changed and then the SaveContentCommand is executed. This means the SaveContentCommand is used on another item.
I have tried to hack something like RenameLastSelectedItem()
But is there a correct/better way?
My List:
<customControls:MyListBox x:Name="UserListBox"
Grid.Row="1"
Grid.Column="0"
ItemsSource="{Binding Users}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Top"
Style="{DynamicResource MyListBoxStyle}"
ItemContainerStyle="{DynamicResource MyListBoxItemUserListStyle}">
My TextBox:
<customControls:MyTextBox x:Uid="textBoxName"
x:Name="textBoxNameOfSelectedItems"
Text="{Binding SelectedItem.Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=true, Mode=TwoWay}"
focus:FocusExtension.IsFocused="{Binding SelectedItem.IsNameFocused, Mode=TwoWay}"
focus:FocusExtension.EnableSelection="True"
UseKeyboardBinding="true"
Style="{DynamicResource MyTextBoxStyle}"
SaveContentCommand="{Binding SelectedItem.UpdateCommand}"
In the set method of the SelectedItem, save the previous item. This code will run when the selected item is changed when selecting a new item with the mouse..
SelectedItem
{get { return _selectedItem;}
set
{
//null check
SaveContent(_selectedItem);
_selectedItem = value;
}
}
Related
My problem is that after I select a item in the ComboBox, the first item or "default" item of the combobox stays empty but if I click the combobox the values beneath show up are selectable etc. but I want the clicked one to show in the "default/first" place.
What I tried so far
XAML:
<ComboBox Margin="55,0,0,10" Height="20" Width="145" VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding TabItems, Source={StaticResource MainWindowViewModelRefactored}, Mode=TwoWay}"
SelectedItem="{Binding SelectedItem, Source={StaticResource MainWindowViewModelRefactored}, Mode=TwoWay}"
DisplayMemberPath="Header">
</ComboBox>
Property:
public TabItem SelectedItem {
get {
return _selectedItem;
}
set {
UpdateTCVCollection(value);
_selectedItem = value;
NotifyPropertyChanged("SelectedItem");
}
}
If I open up the combobox the selecteditem is highlighted, but I also want it to be shown in the "first place" when the ComboBox is closed.
You can add a method when the index has changed, then remove the item that the user selected and add it at the begining.
I've set the value of Sorted to false because that way the value you selected won't be reorganized in your ComboBox.
private void ComboBox1_SelectedIndexChanged(object sender, EventArgs e) {
RadItem selectedItem = ComboBox1.SelectedItem as RadItem;
if (selectedItem != null) {
ComboBox1.Items.Remove(selectedItem);
ComboBox1.Items.Sorted = true;
ComboBox1.Items.Sorted = false;
ComboBox1.Items.Insert(0, selectedItem);
ComboBox1.Text = selectedItem.Text;
}
}
Add the UpdateSourceTrigger to your Combobox.
UpdateSourceTrigger=PropertyChanged
Example:
<ComboBox Margin="55,0,0,10" Height="20" Width="145" VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding TabItems, Source={StaticResource MainWindowViewModelRefactored}, Mode=TwoWay}"
SelectedItem="{Binding SelectedItem, Source={StaticResource MainWindowViewModelRefactored}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Header">
</ComboBox>
Have a look to this MSDN link
That should help you with your problem.
Greetings
I have a listview in WPF in an MVVM/PRISM app which may contain 1-to-many elements. When the listview contains only 1 element, and I select it, I cannot subsequently reselect it even though I set the SelectedIndedx value to -1. Worse, if I make the app update the listview with a different single element, I can't select that one either. The only way I can achieve selection of an item when it is the only item in the listview is to make the app display multiple items and select something other than the first. Then, when I make the app display a listview containing a single item, I can select it again - but only once.
In those cases where I cannot select the single item in the listview, the servicing routine never fires.
I tried implementing a XAML suggestion I found here using "Listview.Container.Style" and the IsSelected property, but that did not work.
My listview is fairly straightforward:
<ListView Name="lstEditInstance"
Grid.Row="5"
ItemsSource="{Binding Path=InstanceList,Mode=TwoWay}"
Width="488"
FontFamily="Arial" FontSize="11"
HorizontalAlignment="Left" VerticalAlignment="Stretch"
Margin="10,96,0,28"
SelectedIndex="{Binding Path=InstanceSelectedIndex}">
</ListView>
The servicing routine is:
private void OnInstanceSelectedIndexChanged()
{
// Handle case where user hits Enter without making a selection:
if (_instanceIndex == -1) return;
// Get the instance record for the row the user clicked on as a
// ResourceInstance class named "InstanceRecord".
InstanceRecord = _instanceList[_instanceIndex];
_instanceNumber = InstanceRecord.Instance;
FormInstName = InstanceRecord.InstName;
FormInstEnabled = InstanceRecord.Enabled;
FormInstState = InstanceRecord.InitialState;
FormInstIPAddress = InstanceRecord.IPAddress;
FormInstPort = InstanceRecord.Port.ToString();
FormInstSelectedURL = InstanceRecord.UrlHandler;
} // End of "OnResourceSelectedIndexChanged" method.
"InstanceList" is an observable collection.
I'd appreciate some suggestions. Thanks in advance for any help.
In a MVVM scenario, I'd use a ViewModel that contains the selected item instead:
class MyViewModel {
private IList<Item> instanceList= new List<Item>();
public IList<Item> List
{
get {return list; }
set {
list = value;
RaisePropertyChanged(() => List);
}
}
private Item selectedItem;
public Item SelectedItem {
get {return selectedItem;}
set {
selectedItem = value;
RaisePropertyChanged(() => SelectedItem);
}
}}
And the XAML:
<ListView Name="lstEditInstance"
Grid.Row="5"
ItemsSource="{Binding Path=InstanceList}"
Width="488"
FontFamily="Arial" FontSize="11"
HorizontalAlignment="Left" VerticalAlignment="Stretch"
Margin="10,96,0,28"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}}">
Notice that observableCollection is not required unless you have to modify the list items, in the same way the binding should be the default one for the list.
The SelectedItem / SelectedIndex should be TwoWay or Onewaytosource, the latter if you think you don't need to change the selectedItem programmatically
The service routine should be called from the ViewModel
EDIT:
your code of the service routine should be placed there:
set {
selectedItem = value;
// your code
RaisePropertyChanged(() => SelectedItem);
}
Another valid approach is to use Blend on XAML, by invoking a command on changed index and process under the ViewModel.
To do this, first add reference to System.Windows.Interactivity in your project and in XAML add
xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity
Then modify ListView with the following:
<ListView Name="lstEditInstance"
Grid.Row="5"
ItemsSource="{Binding Path=InstanceList}"
Width="488"
FontFamily="Arial" FontSize="11"
HorizontalAlignment="Left" VerticalAlignment="Stretch"
Margin="10,96,0,28"
SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay}}">
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="SelectionChanged">
<interactivity:InvokeCommandAction Command="{Binding YourCommand}"
CommandParameter="{Binding YourCommandParameter}" />
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
I need the ComboBox below to keep the SelectedItem when I edit the text, at the moment as soon as I edit the text the SelectedItem turns null.
<ComboBox x:Name="FilterGroups"
IsEditable="True"
DisplayMemberPath="Code"
Text="{Binding FilterGroupCode}"
ItemsSource="{Binding FilterGroups}"
SelectedItem="{Binding SelectedFilterGroup}"
Margin="10,0"/>
My goal is to detect that the item has been edited, currently I have no idea which item was edited since the SelectedItem becomes null.
And a null SelectedItem to me at the moment means "New" item.
As AGH's Comment.
Xaml
<ComboBox x:Name="myFilterGroups"
ItemsSource="{Binding FilterGroups}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedFilterGroup}"
IsEditable="True" Height="20"
LostFocus="myFilterGroups_LostFocus"
>
</ComboBox>
Code Behind
private void myFilterGroups_LostFocus(object sender, RoutedEventArgs e)
{
var selItem = myFilterGroups.SelectedItem;
if (selItem == null)
// Create New Item
;
}
I have this List box and I want to search for its items which were selected (IsChecked=true) by user
<CheckBox Style="{StaticResource ResourceKey=CheckBoxes}"
Name="chkBoxSelectAllStaff" Content="Select All">
</CheckBox>
<ListBox Name="lstStaffs" MaxHeight="250" MinHeight="50" Margin="0,5,5,5" Width="350"
ScrollViewer.VerticalScrollBarVisibility="Auto" HorizontalAlignment="Right"
HorizontalContentAlignment="Right">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Style="{StaticResource ResourceKey=CheckBoxes}" IsChecked="{Binding ElementName=chkBoxSelectAllStaff, Mode=OneWay, Path=IsChecked}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" Margin="0,0,3,0"></TextBlock>
<TextBlock Text="{Binding LastName}" Margin="0,0,3,0"></TextBlock>
<TextBlock Text="{Binding CellphoneNumber}" Margin="0,0,3,0"></TextBlock>
</StackPanel>
</CheckBox>
</DataTemplate>
</ListBox.ItemTemplate>
I want to do something like this
foreach(var item in lstStaff.Items){
if((CheckBox) item).IsChecked){
//do something
}
}
And also I am binding the data this way :
//staff is my entity object containing Id, FirstName, LastName, CellphoneNumber
lstStaffs.ItemsSource = args.Result; // comes from webservice call and is Staff[]
lstStaffs.UpdateLayout();
But I get Staff object in lstStaffs.Items!!, So how can I iterate over selected(IsChecked=true) items(staffs) ...
Tnx
From the How to: Find DataTemplate-Generated Elements page at MSDN:
// Getting the currently selected ListBoxItem
// Note that the ListBox must have
// IsSynchronizedWithCurrentItem set to True for this to work
ListBoxItem myListBoxItem = (ListBoxItem)(myListBox.ItemContainerGenerator.
ContainerFromItem(myListBox.Items.CurrentItem));
// Getting the ContentPresenter of myListBoxItem
ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(myListBoxItem);
// Finding textBlock from the DataTemplate that is set on that ContentPresenter
DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
TextBlock myTextBlock = (TextBlock)myDataTemplate.FindName("textBlock",
myContentPresenter);
// Do something to the DataTemplate-generated TextBlock
MessageBox.Show("The text of the TextBlock of the selected list item: "
+ myTextBlock.Text);
This shows you how to get access to elements defined in a DataTemplate. However, if you just want to get access to the items from the collection that have been selected, there is a much simpler way:
var selectedItems = lstStaffs.SelectedItems;
You must set the SelectionMode to Multiple or Extended for this to work.
My code is as below
<ListBox x:Name="lstbxRefMarket" Margin="5,5,5,5" BorderThickness="0" Height="100" VerticalAlignment="Stretch">
<ListBox.ItemTemplate>
<HierarchicalDataTemplate>
<CheckBox Name="chkbxRefMarket" Content="{Binding Market}" CommandParameter="{Binding MarketId}" Tag="{Binding MarketId}" IsChecked="{Binding Checked}" Checked="chkbxRefMarket_Checked" Unchecked="chkbxRefMarket_Unchecked" Foreground="Blue"/>
</HierarchicalDataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now in code behind I need to uncheck the particular checkbox with MarketId as 8 from chkbxRefMarket list
As you see from the code checkbox will be having CommandParameter ,Tag as MarketId
How can I find the particular checkbox with that market id in the list .
Why not simply find the right item and set its Checked property. The associated CheckBox is bound to that property and will automatically be unchecked.
The code below assumes that your data item class is MyItem.
IEnumerable<MyItem> items = lstbxRefMarket.Items.OfType<MyItem>();
MyItem item = items.FirstOrDefault(i => i.MarketId == 8);
if (item != null)
{
item.Checked = false;
}