how to remove custome items from observablecollection in silverlight - 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

Related

CollectionViewSource unselect selectedItem when clicking a group name

I have a listbox that has its itemSource bound to a collectionViewSource that is grouped and has 2 levels of groupings over the actual items:
<ListBox ItemsSource="{Binding Source={StaticResource myCVS}}" ItemTemplate="{StaticResource myItemsTemplate}" ItemContainerStyle="{StaticResource myItemsStyle}" SelectedItem="{Binding SelectedListItem}" >
<ListBox.GroupStyle>
<GroupStyle ContainerStyle="{StaticResource HeaderStyle}" />
<GroupStyle ContainerStyle="{StaticResource SubHeaderStyle}" />
</ListBox.GroupStyle>
</ListBox>
With a CollectionViewSource bound to an ObservabeleCollection:
<CollectionViewSource x:Key="myCVS" Source="{Binding Path=myItemsToGroup}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="HeaderName" />
<PropertyGroupDescription PropertyName="SubHeaderName" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
the items in the ObservalbleCollection look like:
public class Items
{
public string GroupName;
public string SubGroupName;
public string ItemName;
}
This all works great i end up with:
Header1
|_SubHeader1
|_item1
|_item2
Header2
|_SubHeader2
|_item1
|_item2
The problem is if i click an item it becomes selected, and stays selected if I click on a header or subheader. If a header is clicked I would like to set the SelectedItem to null. I am using a command to remove the SelectedItem from the UI, but i don't want the command to execute if a header or subheader is being clicked only when a item is being clicked.
GroupStyles are not selectable, so of course your view model won't see a selection change happen.
To work around this, you can use some code behind. What you'll notice is if you click on the items in the ListBox, then ListBoxItem will set the MouseUp event's Handled property to true. If you click anywhere else on the ListBox, nothing handles the event. With that being said, you can set your selected item based on the state of Handled.
XAML:
<ListBox ItemsSource="{Binding Source={StaticResource myCVS}}"
ItemTemplate="{StaticResource myItemsTemplate}"
ItemContainerStyle="{StaticResource myItemsStyle}"
SelectedItem="{Binding SelectedListItem}"
MouseLeftButtonUp="ListBox_MouseLeftButtonUp">
Code-behind:
private void ListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if(!e.Handled)
{
var lb = sender as ListBox;
lb.SelectedItem = null;
}
}
Addendum:
Clicking on an already selected item will set the SelectedItem to null. To prevent that, do this: instead of using MouseLeftButtonUp use MouseDown:
<ListBox ItemsSource="{Binding Source={StaticResource myCVS}}"
SelectedItem="{Binding SelectedListItem}"
MouseDown="ListBox_MouseLeftButtonUp">
Here is the state of my current application (GroupStyle's) don't get drawn properly, but the implementation is what's important here. If this doesn't do it for you, I would implement a pure MVVM approach.

Pass DropDown value to RelayCommand in WPF MVVM

This is my Code in XAML.
<telerik:RadComboBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectedItem}" ></telerik:RadComboBox>
<telerik:RadButton Name="BtnExportToPdf" Content="Export To PDF" Command="{Binding ExportToPDFClickCommand}"></telerik:RadButton>
Below is my RelayCommand in ViewModel
public ICommand ExportToPdfClickCommand
{
get
{
return new RelayCommand(ExportReportData);
}
}
I want to pass Dropdown Value to Relay Command. How can I do this ?
Why do you need to pass the selected item to your command?
Your viewmodel already has that value:
SelectedItem="{Binding SelectedItem}"
As a result, just refrence your SelectedItem property within your view-model.

WPF MVVM DataTemplate: Inject Template ViewModel with Data from parent Viewmodel

