Re-evaluate a ListView's SelectedItem after changing ItemSource - wpf

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.

Related

WPF make combobox binding twoways

I have a combo box that is editable, and i have a button that is enable when SelectedReplacement that binds to the combobox is not null and disable when it is. When it's null, i would input some random text to make the button enable, the problem is it wouldn't become enable when there I input text. making the Mode TwoWay doesn't help. i assumed setting the propertychangedevent would bind the new text to SelectedReplacement, but Im wrong, so any help is appreciated.
<ComboBox ItemsSource="{Binding SelectedError.Suggestions}"
Text="{m:Binding Path=SelectedError.SelectedReplacement, Mode=TwoWay}"
IsEditable="True"
HorizontalAlignment="Stretch"/>
i also tried to get the propertychanged
private void ViewModelPropertyChanged(SpellcheckViewModel sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(sender.SelectedError.SelectedReplacement))
{
_correctCommand?.Refresh();
}
}
I try to write a demo project to meet your requirement.
Mainly, the enable state is controlled by another boolean property IsButtonEnabled in the view model, the value for that property is controlled by InputText property which is controlled by the text you input in the ComboBox control.
Here is the UI:
<StackPanel Margin="10">
<ComboBox
x:Name="cmb"
IsEditable="True"
ItemsSource="{Binding AllItems}"
TextBoxBase.TextChanged="cmb_TextChanged"
TextSearch.TextPath="Name">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBox
x:Name="hiddenTextBox"
Text="{Binding InputText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Visibility="Collapsed" />
<Button
x:Name="btn"
Margin="0,10,0,0"
Content="Show message"
IsEnabled="{Binding IsButtonEnabled}" />
</StackPanel>
And here is the main logic in the view model:
public ObservableCollection<Item> AllItems
{
get { return _allItems; }
set { _allItems = value; this.RaisePropertyChanged("AllItems"); }
}
public bool IsButtonEnabled
{
get { return _isButtonEnabled; }
set { _isButtonEnabled = value; this.RaisePropertyChanged("IsButtonEnabled"); }
}
/// <summary>
/// When InputValue changed, change the enable state of the button based on the current conditions
/// </summary>
public string InputText
{
get { return _inputText; }
set
{
_inputText = value;
this.RaisePropertyChanged("InputText");
// You can control the enable state of the button easily
if (AllItems.Any(item => item.Name == value))
{
// SelectedItem is not null
IsButtonEnabled = true;
}
else if (!string.IsNullOrEmpty(value))
{
// SelectedItem is null
IsButtonEnabled = true;
}
else
{
IsButtonEnabled = false;
}
}
}
Finally, here is the project: ComboBoxDemo

Set selected value of combobox

I want to set selected value of a combobox
I am receiving a DataTable from the database looking like this:
this Datatable is bound to this combobox.
<ComboBox
DisplayMemberPath="KommuneNavn"
SelectedValuePath="KommuneNr"
ItemsSource="{Binding KommuneNavne}"
SelectedValue="{Binding KommuneNr, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="3"
IsEnabled="{Binding IsUdenlandskAdresse, Converter={StaticResource BooleanNotConverter}}" />
In my viewmodel I have a specific KommuneNr stored in a property. I would like to have my combobox set to show the KommuneNavn that matches with this KommuneNr.
Example:
I have the KommuneNr 101 stored in my viewmodel, the KommuneNavn that matches with this is København I would then like to have my combobox be set to København.
This was pretty difficult to explain, I hope I am making sense. Otherwise feel free to ask.
KommuneNavne must be an ObservableCollection, and in your ViewModel you should implement INotifyPropertyChanged (not described in this example)
<ComboBox
ItemsSource="{Binding KommuneNavne}"
SelectedValue="{Binding KommuneNr, NotifyOnSourceUpdated=True, UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="KommuneNavn"
SelectedValuePath="KommuneNr"
/>
ViewModel
public class MyViewModel : INotifyPropertyChanged
{
public ObservableCollection<KommuneNavn> KommuneNavne
{
get { value = _kommuneNavne; } //=> _kommuneNavne;
set
{
_kommuneNavne = value;
OnPropertyChanged(nameof(KommuneNavne));
}
}
public long KommuneNr
{
get { value = _kommuneNr; } //=> _kommuneNr;
set
{
if (_kommuneNr == value) return;
_kommuneNr = value;
OnPropertyChanged(nameof(KommuneNr));
}
}
private void SetValue(int valueToSet)
{
KommuneNr = valueToSet;
}
}

WPF listbox removing item properly

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.

How can I add items from a listbox to a list by clicking a button without any codebehind?

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>

Unable to hide the control in WPF using MVVM

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.

Resources