Binding SelectedItem of ListBox - c#

hi i have one list box that every row contain one textbox and one button;
with click button that row delete from listbox; this work with mvvm pattern
i use command for this.
this is my xaml:
<DataTemplate x:Key="CategoryTemplate">
<Border Width="400" Margin="5" BorderThickness="1" BorderBrush="SteelBlue" CornerRadius="4">
<StackPanel Grid.Row="0" Orientation="Horizontal">
<TextBlock Width="300" Margin="5" Text="{Binding Path=Name}"></TextBlock>
<Button Name="btnDeleteCategory" Width="50" Margin="5"
Command="{Binding DataContext.DeleteCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}" Content="-" />
</StackPanel>
</Border>
</DataTemplate>
<ListBox Grid.Column="0" Grid.Row="0" Name="lstCategory"
ItemTemplate="{StaticResource CategoryTemplate}"
ItemsSource="{Binding Path=GetAllCategories}">
</ListBox>
and in viewmodel class i have this command :
private ObjectButtonCommand<Category> _deleteCommand;
public ObjectButtonCommand<Category> DeleteCommand
{
get
{
return _deleteCommand
?? (_deleteCommand = new ObjectButtonCommand<Category>(
_category =>
{
GetAllCategories.Remove(_category);
}));
}
}
that GetAllCategories is observecollection propert;
and this is my ObjectButtonCommand code:
public class ObjectButtonCommand<T> : ICommand
where T:class
{
private Action<T> WhatToExecute;
public ObjectButtonCommand(Action<T> What)
{
WhatToExecute = What;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
WhatToExecute((T)parameter);
}
}
now every thing is ok and when click button that row delete;
now i want that this process repeat when i select one row of listbox
i try this code :
<ListBox Grid.Column="0" Grid.Row="0" Name="lstCategory" ItemTemplate="{StaticResource CategoryTemplate}" ItemsSource="{Binding Path=GetAllCategories}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DataContext.DeleteCommand , RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding Path=SelectedItems,ElementName=lstCategory}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
but i get this error at this code : WhatToExecute((T)parameter);
{"Unable to cast object of type 'System.Windows.Controls.SelectedItemCollection' to type 'Sepand.WPFProject.Model.Model.Category'."}
what should i do?

You pass the selection to the delete command which is a list, hence you cannot use the same command for both cases unless you would wrap the individual items (as passed from the DataTemplate) in a list first.
You should probably define a new command which takes an IList as parameter (type of ListBox.SelectedItems), whose items you then cast to Category and remove individually.
If you just want to delete a single selected item you need to change the binding to SelectedItem and need be able to handle the case of SelectedItem being null in your existing command. e.g. change CanExecute to parameter != null if that is respected by InvokeCommandAction.

Hi Mohammad can you try this:
For your Listbox, make sure your SelectionMode is set to Single. Then change that you refer to SelectedItem in the CommandParameter instead of SelectedItems. Like so:
<ListBox Grid.Column="0" Grid.Row="0" Name="lstCategory" ItemTemplate="{StaticResource CategoryTemplate}" ItemsSource="{Binding Path=GetAllCategories}" SelectionMode="Single">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding DataContext.DeleteCommand , RelativeSource={RelativeSource AncestorType=ListBox}}" CommandParameter="{Binding Path=SelectedItem,ElementName=lstCategory}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>

Related

selected item is not passed correctly for command parameter for first time

I need to get selected item from the combo box as command parameter.
but for the first time selected item is received as old value in the command parameter.
XAML:
<DataTemplate x:Uid="DataTemplate_2">
<control:ComboBox x:Uid="ComboBoxType"
x:Name="AstmComboBox"
HorizontalAlignment="Stretch"
Height="20"
FlowDirection="LeftToRight"
HorizontalContentAlignment="Right"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type control:UserControl}}, Path=DataContext.InclusionTypes}"
SelectedItem="{Binding Path=ClassName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding DataContext.IsReclassificationAllowed, RelativeSource={RelativeSource AncestorType=control:DataGrid}}"
Width="Auto">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type control:UserControl}},Path=DataContext.ClassChangedCommand, Mode=OneWay}"
CommandParameter="{Binding ElementName=AstmComboBox, Path=SelectedItem}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</control:ComboBox>
</DataTemplate>
in viewmodel i have relaycommand
public RelayCommand ClassChangedCommand
{
get
{
return _classChangedCommand ?? (_classChangedCommand = new RelayCommand(ClassChanged));
}
}
private void ClassChanged(object obj)
{
{
SetSelectedItemsType(obj as string);
}
}
Here for the first time obj received has the old value of the combo box item.