I have an ObservableCollection in my parent ViewModel which I want to display in the parent View. So I've defined a child View and a child ViewModel handling button clicks.
How do I get each item from the ObservableCollection into the according child ViewModel without loosing my already setup RelayCommands for button click handling?
In my parent View Code-Behind the only thing I do is setting the DataContext to the appropiate ViewModel:
DataContext = new ParentViewModel();
In my parent View XAML I defined a ListBox to display a DataTemplate of my child View:
<ListBox
ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<views:ChildView Width="auto" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now in my ChildView I got several TextBlocks displaying the Binding Data and Buttons which should execute a file in a path specified within the ObservableCollection:
<TextBlock
Text="{Binding Path=Title}" />
...
<Button
Content="Start exe"
Tag="{Binding Path=ExePath}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<i:InvokeCommandAction Command="{Binding Path=OnButtonClicked}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Button>
The Child ViewModel holds RelayCommands to handle the Button click event:
private RelayCommand onButtonClicked;
public ICommand OnButtonClicked
{
get
{
return onButtonClicked ??
(onButtonClicked =
new RelayCommand(ObeyOnButtonClicked, CanObeyOnButtonClicked));
}
}
private void ObeyOnButtonClicked()
{
... //Path conversion
Process.Start(pathToExe);
}
private bool CanObeyOnButtonClicked()
{
return true;
}
Now, within my child View's Code-Behind, when I add
DataContext = new SampleItemViewModel();
to the Constructor, the Button click is handled but the TextBoxes are all empty.
When i remove this line, the TextBoxes are filled correctly, but the Button Clicks are not handled.
How do I get both features working?
EDIT:
ParentViewModel:
private ObservableCollection<Item> items;
public ObservableCollection<Item> Items
{
get { return items; }
set
{
items= value;
OnPropertyChanged("Items");
}
}
... //Filling the Collection in Constructor
ChildViewModel contains just the above mentioned button click handlers.
EDIT:
I tried several things now but I don't know how to bind the Command from the ChildView to my ChildViewModel WITHOUT setting the DataContext of my ChildView to my ChildViewModel
You can remove the Event Trigger, as Button has a Command property.
<TextBlock Text="{Binding Path=Title}" />
...
<Button
Content="Start exe"
Tag="{Binding Path=ExePath}"
Command="{Binding Path=OnButtonClicked}"
>
</Button>
And set the DataContext :
<ListBox
ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type vm:ChildViewModel}">
<views:ChildView Width="auto" DataContext="{Binding}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

WPF: ComboBoxes in ListBox and concurrency

I have code like this:
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock>Some Other Stuff Here</TextBlock>
<ComboBox ItemsSource="{Binding}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem is, every time the outside ListBox.SelectedItem gets changed, the ComboBoxes inside it would change their SelectedIndex to -1. Which means if I click "Some Other Stuff Here" (unless the ListBoxItem it is in is selected), all the comboboxes' selection get cleared.
How do I overcome this? Thx!
Presumably your combobox is bound to something like an ObservableCollection - try exposing an instance of ICollectionView instead:
class DataSource
{
// ...
public ObservableCollection<string> MyData { get; private set; }
public ICollectionView MyDataView
{
get
{
return CollectionViewSource.GetDefaultView(this.MyData);
}
}
}
You can then bind your combobox with:
<ComboBox ItemsSource="{Binding MyDataView}" IsSynchronizedWithCurrentItem="True" />
This means that the 'selected item' for each data source is stored in the ICollectionView object instead of within the combobox, which should mean that it is persisted when the ListBox SelectedItem changes

How to bind a TextBox to plain string collection

As a part of large data model I need to display/edit a string collection defined like ObservableCollection<String>. In prototype app we use a list view to display entire of collection and a text box to edit selected element. The text box should be bound to the current element of the collection. Because GUI is subject to change I can't bind directly using <TextBox Text="{Binding SelectedItem,ElementName=listView}" />.
I tried to use
<TextBox Text="{Binding Path=/, UpdateSourceTrigger=PropertyChanged}"/>
but it works only in one direction, changing listview current item causes updating a text box but not otherwise.
How can I bind a text box directly to sting instance of current element in string collection?
Ok, so here's your ListView. I'm going to add a name to it so I can reference it elsewhere in the XAML:
<ListView
x:Name=stringList
ItemsSource="{Binding}"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True">
<ListView.View>
<GridView>
<GridViewColumn
Header="Data Item"
Width="80"
DisplayMemberBinding="{Binding}"/>
</GridView>
</ListView.View>
</ListView>
Now in your TextBox over on the right you can bind directly to the ListView:
<TextBox Text="{Binding SelectedItem,ElementName=stringList}" />
Since your ListView is bound directly to a list of strings, SelectedItem will be the string the currently-selected ListViewItem points to.
Update
Since you're not allowed to use ElementBinding, your best bet is to introduce a ViewModel class to sit between your list and your window. Define it like this:
public class StringListViewModel : INotifyPropertyChanged
{
// you'll have to implement INotifyPropertyChanged - I won't
// do that here - do a quick search to learn how it works.
public ObservableCollection<String> List { get; set; }
private object _si;
public object SelectedItem
{
get { return _si; }
set
{
_si = value;
OnPropertyChanged("SelectedItem");
}
}
}
Now set your window's DataContext to an instance of your ViewModel class instead of pointing it directly to the string list. Bind your ListView's ItemsSource and SelectedItem to it like this:
<ListView ItemsSource="{Binding List}" SelectedItem="{Binding SelectedItem}" ... />
Now bind your TextBox to the SelectedItem of your ViewModel:
<TextBox Text="{Binding SelectedItem}" />
Now your list sets the SelectedItem on the ViewModel whenever it changes, and thus your TextBox reflects that value. Hope that makes sense.

Resources