My Problem, I can't remove list in my listbox from browser, but when i debug in my code data list has removed.
View Model
private List<Customer> _listCustomer = new List<Customer>();
public List<Customers> ListCustomers
{
get { return _listCustomers; }
set { _listCustomers = value; OnPropertyChanged("ListCustomers"); }
}
private ICommand _removeCommand;
public ICommand RemoveCommand
{
get { return _removeCommand ?? (_removeCommand = new RelayCommand(param => ButtonRemoveCustomer(), null)); }
set { OnPropertyChanged("ListCustomers"); }
}
private void ButtonRemoveCustomer()
{
ListCustomers.Remove(this.SelectCustomer);
this.SelectCustomer = null;
}
My View
<Intersoft:UXListBox x:Name="CustData" Width="200" MaxHeight="500" SelectedItem="{Binding SelectCustomer, Mode=TwoWay}"
ItemsSource="{Binding ListCustomers, Mode=TwoWay}" ItemTemplate="{StaticResource DataListTemplate}"
VerticalScrollBarVisibility ="Visible" HorizontalScrollBarVisibility="Visible"/>
<Intersoft:UXButton Content="Remove List" Command="{Binding RemoveCommand, Mode=TwoWay}" Width="100"/>
How to fix my code ??
private void ButtonRemoveCustomer()
{
ListCustomers.Remove(this.SelectCustomer);
OnPropertyChanged("ListCustomers");
this.SelectCustomer=null;
}
Related
This is my service in MVVM. The data is added to the list and can see it in debugger but just before showing it on UI Presentation it did not show. i had applied two way binding and have use DataGridView. its showing data on the LoadData function but not loading. i am starter to the WPF
public EmployeeViewModel()
{
CurrentEmployee = new Employee();
objEmployeeService = new EmployeeService();
saveCommand = new RelayCommand(Save);
LoadData();
}
private void LoadData()
{
obj_Employee = new ObservableCollection<Employee>(objEmployeeService.GetAllEmployees());
}
#endregion
#region AddEmployee
private Employee currentEmployee;
private string message;
public string Message { get { return message; } set { message = value; OnPropertyChanged("Message"); } }
public Employee CurrentEmployee
{
get { return currentEmployee; }
set { currentEmployee = value; OnPropertyChanged("CurrentEmployee"); }
}
private RelayCommand saveCommand;
public RelayCommand SaveCommand
{
get { return saveCommand; }
}
public void Save()
{
bool IsSaved=false;
try
{
IsSaved = objEmployeeService.Add(CurrentEmployee);
LoadData();
}
catch (Exception ex)
{
Message = ex.Message;
}
if (IsSaved)
Message = "Employee Saved";
}
Here is my UI
<DataGrid x:Name="dgridEmployees"
AutoGenerateColumns="False"
Grid.Row="6"
Grid.Column="1"
Margin="3"
ItemsSource="{Binding Path = Employees, Mode=TwoWay}"
>
<DataGrid.Columns>
<DataGridTextColumn Header="EmployeeID"
Width="auto"
Binding=
"{Binding Path=Id}"></DataGridTextColumn>
<DataGridTextColumn Header="Employee Name"
Width="auto"
Binding=
"{Binding Path=Name}"></DataGridTextColumn>
<DataGridTextColumn Header="EmployeeAge"
Width="auto"
Binding=
"{Binding Path=Age}"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
It does not appear that this binding goes anywhere...what is Employees>
ItemsSource="{Binding Path = Employees, Mode=TwoWay}"
You only show obj_Employee being set. Maybe bind to that?
As to a re-load, ...sometimes the control needs to be signaled to announce a change after an initial bind. This is sometimes done by setting the initial binding target to null first, and then set to the new reference. Add this into your load:
obj_Employee = null;
obj_Employee = new ObservableCollection<Employee>(objEmployeeService.GetAllEmployees());
I have a ListBox containing Name. Now I need to select multiple items from ListBox.
ViewModel.CS
private Person selectedListOfPeople_;
public Person SelectedListOfPeople
{
get
{ return selectedListOfPeople_;}
set
{ this.SetProperty(ref selectedListOfPeople_, value, nameof(SelectedListOfPeople));}
}
private ObservableCollection<Person> listOfPeople_;
public ObservableCollection<Person> ListOfPeople
{
get { return listOfPeople_; }
set
{
this.SetProperty(ref listOfPeople_, value, nameof(ListOfPeople));
}
}
public ShellViewModel()
{
ListOfPeople = new ObservableCollection<Person>
{
new Person("ABC"),new Person("DEF"),new Person("GHI"),new Person("JKL")
};
}
public class Person : Screen
{
private string personName_;
public string PersonName
{
get { return personName_; }
set { this.SetProperty(ref personName_, value, nameof(PersonName)); }
}
public Person(string personName)
{
PersonName = personName;
}
private bool isSelected_;
public bool IsSelected
{
get { return isSelected_; }
set { this.SetProperty(ref isSelected_, value, nameof(IsSelected)); }
}
}
View.XAML
<Grid Width="500" Height="500" Background="LightBlue">
<ListBox x:Name="ListOfPeople" SelectionMode="Multiple" Height="300" Width="300" Margin="120,100,80,100">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding PersonName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
in that SelectedListOfPeople is not called when the second item is selected in ListBox set to Multiple selections. How can I make sure that this event is raised every time the user makes a selection in ListBox?
One way of doing this would be to break from the convention available in that framework and bind the property manually.
But first you would need to update the property for multiselect in the view model
private ObservableCollection<Person> selectedListOfPeople;
public ObservableCollection<Person> SelectedListOfPeople {
get { return selectedListOfPeople; }
set { this.SetProperty(ref selectedListOfPeople, value, nameof(SelectedListOfPeople)); }
}
private ObservableCollection<Person> listOfPeople;
public ObservableCollection<Person> ListOfPeople {
get { return listOfPeople; }
set { this.SetProperty(ref listOfPeople, value, nameof(ListOfPeople)); }
}
public ShellViewModel() {
ListOfPeople = new ObservableCollection<Person> {
new Person("ABC"),
new Person("DEF"),
new Person("GHI"),
new Person("JKL")
};
SelectedListOfPeople = new ObservableCollection<Person>();
}
And then bind to the desired property in the view's XAML
<ListBox x:Name="ListOfPeople" SelectionMode="Multiple"
Height="300" Width="300" Margin="120,100,80,100"
SelectedItems = "{Bining SelectedListOfPeople}"
>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding PersonName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
The convention will bind the items source or the ListBox and the manual binding of the SelectedItems will provided the desired behavior.
Goal is to have multiple Combobox, once the item is selected in any of the Combobox, it should be removed or hided from other Comboboxes for selection.
I'm able to change the source whenever the selection got changed on any of the Comboboxes. But Problem is when I remove the selected item from the ItemsSource, item got removed from all the sources including the one on which I selected.
Here is the sample
xaml
<StackPanel>
<ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
<ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
<ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
<ComboBox Width="100" Height="50" SelectedItem="{Binding SelectedItem}" ItemsSource="{Binding ComboboxItems}" />
</StackPanel>
Codebehind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObservableCollection<string> s = new ObservableCollection<string>();
s.Add("item1");
s.Add("item2");
s.Add("item3");
s.Add("item4");
s.Add("item5");
s.Add("item6");
DataContext = new MainViewModel() { ComboboxItems = s , SelectedItem = "item2" };
}
}
public class MainViewModel : INotifyPropertyChanged
{
private ObservableCollection<string> comboboxitems;
public ObservableCollection<string> ComboboxItems
{
get { return comboboxitems; }
set { comboboxitems = value; OnPropertyChanged("ComboboxItem"); }
}
private string _selectedItem;
public string SelectedItem
{
get { return _selectedItem; }
set
{
_selectedItem = value;
comboboxitems.Remove(value); //here removing selected item from itemssource
OnPropertyChanged("SelectedItem");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propname)
{
if(PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propname));
}
}
I know I can have multiple Collection for each Combobox but that may take lot of memory if number of Combobox increases.
Hope, there should be a easy way to achieve this in WPF.
You could define different SelectedItem for each ComboBox, and then create a wrapper of the SharedItemSource for each ComboBoxto filter out the SelectedItem of other ComboBox. eg:
C# :
public IEnumerable<string> ComboboxItems1
{
get
{
return ComboboxItems.Where(x => x != SelectedItem2 && x != SelectedItem3);
}
}
public string SelectedItem1
{
get { return _selectedItem1; }
set
{
if (_selectedItem1 != value)
{
_selectedItem1 = value;
RaisePropertyChanged("SelectedItem1");
RaisePropertyChanged("ComboboxItems2"); //raise propertychanged to refresh GUI
RaisePropertyChanged("ComboboxItems3");
}
}
}
public IEnumerable<string> ComboboxItems2
{
get
{
return ComboboxItems.Where(x => x!=SelectedItem1&&x!=SelectedItem3);
}
}
public string SelectedItem2
{
get { return _selectedItem2; }
set
{
if (_selectedItem2 != value)
{
_selectedItem2 = value;
RaisePropertyChanged("SelectedItem2");
RaisePropertyChanged("ComboboxItems1"); //raise propertychanged to refresh GUI
RaisePropertyChanged("ComboboxItems3");
}
}
}
public IEnumerable<string> ComboboxItems3
{
get
{
return ComboboxItems.Where(x => x != SelectedItem1 && x != SelectedItem2);
}
}
public string SelectedItem3
{
get { return _selectedItem3; }
set
{
if (_selectedItem3 != value)
{
_selectedItem3 = value;
RaisePropertyChanged("SelectedItem3");
RaisePropertyChanged("ComboboxItems1"); //raise propertychanged to refresh GUI
RaisePropertyChanged("ComboboxItems2");
}
}
}
XAML:
<ComboBox SelectedItem="{Binding SelectedItem1}" ItemsSource="{Binding ComboboxItems1}" />
<ComboBox SelectedItem="{Binding SelectedItem2}" ItemsSource="{Binding ComboboxItems2}" />
<ComboBox SelectedItem="{Binding SelectedItem3}" ItemsSource="{Binding ComboboxItems3}" />
I want to pass selected items of listview checkbox in view model, later I will use further process to store in database.
Code in the FormWeek.xaml as
<Window.DataContext>
<Binding Source="{StaticResource Locator}" Path="TaskExecDefModel"></Binding>
</Window.DataContext>
<Window.Resources>
<ResourceDictionary>
<DataTemplate x:Key="ItemDataTemplate">
<CheckBox
x:Name="checkbox"
Content="{Binding}" Command="{Binding CheckBoxCommand}" CommandParameter="{Binding ElementName=checkedListView, Path=SelectedItems}"
IsChecked="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
</DataTemplate>
</ResourceDictionary>
<StackPanel Grid.Column="1" Grid.Row="3" Margin="5">
<CheckBox x:Name="selectAll" Content="Select all" Click="OnSelectAllChanged"/>
<ListView x:Name="checkedListView" SelectionMode="Multiple" ItemsSource="{Binding CollectionOfDays}" DataContext="{Binding}"
ItemTemplate="{StaticResource ItemDataTemplate}" SelectedValue="WorkingDay"
CheckBox.Unchecked="OnUncheckItem" SelectionChanged="SelectDays" SelectedItem="{Binding SelectedItems}">
</ListView>
</StackPanel>
Code in FormWeek.xaml.cs
private void SelectDays(object sender, SelectionChangedEventArgs e)
{
(this.DataContext as TaskExecDefinitionViewModel).OnCheckBoxCommand(checkedListView.SelectedItems,true);
}
My View Model TaskWeek.cs as follows
//Declaration
private RelayCommand<object> _checkBoxCommand;
public ObservableCollection<string> CollectionOfDays { get; set; }
public ObservableCollection<string> SelectedItems { get; set; }
public RelayCommand<object> CheckBoxCommand
{
get
{
if (_checkBoxCommand == null)
{
_checkBoxCommand = new RelayCommand<object>((args) => OnCheckBoxCommand(args,true));
// _checkBoxCommand = new RelayCommand(() => OnCheckBoxCommand(object args));
}
return _checkBoxCommand;
}
}
//Constructor
CollectionOfDays = new ObservableCollection<string>();
//Method
private void GetWeekDays()
{
try
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
CollectionOfDays.Add("Saturday");
CollectionOfDays.Add("Sunday");
CollectionOfDays.Add("Monday");
CollectionOfDays.Add("Tuesday");
CollectionOfDays.Add("Wednesday");
CollectionOfDays.Add("Thursday");
CollectionOfDays.Add("Friday");
}));
}
catch(Exception Ex)
{
MessageBox.Show(Ex.Message, "TaskWeek:GetWeekDays");
}
}
public void OnCheckBoxCommand(object obj, bool _direction)
{
try
{
if (SelectedItems == null)
SelectedItems = new ObservableCollection<string>();
if (obj != null)
{
SelectedItems.Clear();
StringBuilder items = new StringBuilder();
if (_direction)
{
foreach (string item in CollectionOfDays)
{
items.AppendFormat(item + ",");
}
}
MessageBox.Show(items.ToString());
}
else
SelectedItems.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "TaskDefinition:OnCheckBoxCommand");
}
}
And below is button click commond to save the data.
<Button Grid.Column="2" Grid.Row="2" Content="Save" HorizontalAlignment="Center" VerticalAlignment="Bottom"
Command="{Binding InsertExecDefCommand}" Margin="5" >
Now my requirement is to pass selected listview items to view model through command object. I had done this using following code in FormWeek.xam.cs through SelectionChanged event as
private void OnSelectedItems(object sender, RoutedEventArgs e)
{
StringBuilder items = new StringBuilder();
foreach (string item in checkedListView.SelectedItems)
{
items.AppendFormat(item + ",");
}
string AllDays= items.ToString();
}
But please let me know how to achieve this logic through MVVM. How to get selecteditems in my view model TaskWeek.cs
After R&D and google i had done chages through RelayCommand. In OnCheckBoxCommand method foreach statement is wrong it is passing all days. I want to pass only selected listview item. Please suggest me what is wrong in OnCheckBoxCommand method.
Here are my findings;
use this code in code behind of FormWeek.xaml:
private void SelectDays(object sender, SelectionChangedEventArgs e)
{
(this.DataContext as TaskExecDefinitionViewModel).OnCheckBoxCommand(checkedListView.SelectedItems,true);
}
And in 'OnCheckBoxCommand': -
public void OnCheckBoxCommand(object obj, bool _direction)
{
try
{
if (SelectedItems == null) SelectedItems = new ObservableCollection<string>();
if (obj != null)
{
SelectedItems.Clear();
var _list = ((IList)obj).Cast<string>().ToList();
if (_direction)
{
_list.ForEach(item => SelectedItems.Add(item));
}
}
else
SelectedItems.Clear();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "TaskDefinition:OnCheckBoxCommand");
}
}
Have a nice day man.....keep going.
Hi try something like this
<StackPanel Grid.Column="1" Grid.Row="3" Margin="5">
<CheckBox x:Name="selectAll" Content="Select all" Command="{Binding CheckBoxCommand}" CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Mode=Self}}"/>
<ListView x:Name="checkedListView" SelectionMode="Extended" ItemsSource="{Binding CollectionOfDays}" SelectedItem="{Binding SelectedItems}"/>
</StackPanel>
public class MainViewModel
{
public MainViewModel()
{
CollectionOfDays = new ObservableCollection<string>();
SelectedItems = new ObservableCollection<string>();
CollectionOfDays.Add("Saturday");
CollectionOfDays.Add("Sunday");
CollectionOfDays.Add("Monday");
CollectionOfDays.Add("Tuesday");
CollectionOfDays.Add("Wednesday");
CollectionOfDays.Add("Thursday");
CollectionOfDays.Add("Friday");
}
private CommandHandler _checkBoxCommand;
public CommandHandler CheckBoxCommand
{
get
{
return _checkBoxCommand ?? (_checkBoxCommand=new CommandHandler((param)=>OnCheckBoxCommand(param)));
}
}
public ObservableCollection<string> CollectionOfDays { get; set; }
public ObservableCollection<string> SelectedItems {get;set;}
private void OnCheckBoxCommand(object obj)
{
if (obj is bool)
{
if (SelectedItems == null)
SelectedItems = new ObservableCollection<string>();
if ((bool)obj)
{
SelectedItems.Clear();
foreach (var item in CollectionOfDays)
{
SelectedItems.Add(item);
}
}
else
SelectedItems.Clear();
}
}
}
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
I hope this will give you an idea.
I have a treeview which shows a hierarchy of items where each item has a checkbox. I would like to show below the treeview a listbox with all the checked items. How to achieve such functionality using MVVM pattern?
Thanks in advance
Lukasz Glaz
Here's an example:
ViewModel
public class TreeNodeViewModel : ViewModelBase
{
#region Constructors
public TreeNodeViewModel(string text, params TreeNodeViewModel[] nodes)
: this(text, new ObservableCollection<TreeNodeViewModel>(nodes))
{
}
public TreeNodeViewModel(string text, ObservableCollection<TreeNodeViewModel> nodes)
{
Text = text;
Nodes = nodes;
foreach (var node in Nodes)
{
node.Parent = this;
}
Nodes.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(Nodes_CollectionChanged);
}
#endregion
#region Private methods
private void Nodes_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
foreach (var node in e.OldItems.Cast<TreeNodeViewModel>())
{
node.Parent = null;
}
foreach (var node in e.NewItems.Cast<TreeNodeViewModel>())
{
node.Parent = this;
}
OnPropertyChanged("CheckedNodes");
}
private void NotifyParent()
{
if (Parent != null)
{
Parent.OnPropertyChanged("CheckedNodes");
Parent.NotifyParent();
}
}
#endregion
#region Private data
private string _text;
private bool _isChecked;
private TreeNodeViewModel _parent;
#endregion
#region Public properties
public string Text
{
get { return _text; }
set
{
if (value != _text)
{
_text = value;
OnPropertyChanged("Text");
}
}
}
public bool IsChecked
{
get { return _isChecked; }
set
{
if (value != _isChecked)
{
_isChecked = value;
NotifyParent();
OnPropertyChanged("IsChecked");
}
}
}
public ObservableCollection<TreeNodeViewModel> Nodes { get; private set; }
public IEnumerable<TreeNodeViewModel> CheckedNodes
{
get
{
foreach (var node in Nodes)
{
if (node.IsChecked)
yield return node;
foreach (var child in node.CheckedNodes)
{
yield return child;
}
}
}
}
public TreeNodeViewModel Parent
{
get { return _parent; }
private set
{
if (value != _parent)
{
_parent = value;
OnPropertyChanged("Parent");
}
}
}
#endregion
}
XAML
<TreeView Grid.Row="0" ItemsSource="{Binding Nodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Nodes}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}" />
<TextBlock Text="{Binding Text}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<ListBox Grid.Row="1" ItemsSource="{Binding CheckedNodes}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Code-behind
this.DataContext = new TreeNodeViewModel(
null,
new TreeNodeViewModel(
"1",
new TreeNodeViewModel(
"1.1",
new TreeNodeViewModel("1.1.1"),
new TreeNodeViewModel("1.1.2")),
new TreeNodeViewModel("1.2")),
new TreeNodeViewModel(
"2",
new TreeNodeViewModel("2.1"),
new TreeNodeViewModel(
"2.2",
new TreeNodeViewModel("2.2.1"))));
Note that it is a rather naive implementation, it could easily be improved... For instance, the whole list of checked nodes is reevaluated every time a node is checked/unchecked, which could lead to bad performance for a big TreeView