WPF MVVM Grid With Button Column

I am following the MVVM pattern. I have a grid with few columns one column having Button in it . Clicking on button i want to open dialog box which is expected to display data related to that particular row in which button was clicked. But the problem is with binding , as i am unable to bind the control with viewmodel.
<Button Command="{Binding Path=ParentRow.DataContext,
RelativeSource={RelativeSource AncestorType={x:Type UserControl}},
UpdateSourceTrigger=PropertyChanged, Mode=Default}"
lib:Event.Binding="Click.[**NameOfViewModelMethod**]" >
</Button>
First things first, if your Button is inside a Grid with a defined DataContext you don't need to set the Path like Path=ParentRow.DataContext.
Your Command binding should be like this:
<Button Command="{Binding YourVMICommand"} />
You have to define a public ICommand in your VM and then bind it to the button.
you don't show all of your code and context but it should work like this
i assume you are in a usercontrol caling parent datacontext ...
(exemple with listview):
<ListView ItemsSource="{Binding listFromDataContext, IsAsync=True}" Margin="3,51,0,10" >
<ListView.ItemTemplate >
<DataTemplate>
<grid>
<Button Command="{Binding DataContext.MyMethode, RelativeSource={RelativeSource AncestorType={x:Type controls:thisUserControl}}}" CommandParameter="{Binding}" />
</grid>
</DataTemplate>
</ListView.ItemTemplate >
</ListView>
then in model
private ICommand _MyMethode;
public ICommand MyMethode
{
get
{
return _MyMethode ?? (_MyMethode = new CommandHandler<MyModel.item>(x => showMessage(x), _canExecute));
}
}
public void showMessage(MyModel.item x)
{
MessageBox.Show(x.Info);
}

ComboBox in a ListBox fires SelectionChanged event but value of the selected item of combo box doesnt get updated - MVVM Pattern

