Hi I am making an WPF application and have a problem with a listbox/listview, MVVM is implemented. I am creating a list of a class that is displayed on the listbox and I am editing the items through selecting an item in the listbox. The problem is when I am deleting an item it doesn't trigger onpropertychanged event to the UI, but is however working in the code, the values are right. When I close the window and reopens it then the list is updated, but not directly when the item is deleted, it never triggers onpropertychanged event for some reason.
It does work to just filter the quicknotelist like
quicknotelist = quicknotelist.where(x => x.id != selecteditem.id);
It works only once though and the UI updates however the selecteditem doesn't seem to work properly even though I am declaring
selecteditem = new quicknote() {*values*};
Part of relevant code, I am using INotifyPropertyChanged
private QuickNote selectedNote = new QuickNote(); // weeeeeee
public QuickNote SelectedNote
{
get
{
return selectedNote;
}
set
{
if (SelectedNote != null)
{
selectedNote = value;
OnPropertyChanged("SelectedNote");
EnableEditNoteBox = true;
}
}
}
private List<QuickNote> quickNoteList = new List<QuickNote>();
public List<QuickNote> QuickNoteList
{
get { return quickNoteList; }
set { quickNoteList = value; OnPropertyChanged("QuickNoteList"); }
}
here is the method that deletes the item
private void DeleteNote(object obj)
{
if (SelectedNote != null)
{
QuickNoteList.Remove(SelectedNote);
// I want this to trigger onpropertychanged without using myclasslist = newclasslist; since it messes up selecteditem to null.
}
}
heres the xaml part.
<ListBox
Width="713"
Height="230"
SelectedItem="{Binding SelectedNote, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
ItemsSource="{Binding QuickNoteList,BindsDirectlyToSource=True, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
DisplayMemberPath="Notes"
Foreground="Black"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.CanContentScroll="False"/>
I'd leave a comment if I could. You should lookup ObservableCollection. I think QuickNoteList should be of this type.
Related
I have a ListView which I would like te re-evaluate its SelectedItem once it receives a new ItemSource. The goal of this is to 'remember' if the user already selected an item in the ListView.
XAML:
<ListView
x:Name="_matchingTvShowsFromOnlineDatabaseListView"
Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="3"
ItemsSource="{Binding AvailableMatchingTvShows}"
SelectedItem="{Binding AcceptedMatchingTvShow, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The SelectedItem is also bound to a property on my VM.
The VM:
public IWebApiTvShow AcceptedMatchingTvShow
{
get
{
IWebApiTvShow acceptedTvShow = null;
if (FoundTvShows.Count > 0)
{
var tvShowName = FoundTvShows[CurrentTvShow];
acceptedTvShow = AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
}
return acceptedTvShow;
}
set
{
if (value != null)
{
var tvShowName = FoundTvShows[CurrentTvShow];
var currentlyAcceptedTvShow =
AvailableTvShowMatches[tvShowName].FirstOrDefault(webApiTvShow => webApiTvShow.Accepted);
if (currentlyAcceptedTvShow != null)
{
currentlyAcceptedTvShow.Accepted = false;
}
value.Accepted = true;
}
OnPropertyChanged();
}
}
I made a screen shot of the application I am building, which hopefully makes clear what I am trying to achieve.
The idea would be that when the user is navigating through the TV Shows, the application would remember the associated TV Show.
Currently, when I associate a TV Show, and navigate to the next TV Show and back again, nothing is selected (the getter of the property AcceptedMatchingTvShow is not executed after setting the new ItemSource)
UPDATE:
Added the code for AvailableMatchingTvShows
private ObservableCollection<IWebApiTvShow> _availableMatchingTvShows;
public ObservableCollection<IWebApiTvShow> AvailableMatchingTvShows
{
get { return _availableMatchingTvShows; }
set
{
_availableMatchingTvShows = value;
OnPropertyChanged("AcceptedMatchingTvShow");
}
}
Without seeing all of your ViewModel, I'm guessing if you raise PropertyChanged("AcceptedMatchingTvShow") when the ItemsSource binding changes that would update the SelectedItem binding.
I have an ObservableCollection that I would like to bind to multiple datagrids, each one displayed in its own window, and each datagrid having a different filter. I was initially using this:
ICollectionView m_icvs = CollectionViewSource.GetDefaultView(ListOrder)
m_icvs.Filter = OrderFilter;
And it worked fine for one filter, but when I needed to open more windows, each with its own filter, the filter would change across all windows. I think this is because all of the windows are using the same ICollectionView, which is returned by the GetDefaultView. So I found another post with a similar problem - Multiple Views of Observable Collection with Datagrid. I tried to adapt this solution to my problem but could not get it to work. This is what I tried:
private CollectionViewSource m_cvs;
public CollectionViewSource Cvs
{
get { return m_cvs; }
set { m_cvs = value; }
}
ObservableCollection<OrderItem> m_listOrder;
public ObservableCollection<OrderItem> ListOrder
{
get { return m_listOrder; }
set { m_listOrder = value; }
}
public OrderDlg(ObservableCollection<OrderItem> listOrder)
{
ListOrder = listOrder;
...
Cvs = new CollectionViewSource();
Cvs.Source = ListOrder;
Cvs.View.Filter = delegate(object o) { return OrderFilter(o); };
}
xaml:
<DataGrid
ItemsSource="{Binding Cvs}">
...
</DataGrid>
Using this approach, the DataGrid doesn't display data, even if I comment out the line that applies the filter.
DataGrid's itemsource should be binded to ICollectionView and not
CollectionViewSource.
Create a property which will return ICollectionView from your CollectionViewSource object -
public ICollectionView CV
{
get
{
return m_cvs.View;
}
}
Update your binding in XAML -
<DataGrid ItemsSource="{Binding CV}"/>
Can anyone help, lost a lot of time trying to figure this issue out.
I have a ViewModel with following properties
public ObservableCollection<ListItem> OpcoList { get; set; }
public ListItem SelectedOpco {
get {
return _selectedOpco;
}
set {
if (_selectedOpco != null && _selectedOpco.Equals(value)) {
return;
}
var oldValue = _selectedOpco;
_selectedOpco = value;
RaisePropertyChanged("SelectedOpco");
}
And in my XAML i have
<ListBox Name="listOpco" ItemsSource="{Binding OpcoList}"
SelectionMode="Single" SelectedItem="{Binding Mode=TwoWay, Path=SelectedOpco}">
But whenever I set some value to SelectedOpco in my VM it does not show as selected in ListBox.
Any ideas? Thanks in advance!
Some things you could try:
Simplify the setter to something simpler (it should do what you expect to - check if a different element of the list is selected).
set {
if(_selectedOpco != value) {
_selectedOpco = value;
RaisePropertyChanged("SelectedOpco");
}
}
Put a break point at the RaisePropertyChanged("SelectedOpco"); line to see if the execution goes there. If yes, check if the class is really marked as INotifyPropertyChanged.
if(!(this is INotifyPropertyChanged))
throw new Exception("Not INotifyPropertyChanged");
Try to set the value with:
SelectedOpco = OpcoList.FirstOrDefault(); // LastOrDefault
Good luck!
I am new to MVVM, and also fairly new to WPF. As a matter of fact I started programming just a few months ago. MVVM is really dng my head in with the binding concept, and I have been trying for days now to just simply make an application that allows you to select an item from a listbx, and when you click on the add button the selected item should be saved in a new list. The second listbox displays the latest items added, and you can select an item and delete it by using another button. ususally I would go for the click event and decorate my codebehind with pretty little methods, but I really want to learn how to do all this by using bindings and no codebehind.
I would be extremly happy for any help, and please remember that I am new to this and I really want to keep it as simple as possible :)
with kind regards Daniela
<WrapPanel HorizontalAlignment="Center" Margin=" 10">
<ListBox x:Name="Firstbox"
Width="100"
ItemsSource="{Binding FoodList}"
DisplayMemberPath="Name" >
</ListBox>
<Button Margin="10 >Select</Button>
<ListBox Width="100"></ListBox>
private List _foodList;
public List<FoodItem> FoodList
{
get { return _foodList; }
set { _foodList = value; }
}
private List<FoodItem> _newFoodList;
public List<FoodItem> NewFoodList
{
get { return _newFoodList; }
set { _newFoodList = value; }
}
public MainViewModel()
{
InitializeCommands();
GetFood();
}
private void GetFood()
{
FoodList = new List<FoodItem>()
{
new FoodItem() {Name="Applepie"},
new FoodItem() {Name="Scones"}
};
}
first, you need to replace the Lists with ObservableCollections, so that the UI can detect when new items are added.
Add a SelectedItem property to your ViewModel:
private FoodItem _selectedItem;
public FoodItem SelectedItem
{
get { return _selectedItem;}
set
{
_selectedItem = value;
OnPropertyChanged("SelectedItem");
}
}
bind the SelectedItem property of the 1st ListBox to this property:
<ListBox Width=" 100" x:Name="Firstbox"
ItemsSource="{Binding FoodList}"
DisplayMemberPath="Name"
SelectedItem="{Binding SelectedItem}" />
bind your 2nd ListBox to the NewFoodList property
create a command in your ViewModel:
private DelegateCommand _addItemCommand;
public ICommand AddItemCommand
{
get
{
if (_addItemCommand == null)
{
_addItemCommand = new DelegateCommand(AddItem);
}
return _addItemCommand;
}
}
void AddItem()
{
if (SelectedItem != null)
NewFoodList.Add(SelectedItem);
}
And finally, bind the button's Command property to the AddItemCommand property:
<Button Margin="10" Command="{Binding AddItemCommand}" >Select</Button>
When i selected the values in combo box,i have to hide another control. I have write the code as shown in below. Please correct me where i made mistake in that.
View Code:
<ComboBox x:Name="cboShowRuleWhere" Height="20" Width="200" ItemsSource="{Binding Source={StaticResource listedView}, Path=FilterRules}" DisplayMemberPath="RuleName" SelectedValuePath="RuleId" SelectedValue="{Binding Source={StaticResource listedView}, Path=SelectedRuleName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" ></ComboBox>
<ComboBox Height="21" HorizontalAlignment="Left" Margin="6,4,0,0" x:Name="cboRuleCondtion" Visibility="{Binding Path=IsButtonVisible,Converter={StaticResource BoolToVisible}}" VerticalAlignment="Top" Width="212" />
ViewModel Code:
private DataTable m_selectedRuleName;
public DataTable SelectedRuleName
{
get
{
return m_selectedRuleName;
}
set
{
m_selectedRuleName = value;
base.RaisePropertyChangedEvent("SelectedRuleName");
}
}
private bool _IsButtonVisible;
public bool IsButtonVisible
{
get { return _IsButtonVisible; }
set
{
_IsButtonVisible = value;
base.RaisePropertyChangedEvent("IsButtonVisible");
}
}
Where i have to correct? Please help me asap. Thanks in advance..
There's not a whole lot to go on here. For instance, where are you setting IsButtonvisible based on your rule criteria? Here are some ideas:
1) Don't create a backing field for IsButtonVisible. Instead, have it return the correct analysis.
public bool IsButtonVisible { get { return SelectedRuleName == "IsVisibleRule"; } }
2) You can fire the Notify Propery Changed event from anywhere. In this case, you want the IsButtonVisible binding to be reevaluated every time the SelectedRuleName changes:
private DataTable m_selectedRuleName;
public DataTable SelectedRuleName
{
get
{
return m_selectedRuleName;
}
set
{
m_selectedRuleName = value;
base.RaisePropertyChangedEvent("SelectedRuleName");
base.RaisePropertyChangedEvent("IsButtonVisible");
}
}
3) Is the SelectedRuleName really a DataTable? That would seem odd to me because it indicates multiple rows. It would be a longer post, but I would avoid DataTable altogether and change the ComboBox item source to an ObservableCollection. The "SelectedRuleName" would be of type T (not DataTable).
4) Along the same lines, I have found much greater success using SelectedItem instead of SelectedValue.
I hope some of this helps.