How to bind combobox events to viewmodel with ICommand - c#

I am relatively new to MVVM and I want to bind my view to the view model. I have a lot of code to move from the CodeBehind into the ViewModel class.
What I would like to do is binding the ComboBox Events to the corresponding ViewModel ICommand methods. I want the ComboBox to show "CompanyB" when the view loads and when I make a selection, the ComboBox should give me "CompanyA", "CompanyB" and "CompanyC" as options to select from.
After a company was selected, the values of the 2 textboxes below
Nachbest.Empf_Ansprechpartner
Nachbest.Empfaenger_Mail
must change accordingly.
The problem is with my code both the ComboBox and the textboxes remain empty and there is also nothing to choose from inside the combobox.
Could you please help me find what I am missing here? Thanks in advance for any help!
XAML (neueNachbestellung.xaml):
<Window xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<Grid>
<StackPanel Grid.Column="0" Margin="25,25,0,0" x:Name="leftStPnl">
<ComboBox x:Name="cboxEmpfaenger"
ItemsSource="{Binding Empf}"
Text="{Binding Empfaenger}"
FontSize="12" Width="150" Margin="118,0,0,0"
SelectedItem="{Binding SelValue}">
</ComboBox>
<TextBox x:Name="txtEmpfAnsprechpartner" Text="{Binding Empf_Ansprechpartner}" FontSize="12" IsEnabled="False" Width="150" Margin="50,0,0,0"/>
<TextBox x:Name="txtEmpfMail" Text="{Binding Empfaenger_Mail}" FontSize="12" IsEnabled="False" Width="150" Margin="73,0,0,0"/>
</StackPanel>
</Grid>
</Window>
Code Behind (neueNachbestellung.xaml.cs):
public neueNachbestellung(string someId)
{
InitializeComponent();
this.DataContext = new neueNachbestellungViewModel(someId);
}
View Model(neueNachbestellungViewModel.cs):
public class neueNachbestellungViewModel: INotifyPropertyChanged
{
public ICommand LoadCombobox => new DelegateCommand<object>(ExecuteLoadCombobox);
public ICommand ComboboxSelectionChanged => new DelegateCommand<object>(ExecuteComboboxSelectionChanged);
public Nachbestellung Nachbest { get; set; }
private object someObject;
private ObservableCollection<string> _empf;
public ObservableCollection<string> Empf
{
get { return _empf; }
set
{
_empf = value;
OnPropertyChanged("Empf");
}
}
private string _selValue = "12";
public string SelValue
{
get { return _selValue; }
set
{
_selValue = value;
OnPropertyChanged("SelValue");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public neueNachbestellungViewModel(string id)
{
this.Artikel = new ArtikelViewModel();
this.ArtikelList = new ObservableCollection<Artikel>();
InitializeReorderModel(id);
ExecuteComboboxSelectionChanged(someObject);
}
public void InitializeReorderModel(string id)
{
//set the MODEL
this.Nachbest = new Nachbestellung();
//Retrieve and set some values on *VIEW LOAD*!
var dbOracle = new Datenbank();
this.Nachbest.Bv = dbOracle.GetBauvorhaben(hv);
this.Nachbest.Hv = hv;
this.Nachbest.Bauleiter = dbOracle.GetBauleiter(hv);
this.Nachbest.Projektleiter = dbOracle.GetProjektleiter(hv);
}
private void ExecuteLoadCombobox(object param)
{
Empf = new ObservableCollection<string>()
{
"CompanyA",
"CompanyB",
"CompanyC"
};
//Company B is the standard selection on combobox load
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
}
private void ExecuteComboboxSelectionChanged(object param)
{
Empf = new ObservableCollection<string>()
{
"CompanyA",
"CompanyB",
"CompanyC"
};
switch (SelValue)
{
case "CompanyA":
{
Nachbest.Empf_Ansprechpartner = "CompanyA";
Nachbest.Empfaenger_Mail = "service#companyA.com";
}
break;
case "CompanyB":
{
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
}
break;
case "CompanyC":
{
Nachbest.Empf_Ansprechpartner = "CompanyC";
Nachbest.Empfaenger_Mail = "info#companyC.com";
}
break;
default:
MessageBox.Show("Something went wrong with the company selection!");
break;
}
}
}
View Fragment:

This is my quick & dirty solution. It does what it needs to and I don't have these click_button, selection_changed events inside my code behind anymore but inside my view model. That is all I need for now. Obviously not an elegant solution but it is working. I hope I can help some developers with it in the future who run into similar problems. Just a side note: The ICommand properties inside the view model are not necessary in this scenario but I am using them to handle button click events in the view. You can replace them with your own properties if you don't need the DelegateCommand class in your application.
XAML (neueNachbestellung.xaml):
<Window>
<Grid>
<StackPanel Grid.Column="0" Margin="25,25,0,0" x:Name="leftStPnl">
<ComboBox x:Name="cboxEmpfaenger"
ItemsSource="{Binding Empf}"
Text="{Binding Empfaenger}"
FontSize="12" Width="150" Margin="118,0,0,0"
SelectedItem="{Binding SelValue}">
</ComboBox>
<TextBox x:Name="txtEmpfAnsprechpartner" DataContext="{Binding Nachbest}" Text="{Binding Empf_Ansprechpartner}" FontSize="12" IsEnabled="False" Width="150" Margin="50,0,0,0"/>
<TextBox x:Name="txtEmpfMail" DataContext="{Binding Nachbest}" Text="{Binding Empfaenger_Mail}" FontSize="12" IsEnabled="False" Width="150" Margin="73,0,0,0"/>
</StackPanel>
</Grid>
</Window>
Code Behind (neueNachbestellung.xaml.cs):
public neueNachbestellung(string someId)
{
InitializeComponent();
this.DataContext = new neueNachbestellungViewModel(someId);
}
neueNachbestellungViewModel.cs:
public class neueNachbestellungViewModel: INotifyPropertyChanged
{
//public ICommand LoadCombobox => new DelegateCommand<object>(ExecuteLoadCombobox);
public ICommand ComboboxSelectionChanged => new DelegateCommand<object>(ExecuteComboboxSelectionChanged);
public Nachbestellung Nachbest { get; set; }
private object someObject; //DelegateCommand.cs requires an argument
private ObservableCollection<string> _empf;
public ObservableCollection<string> Empf
{
get { return _empf; }
set
{
_empf = value;
OnPropertyChanged("Empf");
}
}
private string _selValue = "CompanyB"; //default value
public string SelValue
{
get { return _selValue; }
set
{
_selValue = value;
OnPropertyChanged("SelValue");
switch (SelValue)
{
case "CompanyA":
{
Nachbest.Empf_Ansprechpartner = "CompanyA";
Nachbest.Empfaenger_Mail = "service#companyA.com";
}
break;
case "CompanyB":
{
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
}
break;
case "CompanyC":
{
Nachbest.Empf_Ansprechpartner = "CompanyC";
Nachbest.Empfaenger_Mail = "info#companyC.com";
}
break;
default:
MessageBox.Show("Something went wrong with the company selection!");
break;
}
//setting the Empfaenger property here with the current selected value is necessary for the database insert later on!
Nachbest.Empfaenger = SelValue;
}
}
public event PropertyChangedEventHandler PropertyChanged;
public virtual void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public neueNachbestellungViewModel(string id)
{
this.Artikel = new ArtikelViewModel();
this.ArtikelList = new ObservableCollection<Artikel>();
InitializeReorderModel(id);
ExecuteComboboxSelectionChanged(someObject);
}
public void InitializeReorderModel(string id)
{
//set the MODEL
this.Nachbest = new Nachbestellung();
//Retrieve and set some values on *VIEW LOAD*!
var dbOracle = new Datenbank();
this.Nachbest.Bv = dbOracle.GetBauvorhaben(hv);
this.Nachbest.Hv = hv;
this.Nachbest.Bauleiter = dbOracle.GetBauleiter(hv);
this.Nachbest.Projektleiter = dbOracle.GetProjektleiter(hv);
}
private void ExecuteComboboxSelectionChanged(object param)
{
Empf = new ObservableCollection<string>()
{
"CompanyA",
"CompanyB",
"CompanyC"
};
Nachbest.Empf_Ansprechpartner = "CompanyB";
Nachbest.Empfaenger_Mail = "orders#companyB.com";
Nachbest.Empfaenger = SelValue; //if this is left out and there is no selection (just the default remaining unchanged!), Nachbest.Empfaenger will be null!
}
}

Related

Get checked items from a listbox

I'm just getting used to MVVM and want to do without the code-behind and define everything in the view-models.
the combobox represents several selection options (works). I would like to query the elements that have been checked.
Unfortunately I can't access them. The textbox should display all selected elements as concatenated string.
View-Model
class MainViewModel : BaseViewModel
{
#region Fields
private ObservableCollection<EssayTypeViewModel> _essayTypes;
private EssayTypeViewModel _selectedEssayTypes;
#endregion
public ObservableCollection<EssayTypeViewModel> EssayTypes
{
get => _essayTypes;
set
{
if (_essayTypes == value) return;
_essayTypes = value; OnPropertyChanged("EssayTypes");
}
}
public EssayTypeViewModel SelectedEssayTypes
{
get => _selectedEssayTypes;
set { _selectedEssayTypes = value; OnPropertyChanged("SelectedEssayTypes"); }
}
public MainViewModel()
{
// Load Essay Types
EssayTypeRepository essayTypeRepository = new EssayTypeRepository();
var essayTypes = essayTypeRepository.GetEssayTypes();
var essayTypeViewModels = essayTypes.Select(m => new EssayTypeViewModel()
{
Text = m.Text
});
EssayTypes = new ObservableCollection<EssayTypeViewModel>(essayTypeViewModels);
}
}
XAML
<ListBox x:Name="Listitems" SelectionMode="Multiple" Height="75" Width="200" ItemsSource="{Binding EssayTypes}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Text}" IsChecked="{Binding Checked}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Text="{Binding Path=SelectedEssayTypes}" Grid.Column="0" Width="160" Height="25" Margin="0,140,0,0"/>
You could hook up an event handler to the PropertyChanged event of all EssayTypeViewModel objects in the EssayTypes collection and raise the PropertyChanged event for a read-only property of the MainViewModel that returns all selected elements as concatenated string:
public MainViewModel()
{
// Load Essay Types
EssayTypeRepository essayTypeRepository = new EssayTypeRepository();
var essayTypes = essayTypeRepository.GetEssayTypes();
var essayTypeViewModels = essayTypes.Select(m =>
{
var vm = EssayTypeViewModel()
{
Text = m.Text
};
vm.PropertyChanged += OnPropertyChanged;
return vm;
});
EssayTypes = new ObservableCollection<EssayTypeViewModel>(essayTypeViewModels);
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Checked")
OnPropertyChanged("SelectedItems");
}
public string SelectedItems => string.Join(",", EssayTypes.Where(x => x.Checked).ToArray());
This requires the EssayTypeViewModel class to implement the INotifyPropertyChanged interface (by for example deriving from your BaseViewModel class).
You can apply Mode = Two way on the checkbox binding.
<CheckBox Content="{Binding Text}" IsChecked="{Binding Checked, Mode=TwoWay}"/>
then you can iterate through the essay types collection to check if the item entry was checked.
For ex. Sample code can be:
foreach (var essayTypeInstance in EssayTypes)
{
if(essayTypeInstance.Checked)
{
// this value is selected
}
}
Hope this helps.
mm8 answer works. In the meantime i came up with another approach. Not 100% MVVM compatible but it works and is quite simple.
XAML
<ListBox x:Name="ListItems" SelectionMode="Multiple" Height="75" Width="200" ItemsSource="{Binding CollectionOfItems}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}" IsChecked="{Binding Checked, Mode=TwoWay}" Unchecked="GetCheckedElements" Checked="GetCheckedElements" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox Text="{Binding SelectedItemsString, UpdateSourceTrigger=PropertyChanged}" Grid.Column="0" Width="160" Height="25" Margin="0,140,0,0"/>
Code Behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
private void GetCheckedElements(object sender, RoutedEventArgs e)
{
(DataContext as MainViewModel)?.FindCheckedItems();
(DataContext as MainViewModel)?.ConcatSelectedElements();
}
}
Model
public class Items
{
public bool Checked { get; set; }
public string Name { get; set; }
}
ItemsViewModel (BaseViewModel only implements INotifyPropertyChanged)
class ItemsViewModel : BaseViewModel
{
private bool _checked;
private string _name;
public bool Checked
{
get => _checked;
set
{
if (value == _checked) return;
_checked = value;
OnPropertyChanged("Checked");
}
}
public string Name
{
get => _name;
set
{
if (value == _name) return;
_name = value;
OnPropertyChanged("Name");
}
}
}
MainViewModel
public class MainViewModel : BaseViewModel
{
private string _selectedItemsString;
private ObservableCollection<Items> _selectedItems;
public ObservableCollection<Items> CollectionOfItems { get; set; }
public ObservableCollection<Items> SelectedItems
{
get => _selectedItems;
set
{
_selectedItems = value;
OnPropertyChanged("SelectedItems");
}
}
public string SelectedItemsString
{
get => _selectedItemsString;
set
{
if (value == _selectedItemsString) return;
_selectedItemsString = value;
OnPropertyChanged("SelectedItemsString");
}
}
public MainViewModel()
{
CollectionOfItems = new ObservableCollection<Items>();
SelectedItems = new ObservableCollection<Items>();
CollectionOfItems.Add(new Items { Checked = false, Name = "Item 1" });
CollectionOfItems.Add(new Items { Checked = false, Name = "Item 2" });
CollectionOfItems.Add(new Items { Checked = false, Name = "Item 3" });
}
public void FindCheckedItems()
{
CollectionOfItems.Where(x => x.Checked).ToList().ForEach(y => SelectedItems.Add(y));
}
public void ConcatSelectedElements()
{
SelectedItemsString = string.Join(", ", CollectionOfItems.Where(x => x.Checked).ToList().Select(x => x.Name)).Trim();
}
}

How to prevent all buttons text in a listview from changing xamarin forms

I am wondering if someone could please help me or point me in the right direction. I have a Listview that binds to a Viewmodel , This listview has a label and a button . The listview is populated with music. When i press on the play button all the buttons that are populated with name of song in the listview has their name changed to stop , How do i prevent that from happening. Please find code below.
public class MusicViewModel : INotifyPropertyChanged
{
public MusicViewModel()
{
GetMusic();
CommandText = "Play";
}
public List<AudioModel> _audioList;
public List<AudioModel> AudioList
{
get { return _audioList; }
set
{
_audioList = value;
OnPropertyChanged();
}
}
async void GetMusic()
{
var audioService = new AudioServices();
AudioList = await audioService.GetAudioAsync();
}
private string _commandText;
public string CommandText
{
get { return _commandText; }
set
{
_commandText = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("CommandText"));
}
}
public ICommand _playCommand;
public ICommand PlayCommand
{
get
{
return _playCommand ?? (_playCommand = new Command((obj) =>
{
var item = (obj as AudioModel);
var id = item.souID;
if (CommandText == "Play")
{
CrossMediaManager.Current.Play("http://Example.co.za/Example.asp?fldPRK=souID&PRKvalue=" + id + "&fldBLOB=sousound&TableName=Sounds_Sound_Details&ACT=BLOB&width=250&square=yes", MediaFileType.Audio);
CommandText = "Stop";
}
else if (CommandText == "Stop")
{
CrossMediaManager.Current.Stop();
CommandText = "Play";
}
}));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<ListView ItemsSource="{Binding AudioList}" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid x:Name="Item">
<StackLayout>
<Label Text="{Binding souName}" />
<Button Text="{Binding Source={x:Reference Name=RINGTONE},Path=BindingContext.CommandText}"
Command="{Binding Source={x:Reference Name=RINGTONE},Path=BindingContext.PlayCommand}"
CommandParameter="{Binding Source={Reference Item},Path=BindingContext}"/>
</StackLayout>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
You are binding each item to the same, shared command in the MusicViewModel. That is why all items are updated when you change it.
What you probably want is to add the command to the AudioModel. That way it will only update for that specific entry.

Cannot update ListView using ObservableCollection methods via a derived class

There are two views, the first view contains a ListView along with 2 buttons for adding and removing a person. View 2 shows the selected view by using a ContentControl, when the Add button is clicked it shows a form with the name, gender, …, and a button to store the information and display the person name in the ListView.
When I try to remove a person from the ListView it works since the button is within the same view/context of the ListView. But when I call the Add method via AddViewModel it does not update the UI.
Below it is available the relevant parts code of the different classes.
View sample
View1.xaml
<Window.Resources>
<vm:ViewModelBase x:Key="ViewModel"/>
<DataTemplate x:Name="addViewTemplate" DataType="{x:Type vm:AddViewModel}">
<views:AddView/>
</DataTemplate>
</Window.Resources>
<Button Command="{Binding change2addViewCommand,
Source={StaticResource ViewModel}}">
<materialDesign:PackIcon Kind="Plus" Width="12"/>
</Button>
<Button Command="{Binding removeFromListCommand, Source={StaticResource ViewModel}}"
CommandParameter="{Binding ElementName=lvNames, Path=SelectedItem}">
<materialDesign:PackIcon Kind="Delete" Width="12"/>
</Button>
<ListView MinHeight="560"
DataContext="{Binding Source={StaticResource ViewModel}}"
ItemsSource="{Binding}"
x:Name="lvNames" >
</ListView>
<ContentControl x:Name="controllerViews" Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="4"
Grid.RowSpan="5" Content="{Binding CurrentView, Mode=TwoWay}"/>
ViewModelBase.cs
public class ViewModelBase: ObservableCollection<Person>, INotifyPropertyChanged
{
private ViewModelBase currentView;
public ViewModelBase CurrentView
{
get
{
return currentView;
}
set
{
currentView = value;
OnPropertyChanged("CurrentView");
}
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ViewModelBase()
{
for (int i = 1; i <= 2; i++)
{
Add(new Person()
{
Name = "Person" + i,
Age = i,
Gender = Gender.Female,
Comments = "",
Photo_Path = ""
});
}
change2addViewCommand = new RelayCommand(ExecuteAddCommand, CanExectuteAddCommand);
removeFromListCommand = new RelayCommand(ExecuteRemoveCommand, CanExectuteRemoveCommand);
}
public event PropertyChangedEventHandler PropertyChanged;
public bool CanExectuteAddCommand(object param)
{
return true;
}
public void ExecuteAddCommand(object param)
{
CurrentView = new AddViewModel();
}
public bool CanExectuteRemoveCommand(object param)
{
return true;
}
public void ExecuteRemoveCommand(object param)
{
Person player = param as Person;
Remove(player); //Working
}
protected void AddToListView(Person player)
{
Add(player) // Not Working
}
}
}
AddViewModel.cs
public class AddViewModel: ViewModelBase
{
public RelayCommand addViewCheckCommand { get; set; }
public AddViewModel()
{
addViewCheckCommand = new RelayCommand(ExecuteCheckCommand, CanExecuteCheckCommand);
}
private bool CanExecuteCheckCommand(object param)
{
return true;
}
private void ExecuteCheckCommand(object param)
{
BocciaPlayer player = param as Person;
AddToListView(player); // Inherited method
}
}

Binding multi listbox itemsouce with 1 ObserverableCollection of usercontrol

I have two listbox define below:
<ListBox x:Name="RemoteListBox" HorizontalAlignment="Right" Margin="0,88.5,8,0"
Width="382.5"
HorizontalContentAlignment="Stretch"
ItemsSource ="{Binding RemoteItemsList}"
SelectedIndex="0">
</ListBox>
<ListBox x:Name="LibraryListBox"
Margin="4.5,88.5,437,0"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding LibraryItemsList}"
SelectedIndex="0">
</ListBox>
My viewmodel
private ObservableCollection<MotionTitleItem> _remoteItemsList;
public ObservableCollection<MotionTitleItem> RemoteItemsList
{
get { return _remoteItemsList; }
set
{
_remoteItemsList = value;
NotifyPropertyChanged("RemoteItemsList");
}
}
private ObservableCollection<MotionTitleItem> _libraryItemsList
public ObservableCollection<MotionTitleItem> LibraryItemsList
{
get { return _libraryItemsList; }
set
{
_libraryItemsList = value;
NotifyPropertyChanged("LibraryItemsList");
}
}
I bind two ListBox ItemSource with a ObserverableCollection define below:
var listMotion = new ObservableCollection<MotionTitleItem>();
foreach (MotionInfo info in listMotionInfo)
{
var motionTitleItem = new MotionTitleItem();
listMotion.Add(motionTitleItem);
}
viewModel.RemoteItemsList = listMotion;
viewModel.LibraryItemsList = listMotion;
MotionTitleItem is a custom user control.
My problem is only the first ListBox with ItemSource binding with RemoteListItem displays the Item in UI, the other doest not.
If I bind two ListBox ItemSource with 2 ObserverableCollection, the problem solved:
var listMotion = new ObservableCollection<MotionTitleItem>();
var listMotion2 = new ObservableCollection<MotionTitleItem>();
foreach (MotionInfo info in listMotionInfo)
{
var motionTitleItem = new MotionTitleItem();
listMotion.Add(motionTitleItem);
var motionTitleItem2 = new MotionTitleItem();
listMotion2.Add(motionTitleItem2);
}
viewModel.RemoteItemsList = listMotion;
viewModel.LibraryItemsList = listMotion2;
Could someone explain to me where is the point of the first scenario problem?
I don't know why you used two temporary list for this. You can directly add items to your Observable collection. Try this :
foreach (MotionInfo info in listMotionInfo)
{
viewModel.RemoteItemsList.Add(info);
viewModel.LibraryItemsList.Add(info);
}
Below, I tried to create the solution for you.
I assumed the model MotionTitleItem.
public class MotionTitleItem
{
string _name = string.Empty;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
try
{
PropertyChangedEventHandler eventHandler = this.PropertyChanged;
if (null == eventHandler)
return;
else
{
var e = new PropertyChangedEventArgs(propertyName);
eventHandler(this, e);
}
}
catch (Exception)
{
throw;
}
}
}
My view model for this application is:
public class MotionTitleItemViewModel : INotifyPropertyChanged
{
ObservableCollection<MotionTitleItem> _remoteItemsList = new ObservableCollection<MotionTitleItem>();
public ObservableCollection<MotionTitleItem> RemoteItemsList
{
get { return _remoteItemsList; }
set { _remoteItemsList = value; }
}
ObservableCollection<MotionTitleItem> _libraryItemsList = new ObservableCollection<MotionTitleItem>();
public ObservableCollection<MotionTitleItem> LibraryItemsList
{
get { return _libraryItemsList; }
set { _libraryItemsList = value; }
}
public MotionTitleItemViewModel()
{
MotionTitleItem motion;
for (int i = 0; i < 10; i++)
{
motion = new MotionTitleItem();
motion.Name = "Name " + i.ToString();
this.LibraryItemsList.Add(motion);
this.RemoteItemsList.Add(motion);
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
try
{
PropertyChangedEventHandler eventHandler = this.PropertyChanged;
if (null == eventHandler)
return;
else
{
var e = new PropertyChangedEventArgs(propertyName);
eventHandler(this, e);
}
}
catch (Exception)
{
throw;
}
} }
My View is :
<Window x:Class="WPFExperiments.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox x:Name="RemoteListBox" HorizontalAlignment="Right" Margin="0,0.5,8,0"
Width="382.5"
HorizontalContentAlignment="Stretch"
ItemsSource ="{Binding RemoteItemsList}"
SelectedIndex="0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<ListBox x:Name="LibraryListBox"
Margin="4.5,0.5,437,0"
HorizontalContentAlignment="Stretch"
ItemsSource="{Binding LibraryItemsList}"
SelectedIndex="0">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
In code behind of this window i set DataContext to view model.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MotionTitleItemViewModel();
}}
This code is working for me.
Here is screenshot of the output.
Vote this answer if you find it useful.
Have fun!

