Binding view with model (view doesn't update) - wpf

i'm implementing something, that if i select something in my listbox, some textboxes come visible. So i can fill in some details of the selected item. I already implemented a visibilityconverter and this is my code of xaml and viewmodel:
The items in the listbox are objects of class Question
public Question SelectedQuestionDropList
{
get { return selectedQuestionDrop; }
set
{
selectedQuestionDrop = value;
OnPropertyChanged("SelectedQuestionDropList");
Visible = true;
}
}
this is my property of Visibility:
public Boolean Visible
{
get { return visible; }
set { visible = value; }
}
my xaml looks like this:
<ListBox SelectedItem="{Binding Path=SelectedQuestionDropList, UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
DisplayMemberPath="Description"
/>
<TextBox Height="23" Visibility="{Binding Path=Visible, Converter={StaticResource boolToVis},UpdateSourceTrigger=PropertyChanged,Mode}" />
But i have a problem, when i select something, the property visible is set to true, but the visibility of the textbox stays false .. so my view doesn't update with the viewmodel.
someone who knows what i am doing wrong?

In order for the Visibility Binding to update you have to change your property to call OnPropertyChanged:
public Boolean Visible
{
get { return visible; }
set
{
visible = value;
OnPropertyChanged("Visible");
}
}

Related

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;
}
}

Re-evaluate a ListView's SelectedItem after changing ItemSource

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.

Cancel a user edit from property set in the ViewModel?

quite a newbie question, i'm sure, but i wasn't able to find an answer...
I have a control (in this case- a combo box) which is bound to a ViewModel property:
<ComboBox
x:Name="methodTypeCmb"
Grid.Row="0" Grid.Column="2"
ItemsSource="{Binding Path=AllNames, Mode=OneTime}"
SelectedItem="{Binding Path=Name, ValidatesOnDataErrors=True, Mode=TwoWay}"
Validation.ErrorTemplate="{x:Null}"
/>
In my ViewModel, when this property changes, I want to ask the user to confirm the change.
If the user clicks 'no', I want to cancel the change.
However, I must be doing something wrong, because my view doesn't revert back to the previous value when the change is cancelled.
The ViewModel's property:
public string Name
{
get { return m_model.Name; }
set
{
if (MessageBox.Show("Are you absolutely sure?","Change ",MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
// change name
}
base.OnPropertyChanged("Name");
}
}
Because you are cancelling within the scope of the text changing event, wpf ignores the property changed event. You must call it from the dispatcher
Dispatcher.CurrentDispatcher.BeginInvoke((ThreadStart)delegate
{
OnPropertyChanged("Name");
});
You should leave your existing "OnPropertyChanged("Name");" at the bottom of the function just add the above line to the block where you are cancelling
EDIT: The following code works I have tested it
public string Newtext
{
get
{
return this._newtext;
}
set
{
if (MessageBox.Show("Apply?", "", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
{
this._newtext = value;
this.OnPropertyChanged("Newtext"); //Ignored
}
else
{
Dispatcher.CurrentDispatcher.Invoke((ThreadStart)delegate
{
OnPropertyChanged("Newtext");
});
}
}
}

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>

Siliverlight databound combobox doesn't display initialized value

I am databinding a view to a viewmodel and am having trouble initializing a combobox to a default value. A simplification of the class I'm using in the binding is
public class LanguageDetails
{
public string Code { get; set; }
public string Name { get; set; }
public string EnglishName { get; set; }
public string DisplayName
{
get
{
if (this.Name == this.EnglishName)
{
return this.Name;
}
return String.Format("{0} ({1})", this.Name, this.EnglishName);
}
}
}
The combobox is declared in the view's XAML as
<ComboBox x:Name="LanguageSelector" Grid.Row="0" Grid.Column="1"
SelectedItem="{Binding SelectedLanguage,Mode=TwoWay}"
ItemsSource="{Binding AvailableLanguages}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
and the viewmodel contains this code
private List<LanguageDetails> _availableLanguages;
private LanguageDetails _selectedLanguage;
public LoginViewModel()
{
_availableLanguages = LanguageManager.GetLanguageDetailsForSet(BaseApp.AppLanguageSetID);
_selectedLanguage = _availableLanguages.SingleOrDefault(l => l.Code == "en");
}
public LanguageDetails SelectedLanguage
{
get { return _selectedLanguage; }
set
{
_selectedLanguage = value;
OnPropertyChanged("SelectedLanguage");
}
}
public List<LanguageDetails> AvailableLanguages
{
get { return _availableLanguages; }
set
{
_availableLanguages = value;
OnPropertyChanged("AvailableLanguages");
}
}
At the end of the constructor both _availableLanguages and _selectedLanguage variables are set as expected, the combobox's pulldown list contains all items in _availableLanguages but the selected value is not displayed in the combobox. Selecting an item from the pulldown correctly displays it and sets the SelectedLanguage property in the viewmodel. A breakpoint in the setter reveals that _selectedLanguage still contains what it was initialized to until it is overwritten with value.
I suspect that there is some little thing I'm missing, but after trying various things and much googling I'm still stumped. I could achieve the desired result in other ways but really want to get a handle on the proper use of databinding.
You need to change the order of you bindings in XAML so that your ItemsSource binds before the SelectedItem.
<ComboBox x:Name="LanguageSelector" Width="100"
ItemsSource="{Binding AvailableLanguages}"
SelectedItem="{Binding SelectedLanguage,Mode=TwoWay}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
If you set a breakpoint on the 'get' of both the SeletedLanguage and AvailibleLanguage, you will notice that the SelectedLanguage gets hit before your AvailibleLanguage. Since that's happening, it's unable to set the SelectedLanguage because the ItemsSource is not yet populated. Changing the order of the bindings in your XAML will make the AvailibleLanguages get hit first, then the SelectedLanguage. This should solve your problem.
1) When you assign the SelectedLanguage, use the public property SelectedLanguage instead of the private _selectedLanguage, so that the setter gets executed,
2) You need to move the assignment of the selectedlanguage to the moment that the view has been loaded. You can do it by implementing the Loaded event handler on the View. If you want to be "mvvm compliant" then you should use a Blend behavior that will map UI loaded event to a viewmodel command implementation in which you would set the selected language.

Resources