ComboBoxColumn Issue with WPF-MVVM datagrid - c#

I would like to add a ComboBox column in my dataGrid "Product" with the list of Suppliers. But nothing I did works. What is the good way to bind this column?
The Models:
public partial class foodSupplier
{
public foodSupplier()
{
this.products = new HashSet<product>();
}
public int idfoodSupplier { get; set; }
public string supplier { get; set; }
public virtual ICollection<product> products { get; set; }
}
public partial class product
{
public int idproduct { get; set; }
public string #ref { get; set; }
public int supplier { get; set; }
public string refsup { get; set; }
public string description { get; set; }
public int MOQ { get; set; }
public int unit { get; set; }
public decimal priceMOQ { get; set; }
public virtual foodSupplier foodSupplier { get; set; }
public virtual unit unit1 { get; set; }
}
Here my command base (ViewModel):
public class CommandBase<T> :INotifyPropertyChanged
{
#region "INotifyPropertyChanged members"
public event PropertyChangedEventHandler PropertyChanged;
//This routine is called each time a property value has been set.
//This will //cause an event to notify WPF via data-binding that a change has occurred.
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private ObservableCollection<T> collection;
public ObservableCollection<T> Collection
{
get
{
if (collection == null)
{
collection = new ObservableCollection<T>();
}
return collection;
}
set { collection = value; OnPropertyChanged("Collection");}
}
private ICommand getCommand;
private ICommand saveCommand;
private ICommand removeCommand;
public ICommand GetCommand
{
get
{
return getCommand ?? (getCommand = new RelayCommand(param => Get(),param=>CanGet()));
}
}
protected virtual bool CanGet()
{
return true;
}
public ICommand SaveCommand
{
get
{
return saveCommand ?? (saveCommand = new RelayCommand(param => Save()));
}
}
protected virtual bool CanSave()
{
return true;
}
public ICommand DeleteCommand
{
get
{
return removeCommand ?? (removeCommand = new RelayCommand(param=>Delete()));
}
}
protected virtual bool CanDelete()
{
return true;
}
}
Here the ProductViewModel:
public class ProductViewModel : CommandBase<product>
{
public Context ctx = new Context();
protected override void Get()
{
ctx.products.ToList().ForEach(supplier => ctx.products.Local.Add(supplier));
Collection = ctx.products.Local;
}
protected override bool CanGet()
{
return true;
}
protected override void Save()
{
foreach (product item in Collection)
{
if (ctx.Entry(item).State == System.Data.Entity.EntityState.Added)
{
ctx.products.Add(item);
}
}
ctx.SaveChanges();
}
}
}
Here the SupplierViewModel:
public class SupplierViewModel : CommandBase<foodSupplier>
{
public Context ctx = new Context();
protected override void Get()
{
ctx.foodSuppliers.ToList().ForEach(supplier => ctx.foodSuppliers.Local.Add(supplier));
Collection = ctx.foodSuppliers.Local;
}
protected override bool CanGet()
{
return true;
}
protected override void Save()
{
foreach (foodSupplier item in Collection)
{
if (ctx.Entry(item).State == System.Data.Entity.EntityState.Added)
{
ctx.foodSuppliers.Add(item);
}
}
ctx.SaveChanges();
}
}
Here the view:
<Page.Resources>
<vm:ProductViewModel x:Key="product"/>
<vm:SupplierViewModel x:Key="supplier"/>
</Page.Resources>
<Grid DataContext="{Binding Source={StaticResource product}}">
<StackPanel Grid.ColumnSpan="2" Margin="0,0,58,0">
<Button x:Name="BtnDelete"
Content="Delete"
Command="{Binding DeleteCommand}"/>
<Button x:Name="BtnAdd"
Content="Save"
Command="{Binding SaveCommand}"/>
<DataGrid x:Name="dataGrid" Margin="5" ItemsSource="{Binding Collection}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="id" Binding="{Binding idproduct, UpdateSourceTrigger=PropertyChanged}" Visibility="Hidden"/>
<DataGridTextColumn Header="Ref FTHK" Binding="{Binding ref, UpdateSourceTrigger=PropertyChanged}" />
<DataGridComboBoxColumn Header="Supplier" ItemsSource="{Binding Collection, Source={StaticResource supplier}}????" DisplayMemberPath="supplier" SelectedValueBinding="{Binding ????}" SelectedValuePath="idSupplier"/>
<DataGridTextColumn Header="Ref Supplier" Binding="{Binding refsup, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Description" Binding="{Binding description, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="MOQ" Binding="{Binding MOQ, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Unit" Binding="{Binding unit, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Prix/MOQ" Binding="{Binding priceMOQ, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding GetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</DataGrid>
</StackPanel>
</Grid>

you have to load the SupplierCollection same as you did in loading products. I will prefer the on demand concept. Somthing like the code below
public class CommandBase<T> : INotifyPropertyChanged
{
#region "INotifyPropertyChanged members"
public event PropertyChangedEventHandler PropertyChanged;
//This routine is called each time a property value has been set.
//This will //cause an event to notify WPF via data-binding that a change has occurred.
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
private ObservableCollection<T> collection;
public ObservableCollection<T> Collection
{
get
{
if (collection == null)
{
Get();
}
return collection;
}
set { collection = value; OnPropertyChanged("Collection"); }
}
private ICommand getCommand;
private ICommand saveCommand;
private ICommand removeCommand;
public ICommand GetCommand
{
get
{
return getCommand ?? (getCommand = new RelayCommand(Get, CanGet));
}
}
protected virtual bool CanGet()
{
return true;
}
protected virtual void Get()
{
//return true;
}
//public ICommand SaveCommand
//{
// get
// {
// return saveCommand ?? (saveCommand = new RelayCommand(param => Save()));
// }
//}
protected virtual bool CanSave()
{
return true;
}
//public ICommand DeleteCommand
//{
// get
// {
// return removeCommand ?? (removeCommand = new RelayCommand(param => Delete()));
// }
//}
protected virtual bool CanDelete()
{
return true;
}
}
Now you view will look like.
<Page.Resources>
<vm:ProductViewModel x:Key="product"/>
<vm:SupplierViewModel x:Key="supplier"/>
<DataTemplate x:Key="SupplierDataTemplate">
<TextBlock Text="{Binding supplier}"/>
</DataTemplate>
</Page.Resources>
<Grid>
<StackPanel>
<Grid DataContext="{Binding Source={StaticResource product}}" x:Name="ProductGrid">
<StackPanel Grid.ColumnSpan="2" Margin="0,0,58,0">
<Button x:Name="BtnDelete"
Content="Delete"
Command="{Binding DeleteCommand}"/>
<Button x:Name="BtnAdd"
Content="Save"
Command="{Binding SaveCommand}"/>
<DataGrid x:Name="dataGrid" Margin="5" ItemsSource="{Binding Collection}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="id" Binding="{Binding idproduct, UpdateSourceTrigger=PropertyChanged}" Visibility="Hidden"/>
<DataGridTextColumn Header="Ref FTHK" Binding="{Binding ref, UpdateSourceTrigger=PropertyChanged}" />
<DataGridComboBoxColumn Header="Supplier" ItemsSource="{Binding Collection, Source={StaticResource supplier}}"
DisplayMemberPath="supplier"
SelectedValueBinding="{Binding supplier}"/>
<DataGridTextColumn Header="Ref Supplier" Binding="{Binding refsup, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Description" Binding="{Binding description, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="MOQ" Binding="{Binding MOQ, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Unit" Binding="{Binding unit, UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTextColumn Header="Prix/MOQ" Binding="{Binding priceMOQ, UpdateSourceTrigger=PropertyChanged}"/>
</DataGrid.Columns>
<!--<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding GetCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>-->
</DataGrid>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
Hope it helps

Related

Databind ObservableCollection<Object> to DataGrid WPF C#

i have a xaml page in namespace Dca.KnxPanel.View with a Datagrid defined as
<DataGrid Grid.Row="2" Grid.Column="2" Name="GroupAddressDataGrid" ItemsSource="{Binding Source={x:Static viewModel:DcaAppVm._ProjectGroupAddress}}" AutoGenerateColumns="False" Margin="14,0,-14,0" Grid.RowSpan="2" >
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
</Border>
<DataGrid.Columns>
<DataGridTextColumn Header="Group Address" Binding="{Binding Path=Address_Value}" Width="Auto"/>
<DataGridTextColumn Header="Description" Binding="{Binding Path=Datapoint_Name}" Width="Auto"/>
<DataGridTextColumn Header="Length" Binding="{Binding Path=Datapoint_Object_Size}" Width="Auto"/>
</DataGrid.Columns>
</DataGrid>
where the DCA_GroupAddressList and DCA_GroupAddress are defined as in the namespace Dca.KnxPanel.Model
namespace Dca.KnxPanel.Model
{
[DebuggerDisplay("{Address_Value} {Datapoint_Name} {Datapoint_Object_Size}")]
public class DCA_GroupAddress
{
public DCA_GroupAddress(GroupAddress data) {
Address_Value = data.AddressValue.ToString();
Datapoint_Name = data.Name;
if (data.ObjectSize != null)
{
Datapoint_Object_Size = data.ObjectSize.Value;
}
}
public string Address_Value { get; set; }
public string Datapoint_Name { get; set; }
public ObjectSize Datapoint_Object_Size { get; set; }
}
public class DCA_GroupAddressList : ObservableCollection<DCA_GroupAddress>
{
public static DCA_GroupAddressList dca_groupaddresslist { get; set; }
public void Add(GroupAddress item)
{
this.Add(new DCA_GroupAddress(item));
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (e.Action != null)
{
base.OnCollectionChanged(e);
}
}
}
}
the problem is that the Binding data in DataGrid not works but i don't understand why...
Can you help me?
i have tried many solution and at the end this is what works:
<DataGrid Grid.Row="2" Grid.Column="2" Name="GroupAddressDataGrid" ItemsSource="{Binding _ProjectGroupAddress}" AutoGenerateColumns="False" Margin="14,0,-14,0" Grid.RowSpan="2" >
<Border Background="GhostWhite" BorderBrush="Gainsboro" BorderThickness="1">
</Border>
<DataGrid.Columns>
<DataGridTextColumn Header="Group Address" Binding="{Binding Path=Address_Value}" Width="Auto"/>
<DataGridTextColumn Header="Description" Binding="{Binding Path=Datapoint_Name}" Width="Auto"/>
<DataGridTextColumn Header="Length" Binding="{Binding Path=Datapoint_Object_Size}" Width="Auto"/>
</DataGrid.Columns>
</DataGrid>
The class DCA_GroupAddress now is:
public class DCA_GroupAddress : INotifyPropertyChanged
{
private string address_value, datapoint_name;
private ObjectSize datapoint_object_size;
public DCA_GroupAddress(GroupAddress data) {
Address_Value = data.AddressValue.ToString();
Datapoint_Name = data.Name;
if (data.ObjectSize != null)
{
Datapoint_Object_Size = data.ObjectSize.Value;
}
}
public string Address_Value {
get { return address_value; }
set {
address_value = value;
OnPropertyChanged(new PropertyChangedEventArgs("address_value"));
}
}
public string Datapoint_Name
{
get { return datapoint_name; }
set
{
datapoint_name = value;
OnPropertyChanged(new PropertyChangedEventArgs("datapoint_name"));
}
}
public ObjectSize Datapoint_Object_Size
{
get { return datapoint_object_size; }
set
{
datapoint_object_size = value;
OnPropertyChanged(new PropertyChangedEventArgs("datapoint_object_size"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
}
and i have define a container
public ObservableCollection<DCA_GroupAddress> _ProjectGroupAddress { get; set; } = new ObservableCollection<DCA_GroupAddress>();
my question is why i need to add these code:
GroupAddressDataGrid.Items.Clear();
GroupAddressDataGrid.ItemsSource = _ProjectGroupAddress;
in the UI class constructor? Seems that Items are not empty when the DataGrid is created so the software not use the ItemsSource. I need to clear the items before the binding works...
Thanks

Displaying Empty Combobox content in DataGridView?

I created a User Control page (SubPODetailView.xaml) that contains some entities "that entities defined from SubPO.cs" and a datagridview "that gridview is a separated class called SubInvoice.cs", and everything went good but in the datagridview, one of entities is a combobox display, the problem here is the collection list of this combobox is not displayed when running a program.
SubPO.cs
public class SubInvoice
{
public int Id { get; set; }
[Required]
public string InvoiceName { get; set; }
public DateTime Date { get; set; }
public decimal Amount { get; set; }
public List<string> Status{ get; set; }
public int SubPOId { get; set; }
public SubPO SubPO { get; set; }
}
Configuration.cs (In Migration Folder)
context.SubInvoices.AddOrUpdate(i => i.InvoiceName,
new SubInvoice
{
InvoiceName = "Invoice1",
Date = new DateTime(2020, 5, 26),
Amount = 1200,
SubPOId=context.SubPOs.First().Id,
Status = new List<string>() { "Open", "Closed", "Pending" }
});
SubPODetailViewModel.cs
<DockPanel Grid.Row="12" Margin="10">
<StackPanel DockPanel.Dock="Right" Width="86">
<Button Content="Add" Margin="10"
Command="{Binding AddInvoiceCommand}"/>
<Button Content="Remove" Margin="10"
Command="{Binding RemoveInvoiceCommand}"/>
</StackPanel>
<DataGrid ItemsSource="{Binding Invoices}"
SelectedItem="{Binding SelectedInvoice,Mode=TwoWay}"
AutoGenerateColumns="False" RowHeaderWidth="0" >
<DataGrid.Columns>
<DataGridTextColumn Header="Invoices" Width="*"
Binding="{Binding InvoiceName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTemplateColumn Header="Status" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Date,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Amount" Width="*" Binding="{Binding Amount,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
<DataGridTemplateColumn Header="Status" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Status,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</DockPanel>
SubPODetailViewModel.cs(Model)
namespace SubBV.UI.ViewModel
{
public class SubPODetailViewModel : DetailViewModelBase, ISubPODetailViewModel
{
private ISubPORepository _subPORepository;
private IMessageDialogService _messageDialogService;
private SubPOWrapper _subPO;
private SubInvoiceWrapper _selectedInvoice;
public SubPODetailViewModel(IEventAggregator eventAggregator,
IMessageDialogService messageDialogService,
ISubPORepository subPORepository) : base(eventAggregator)
{
_subPORepository = subPORepository;
_messageDialogService = messageDialogService;
AddInvoiceCommand = new DelegateCommand(OnAddInvoiceExecute);
RemoveInvoiceCommand = new DelegateCommand(OnRemoveInvoiceExecute, OnRemoveInvoiceCanExecute);
Invoices = new ObservableCollection<SubInvoiceWrapper>();
}
public SubPOWrapper SubPO
{
get { return _subPO; }
private set
{
_subPO = value;
OnPropertyChanged();
}
}
public SubInvoiceWrapper SelectedInvoice
{
get { return _selectedInvoice; }
set
{
_selectedInvoice = value;
OnPropertyChanged();
((DelegateCommand)RemoveInvoiceCommand).RaiseCanExecuteChanged();
}
}
public ICommand AddInvoiceCommand { get; }
public ICommand RemoveInvoiceCommand { get; }
public ObservableCollection<SubInvoiceWrapper> Invoices { get; }
public override async Task LoadAsync(int? subPOId)
{
var subPO = subPOId.HasValue
? await _subPORepository.GetByIdAsync(subPOId.Value)
: CreateNewSubPO();
InitializeSubInvoice(subPO.Invoices);
}
private void InitializeSubInvoice(ICollection<SubInvoice> invoices)
{
foreach (var wrapper in Invoices)
{
wrapper.PropertyChanged -= SubInvoiceWrapper_PropertyChanged;
}
Invoices.Clear();
foreach (var subInvoice in invoices)
{
var wrapper = new SubInvoiceWrapper(subInvoice);
Invoices.Add(wrapper);
wrapper.PropertyChanged += SubInvoiceWrapper_PropertyChanged;
}
}
private void SubInvoiceWrapper_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!HasChanges)
{
HasChanges = _subPORepository.HasChanges();
}
if (e.PropertyName == nameof(SubInvoiceWrapper.HasErrors))
{
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
}
}
private void InitializeSubPO(SubPO subPO)
{
SubPO = new SubPOWrapper(subPO);
SubPO.PropertyChanged += (s, e) =>
{
if (!HasChanges)
{
HasChanges = _subPORepository.HasChanges();
}
if (e.PropertyName == nameof(SubPO.HasErrors))
{
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
}
};
((DelegateCommand)SaveCommand).RaiseCanExecuteChanged();
if (SubPO.Id == 0)
{
// Little trick to trigger the validation
SubPO.Title = "";
}
}
}
SubInvoiceWrapper.cs (Wraps what is contained in the DataGridView)
public class SubInvoiceWrapper:ModelWrapper<SubInvoice>
{
public SubInvoiceWrapper(SubInvoice model) : base(model)
{
}
public string InvoiceName
{
get { return GetValue<string>(); }
set { SetValue(value); }
}
public DateTime Date
{
get { return GetValue<DateTime>(); }
set { SetValue(value); }
}
public decimal Amount
{
get { return GetValue<decimal>(); }
set { SetValue(value); }
}
public List<string> Status
{
get { return GetValue<List<string>>(); }
set { SetValue(value); }
}
}
ViewModelBase.cs (contains the propertychanged)
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

DataGrid checkall not working

Hi have a Datagrid with rowCheckBoxes and an header checkbox for checking all.
The header checkbox bind a method in MainViewModel who will update the property of my model data to true. But the checkboxes are still unchecked.
<DataGrid AutoGenerateColumns="False" x:Name="grdLignes" HorizontalAlignment="Stretch" Margin="0,0,0,0"
VerticalAlignment="Stretch" CanUserAddRows="False" CanUserDeleteRows="False" Grid.ColumnSpan="2"
ItemsSource="{Binding CmLignes, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Resources>
<Style TargetType="{x:Type DataGridRow}">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=hasLink, Mode=OneTime}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="False"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.Header>
<CheckBox Command="{Binding RelativeSource={RelativeSource AncestorType=Window, Mode=FindAncestor}, Path=DataContext.ToggleCheckAll}" CommandParameter="{Binding IsChecked, RelativeSource={RelativeSource Self}}"/>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox Name="rowCheck" VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding Path=hasLink, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Ref Mag" Binding="{Binding Path=refMag}" IsReadOnly="True"/>
<DataGridTextColumn Header="Ref Fourn" Binding="{Binding Path=refFourn}"/>
<DataGridTextColumn Header="Désignation" Binding="{Binding Path=design}"/>
<DataGridTextColumn Header="Quantité" Binding="{Binding Path=qte, StringFormat=N2}"/>
<DataGridTemplateColumn Header="Fournisseur">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!--<ComboBox ItemsSource="{Binding FournList, RelativeSource={RelativeSource AncestorType=Window}}" SelectedItem="{Binding Path=fourn}"/>-->
<ComboBox ItemsSource="{Binding Path=fournList}" SelectedItem="{Binding Path=selectedFourn, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Fourn princ" Binding="{Binding Path=fournPrinc}" IsReadOnly="True"/>
<DataGridTextColumn Header="Pièce" Binding="{Binding Path=numPiece}" IsReadOnly="True"/>
</DataGrid.Columns>
</DataGrid>
Then the MainViewModel:
public class MainViewModel : INotifyPropertyChanged
{
private ContremarqueRepository cmRepos;
private ObservableCollection<Contremarque> cmLignes;
public ObservableCollection<Contremarque> CmLignes
{
get { return cmLignes; }
set
{
cmLignes = value;
OnPropertyChanged("CmLignes");
}
}
public ICommand ToggleCheckAll { get; set; }
public MainViewModel()
{
Collection<Contremarque> cms = cmRepos.getAll(doPiece);
CmLignes = new ObservableCollection<Contremarque>(cms);
ToggleCheckAll = new Command(ActionToggleCheckAll);
}
private void ActionToggleCheckAll(object param)
{
bool isChecked = (bool)param;
if (isChecked)
{
foreach (Contremarque contremarque in CmLignes)
{
contremarque.hasLink = true;
}
}
OnPropertyChanged("CmLignes");
}
}
This is the Contremarque class:
public class Contremarque
{
public bool hasLink { get; set; }
public string refMag { get; set; }
public string refFourn { get; set; }
public string design { get; set; }
public double qte { get; set; }
public string fournPrinc { get; set; }
public List<string> fournList { get; set; }
public string selectedFourn { get; set; }
public string numPiece { get; set; }
public int dlNo;
public override string ToString()
{
string str = string.Empty;
foreach (var prop in this.GetType().GetProperties())
{
str += string.Format("{0} = {1} ", prop.Name, prop.GetValue(this, null));
}
return str;
}
}
The propertyChanged should update the state of my checkboxes isn't it?
Your class Contremarque should implement INotifyPropertyChanged and property hasLink should look like that:
public class Contremarque : INotifyPropertyChanged
{
private bool _hasLink;
public bool hasLink
{
get { return _hasLink; }
set
{
_hasLink= value;
OnPropertyChanged();
}
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}

How to update a CheckedListItem using WPF

One of my classes
public class CheckedListItem<T> : INotifyPropertyChanged
has the method
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}
My XAML looks like
<ListBox ItemsSource="{Binding Employee}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked}" Content="{Binding Path=Item.Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My employee.cs file
public class Employee
{
public string Name { get; set; }
}
I cant figure out how I can write back to the database when a item is checked or unchecked.
I would appreciate any help and would be more than happy to post the entire code for any files you need to see.
You should be able to get what you want by adding TwoWay for mode and PropertyChanged on UpdateSourceTrigger.
Final XAML will then be:
<ListBox ItemsSource="{Binding Employee}" >
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Content="{Binding Path=Item.Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
EDIT:
By the way, I think you might be setting your ItemsSource incorrectly. I'm sure what you want is to bind that listbox to a collection of Employees?
Something like:
public ObservableCollection<Employee> Employees
{
get { return _employees; }
set
{
_employees = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Employees"));
}
}
}
I misunderstood the question so here comes second edit:
Your class files would instead look like this:
public partial class MainWindow : INotifyPropertyChanged
{
private ObservableCollection<MutableKeyValuePair<Employee, bool>> _employees;
public MainWindow()
{
InitializeComponent();
Employees = new ObservableCollection<MutableKeyValuePair<Employee, bool>>
{
new MutableKeyValuePair<Employee, bool>(new Employee("Joakim"), false),
new MutableKeyValuePair<Employee, bool>(new Employee("SoftwareIsFun"), false),
};
}
public ObservableCollection<MutableKeyValuePair<Employee, bool>> Employees
{
get { return _employees; }
set
{
_employees = value;
OnPropertyChanged(nameof(Employees));
}
}
public void UpdateDatabase()
{
foreach (var employee in Employees)
{
if (employee.Value)
{
//DATABASE LOGIC HERE
}
}
}
}
public class MutableKeyValuePair<TKey, TValue>
{
public TKey Key { get; set; }
public TValue Value { get; set; }
public MutableKeyValuePair()
{
}
public MutableKeyValuePair(TKey key, TValue value)
{
Key = key;
Value = value;
}
}
public class Employee
{
public Employee(string name)
{
Name = name;
}
public string Name { get; set; }
}
XAML:
<DataGrid ItemsSource="{Binding Employees}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Key.Name}"/>
<DataGridCheckBoxColumn Binding="{Binding Value}"/>
</DataGrid.Columns>
</DataGrid>

C# WPF TwoWay CheckBox Binding not updating

stackoverflow!
Starting with my code:
XAML
<DataGrid Margin="25,112,25,10" Name="datGrid" RowHeight="30"
ColumnWidth="150" BorderThickness="1"
Style="{StaticResource AzureDataGrid}" IsReadOnly="False"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.HeaderTemplate>
<DataTemplate>
<CheckBox Content="CREATE" Name="headerCheckBox"
FontWeight="Bold" Width="Auto"
Checked="headerCheckBox_Checked"/>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=IsChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="HorizontalAlignment" Value="Center"/>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
<DataGridTextColumn Header="Username" Binding="{Binding Path=Username}"/>
<DataGridTextColumn Header="First Name" Binding="{Binding Path=FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding Path=LastName}"/>
<DataGridTextColumn Header="Email" Binding="{Binding Path=Email}"/>
</DataGrid.Columns>
</DataGrid>
And C#
public partial class MainWindow : Window
{
ObservableCollection<MyData> MyItems = new ObservableCollection<MyData>();
public MainWindow()
{
datGrid.ItemsSource = MyItems;
MyItems.Add(new MyData { IsChecked = false, Username = "apetecca", FirstName = "Anthony", LastName = "Petecca", Email = "apetecca#email.com"});
MyItems.Add(new MyData { IsChecked = true, Username = "jhalls", FirstName = "Jake", LastName = "Halls", Email = "jhalls#email.com" });
}
public class MyData
{
public bool IsChecked { get; set; }
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
private void headerCheckBox_Checked(object sender, RoutedEventArgs e)
{
foreach (var item in MyItems)
{
item.IsChecked = true;
}
}
When I click on the headerCheckBox to check it, I've watched the variables in the foreach loop to see it is changing the items from false to true but doesn't visually show that on the DataGrid. However, if I manually check or uncheck the boxes, it displays correctly when going through that loop. The loop correctly sets the values but does not change the GUI display.
Everything I have seen online indicates it has to do with TwoWay mode and UpdateSourceTrigger. Both of these are set and I can't seem to find anything else on these.
Any help would be greatly appreciated!
EDIT-
I also tried changing my class to look like this
public class MyData
{
private bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
_isChecked = value;
OnPropertyChanged("IsChecked");
}
}
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
This didn't resolve it either.
Implement INotifyPropertyChanged and then have your properties raise event to make this happen.
Something like:
public class MyData : INotifyPropertyChanged
{
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set
{
if (isChecked != value)
{
isChecked = value;
OnPropertyChanged("IsChecked");
}
}
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
}

Categories

Resources