Can't able to perform button click and combo box selection changed in WinRT MVVM

UPDATE 1 : You can download the sample project from here.
Can you please help me to find the error in my code. I can't able to assign item source to combo box as well as button click event in WinRT app. I am using MVVM and MetroEventToCommand. I am new to MVVM concept, so please answer my silly question.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Button Content="Click Here">
<mvvm:EventToCommandManager.Collection>
<mvvm:EventToCommand Command="{Binding ButtonClickCommand}" Event="Click"/>
</mvvm:EventToCommandManager.Collection>
</Button>
<ComboBox x:Name="FontsCombo" Height="50" Width="150" SelectedItem="{Binding SelectedFont}" ItemsSource="{Binding fonts}" />
<TextBlock FontSize="30" Text="{Binding SelectedFont}"/>
</Grid>
public MainPage()
{
this.InitializeComponent();
this.DataContext = new VM();
}
public class VM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public RelayCommand ButtonClickCommand { get; set; }
private ObservableCollection<string> _fonts = new ObservableCollection<string>();
public ObservableCollection<string> fonts
{
get { return _fonts; }
set
{
_fonts = value;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("fonts"));
}
}
}
private string _SelectedFont = "";
public string SelectedFont
{
get { return _SelectedFont; }
set
{
// Some logic here
_SelectedFont = value;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelectedFont"));
}
}
}
public VM()
{
fonts.Add("Arial");
fonts.Add("Courier New");
fonts.Add("Times New Roman");
ButtonClickCommand = new RelayCommand(Click);
}
private void Click()
{
new Action(async () => await new Windows.UI.Popups.MessageDialog("Testing dialog").ShowAsync()).Invoke();
}
}
For the SelectedItem, you didn't specify the Mode=TwoWay :
<ComboBox x:Name="FontsCombo" Height="50" Width="150" SelectedItem="{Binding SelectedFont, Mode=TwoWay}" ItemsSource="{Binding fonts}" />
EDIT
I found the solution :
public class VM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public RelayCommand ButtonClickCommand { get; set; }
private ObservableCollection<string> _fonts;
public ObservableCollection<string> fonts
{
get { return _fonts; }
set
{
_fonts = value;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("fonts"));
}
}
}
private string _SelectedFont;
public string SelectedFont
{
get { return _SelectedFont; }
set
{
// Some logic here
_SelectedFont = value;
if (null != PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("SelectedFont"));
}
}
}
public VM()
{
this.fonts = new ObservableCollection<string>();
fonts.Add("Arial");
fonts.Add("Courier New");
fonts.Add("Times New Roman");
ButtonClickCommand = new RelayCommand(Click);
}
private void Click()
{
new Action(async () => await new Windows.UI.Popups.MessageDialog("Testing dialog").ShowAsync()).Invoke();
}
}
If I instance fonts in the constructor, the UX is not freezing anymore.

Categories

Resources