I have a UWP app, using the Prism framework\toolkit. The app has a ListView. Every row composites of various TextBlocks and a ComboBox. Initially, when the grid gets loaded, I want ComboBox to show no item selected but the item source loaded. The user now has to choose any item from the combo box. The ListBox and ComboBox are populated from 2 different ObservableCollection from the ViewModel. The SelectionChanged event does fire for me for the ComboBoxes in the ListBox as I am using Dependency Property but the item which is selected by the user from Combo Box, the properly of Selected Value is not updating in the View Model.
I have a ListView within which I have ComboBox.
I have added the code-snippet from my application below:
I am using Behaviors SDK here as well.
<ListView x:Name="AssignCountryStateGridData" Grid.Row="1"
HorizontalAlignment="Left" ItemsSource="{Binding AssignCCPGridInfo,Mode=TwoWay}" MinWidth="805" MinHeight="480">
<ListView.ItemTemplate>
<DataTemplate>
<Grid MinHeight="25" MinWidth="805">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="120"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions >
<RowDefinition Height="25"/>
</Grid.RowDefinitions>
<TextBlock FontSize="13" Foreground="White" Grid.Column="0" Text="{Binding CompanyCode}" ToolTipService.ToolTip="{Binding CompanyCode}" TextAlignment="Center"/>
<TextBlock FontSize="13" Foreground="White" Grid.Column="1" Text="{Binding CustomerNbr}" ToolTipService.ToolTip="{Binding CustomerNumber}" TextAlignment="Center"/>
<ComboBox Grid.Column="3" Height="25" Width="20" Margin="20,5,0,0" VerticalAlignment="Center" x:Name="comboBoxCountryCode"
ItemsSource="{Binding Path=DataContext.EFSSAPCountryCode,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="CountryCode"
SelectedValue="{Binding SelectedCountryCode,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
<interactivity:Interaction.Behaviors>
<core:EventTriggerBehavior EventName="SelectionChanged">
<core:InvokeCommandAction Command="{Binding ElementName=AssignCountryStateGridData,Path=DataContext.LoadSelectedCountryCodeCommand}"
CommandParameter="{Binding SelectedValue,ElementName= AssignCountryStateGridData}"/>
</core:EventTriggerBehavior>
</interactivity:Interaction.Behaviors>
</ComboBox>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And this is View Model Code
private ObservableCollection<EFSSAPCountryCode> _EFSSAPCountryCode;
private EFSSAPCountryCode _SelectedCountryCode;
public DelegateCommand LoadSelectedCountryCodeCommand { get; set; }
[RestorableState]
public ObservableCollection<EFSSAPCountryCode> EFSSAPCountryCode
{
get { return _EFSSAPCountryCode; }
set { SetProperty(ref _EFSSAPCountryCode, value); }
}
[RestorableState]
public EFSSAPCountryCode SelectedCountryCode
{
get { return _SelectedCountryCode; }
set { SetProperty(ref _SelectedCountryCode, value); }
}
public AssignCountryStateProvinceCodesViewModel()
{
this.LoadSelectedCountryCodeCommand = DelegateCommand.FromAsyncHandler(GetColumnsForSelectedCountryCode);
}
public async override void OnNavigatedTo(NavigatedToEventArgs e, Dictionary<string, object> viewModelState)
{
//Set EFSSAPCountryCode and other call for service
}
private async Task GetColumnsForSelectedCountryCode()
{
//I am getting call here when I select something from Combo Box but I never get what was selected by the user from the Combo Box and "SelectedCountryCode" stays null
}
I saw something about using RelativeSource but that gives syntax error.
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}
I am not sure what is wrong in this code.

Windows Phone 7 - Function for ListBox button

I have list of items in ListBox.
All the items have buttons.
I want to show the selected items name when I click the button inside the ListBox (Not the list box items).
My Xaml:-
<ListBox SelectedIndex="{Binding SelectedIndex,Mode=TwoWay}"
SelectedItem="{Binding SelectedStudent, Mode=TwoWay}" Height="374"
ItemsSource="{Binding StudentDetails,Mode=TwoWay}"
HorizontalAlignment="Left" Margin="2,6,0,0" Name="listBox1"
VerticalAlignment="Top" Width="476" BorderBrush="#00410D0D">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding EventPageCommand, Mode=OneWay}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Gray" Padding="5" BorderThickness="1">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Wheat" BorderThickness="1">
<Image Name="ListPersonImage" Source="{Binding PersonImage}"
Height="100" Width="100" Stretch="Uniform" Margin="10,0,0,0"/>
</Border>
<TextBlock Text="{Binding FirstName}" Name="firstName" Width="200"
Foreground="White" Margin="10,10,0,0"
FontWeight="SemiBold" FontSize="22" />
<Button Height="80" Width="80" Command="{Binding addPerson}"
DataContext="{Binding DataContext, ElementName=listBox1}">
<Button.Background>
<ImageBrush
ImageSource="/NewExample;component/Images/icon_increase.png" />
</Button.Background>
</Button>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Here when I click the 'addPerson' Button it should show the selected items name.
Now I have write the coding for List box 'SelectedItmes'.
My ViewModel:-
private MVVMListBoxModel selectedStudent;
public MVVMListBoxModel SelectedStudent
{
get { return selectedStudent; }
set
{
if (selectedStudent == value)
return;
selectedStudent = value;
MessageBox.Show("Selected Item==>" + selectedStudent.FirstName + " Selected Index==>" + SelectedIndex);
if (SelectedIndex == 0)
{
var rootFrame = (App.Current as App).RootFrame;
rootFrame.Navigate(new Uri("/MainPage.xaml", UriKind.Relative));
}
}
}
Here I can show the selected Name when I click the list box items.
But now I want to show when I click the button.
Is it possible to show the items when I click the button?
Now I have tried like this:-
public ReactiveAsyncCommand addPerson { get; set; }
public MVVMListBoxViewModel()
{
addPerson = new ReactiveAsyncCommand();
addPerson.Subscribe(x =>
{
MessageBox.Show("Button Clicked..!!");
ListBox listbox = (ListBox)sender;
ListBoxEventsModel items = (ListBoxEventsModel)listbox.SelectedItem;
MessageBox.Show("Selected Name" + items.ToString());
});
}
But here I can not show the selected items.
Please let me any idea to solve this issue.
To make sure that your code is working
Make some tests like this:
<Button Tap="btnTestCommand_Tap" Height="80" Width="80" Command="{Binding addPerson}"
DataContext="{Binding DataContext, ElementName=listBox1}">
<Button.Background>
<ImageBrush ImageSource="/NewExample;component/Images/icon_increase.png" />
</Button.Background>
</Button>
Code behind:
private void btnTestCommand_Tap(object sender, GestureEventArgs e)
{
Button btn=sender as Button;
var command = btn.Command;
MessageBox.Show("Entering Command Check\n DataContext is of type: "+btn.DataContext.GetType().Name);
if(command !=null)
{
MessageBox.Show("Command is not null");
if(command is ReactiveAsyncCommand)
{
MessageBox.Show("Command is of ReactiveAsyncCommand type");
}
}
}

Checkbox in Listbox to select multiple items and add it to another listbox using MVVM

Using MVVM,
I have two listboxes which contains Checkboxes and data is binded from database.
The Items which are checked in first Listbox want to add it in Second listbox.
First ListBox:
<pmControls:pmListBox SelectionMode="Multiple" Grid.Row="1" Margin="3" ItemsSource="{Binding ParcelFacilities}" >
<interactivity:Interaction.Triggers>
<interactivity:EventTrigger EventName="SelectionChanged">
<shared:EventToCommandTrigger Command="{Binding Listbox_SelectionChangeCommand}" />
</interactivity:EventTrigger>
</interactivity:Interaction.Triggers>
<pmControls:pmListBox.ItemTemplate >
<DataTemplate >
<pmControls:pmCheckBox Content="{Binding Title}" Margin="3" Width="200" IsChecked="{Binding checkedParcelFacility}" >
</pmControls:pmCheckBox>
</DataTemplate>
</pmControls:pmListBox.ItemTemplate>
Second ListBox:
<pmControls:pmListBox SelectionMode="Multiple" Grid.Row="1" Margin="3" ItemsSource="{Binding Selected_ParcelFacilities}"
Height="100">
<pmControls:pmListBox.ItemTemplate >
<DataTemplate >
<pmControls:pmCheckBox Content="{Binding Title}" Margin="3" Width="200" ></pmControls:pmCheckBox>
</DataTemplate>
</pmControls:pmListBox.ItemTemplate>
In ViewMOdel:
I have handled SelectionChanged Event For first Listbox and tryied to add checked element to the collection
Named as Selected_ParcelFacilities and Binded it to Second Listbox.
public ParcelViewModel(IModalDialogService modalDialogService, IMessageBoxService messageBoxService)
{
parcelFacilities = new ObservableCollection<Parcel_Facility>();
Selected_ParcelFacilities = new ObservableCollection<Parcel_Facility>();
Selected_ParcelFacilities.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Selected_ParcelFacilities_CollectionChanged);
}
void Selected_ParcelFacilities_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged("Selected_ParcelFacilities");
}
private void Executelistbox_SelectionChangeCommand(EventToCommandArgs args)
{
bool a = checkedParcelFacility;
foreach (Parcel_Facility item in parcelFacilities)
{
if (Selected_ParcelFacilities != null)
{
Selected_ParcelFacilities.Add(item);
}
}
}
But using above code all items from first listbox are adding to second ,
i am not getting how to check wheather its cheked or not.
Please Help.
you can simply bind your second list box to SelectedItems of your first one. this would work with real selection in listbox first.
<ListBox x:Name="second" ItemsSource="{Binding Elementname=first, Path=SelectedItems, Mode=OneWay}"/>
another approach is to use a ICollectionView with filter for your second listbox. the filter simply handle the checkedParcelFacility Property and the second listbox is bind to the ICollectionView.

Categories