Infragistics XamDatagrid binding issues - wpf

I have an MVVM C#/WPF app. I'd like to bind a XamDataGrid to one of my view models, so that users can define how they want their results structure - what column is mapped to what variable.
My core holds such dictionary - Dictionary<string, string>, and I'd like to wrap it in an ObservableCollection and bind to this, rather than copy the data to a DataTable. Problem is, I can't add rows this way (the view seems locked for additions) and changes are not saved. My code:
<igDP:XamDataGrid
Grid.Row="1" Grid.Column="0"
Name="resultStructure"
DataSource="{Binding VariablesDictionary, Mode=TwoWay}"
GroupByAreaLocation="None">
<igDP:XamDataGrid.FieldLayoutSettings>
<igDP:FieldLayoutSettings
AllowFieldMoving="WithinLogicalRow"
AllowAddNew="True"
AllowDelete="True"
AddNewRecordLocation="OnBottomFixed" />
</igDP:XamDataGrid.FieldLayoutSettings>
</igDP:XamDataGrid>
the view model (relevant part):
private ObservableCollection<DictionaryEntry> variablesDictionary;
public ObservableCollection<DictionaryEntry> VariablesDictionary
{
get { return variablesDictionary; }
set
{
variablesDictionary = value;
OnPropertyChanged(()=>VariablesDictionary);
}
}
...
List<DictionaryEntry> vars = resultStructureModel.Variables.Select(x => new DictionaryEntry {Key = x.Key, Value = x.Value}).ToList();
VariablesDictionary = new ObservableCollection<DictionaryEntry>(vars);

For adding rows, the XamDataGrid uses either IEditableCollectionView.CanAddnew or IBindingList.AllowNew.
If you use a ListCollectionView for the DataSource of the grid then you can add new rows.
To use the ListCollectionView with an ObservableCollection, pass the ObservableCollection into the ListCollectionView and then use the CollectionView to bind to the grid.

What worked eventually was using a BindingList. ObservableCollection won't let you add rows, but BindingList really provides everything I need.

Related

Binding Observable collection list to dynamically created ComboBox in Silverlight

I have a requirement where I need to bind a list of observable collections to the item source of dynamically created ComboBoxes.
The problem is we bind through xaml conventionally in ItemsSource property but now the control rows in the grid are being added dynamically so each ComboBox in a row reference to the same collection whereas I need to bind it to a separate collection in observable collection list each time a row in the grid is added.
This what I have tried so far, any guidance would be appreciated. Thanks.
public virtual List<ObservableCollection<ComboBoxEntity>> ListRewardRule { get; set; }
Xaml :
<itimControls:ComboBox Name="cboReward"
IsMandatory="True"
itimComponents:ComponentManager.ComponentId="TXT_GROUP_RULE"
MaxWidth="400"
MinWidth="150"
ItemsSource="{Binding ListRewardRule, ElementName=RDefinitionScreen}"
DisplayMemberPath="Name"
SelectedValuePath="Code"
Loaded="cboReward_Loaded"
SelectedValue="{Binding RewardRuleId, Mode=TwoWay}"
SelectionChanged="cboReward_SelectionChanged">
</itimControls:ComboBox>
.CS :
private void cboReward_Loaded(object sender, RoutedEventArgs e)
{
Itim.Framework.Silverlight.UI.Controls.ComboBox cboReward = ((Itim.Framework.Silverlight.UI.Controls.ComboBox)sender);
int row = (int)cboReward.GetValue(Grid.RowProperty);
if (Model.ListRewardRule.Count > 0)
{
var rewardGroups = Model.RewardGroupAndTier.RewardGroups;
if(rewardGroups.Count > 1)
{
cboReward.ItemsSource = Model.ListRewardRule[row];
}
}
}
The way I understand this is, you have a “grid” (I suppose you mean a DataGrid) and each row in the grid has, among other things, a set of combo boxes.
What I’d do is bind that grid to an ObservableCollection of a custom class, call it CustomRowClass. CustomRowClass should have an ObservableCollection that will be bound to the combo boxes.
The magic is to define a DataTemplate for CustomRowClass. Once you set up the XAML this way, all you need to do is create an instance of CustomRowClass, and then add it to the ItemsSource of the grid.

What is the best way to add new field into Model collection in ViewModel in MVVM app?

I'm writing WPF application with MVVM structure using MVVM Light.
I have class Foo in the Model:
class Foo: ObservableObject
{
private string _propA = String.Empty;
public string PropA
{
get => _propA ;
set
{
if (_propA == value)
{
return;
}
_propA = value;
RaisePropertyChanged("PropA");
}
}
// same for property PropB, PropC, PropD, etc.
}
And I have some collection of Foo objects in the Model:
class FooCollection: ObservableObject
{
private ObservableCollection<Foo> _items = null;
public IEnumerable<Foo> Items
{
get { ... }
set { ... }
}
public string Name { get; set; }
// ...
// and other methods, properties and fields
}
Now I have a ViewModel where this list is populated via some injected provider:
class MainWindowModel: ViewModelBase
{
private FooCollection _fooList;
public FooList
{
get => _fooList;
set
{
_fooList = value;
RaisePropertyChangedEvent(FooList);
}
}
public MainWindowModel(IFooListProvider provider)
{
FooList = provider.GetFooList();
}
}
And the View, with MainWindowModel as data context:
<TextBlock Text={Binding FooList.Name} />
<ItemsControl ItemsSource="{Binding FooList.Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding PropA} />
<Button Content={Binding PropB} />
<!-- other controls with bindings -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Everything works fine, I can delete and add new items, edit them and etc. All changes in View reflects automatically in ViewModel and Model via bindings and observable objects, and vice versa.
But now I need to add ToggleButton to data template of ItemsControl, which controls visibility of particular item in other part of window. I need IsChecked value in ViewModel, because control in other part of window is Windows Forms control and I can't bind IsChecked directly without ViewModel.
But I don't want to add new property (Visibility, for example) in model classes (Foo, FooCollection), because it is just an interface thing and it doesn't need to be saved or passed somewhere outside ViewModel.
So my question: what is the best way to add new property to Model collection in ViewModel?
I could create new collection of wrappers in ViewModel (some sort of class Wrapper { Foo item, bool Visibility }) and bind it to ItemsControl. But in this case I have to control adding, removing and editing manually and transfer all changes from List<Wrapper> to FooList.Items, so I don't like this solution. Is there any more simple way to achieve this?
Edition to clarify the question. Now I have:
<ItemsControl ItemsSource="{Binding FooList.Items}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding PropA} />
<Button Content={Binding PropB} />
<ToggleButton IsChecked={Binding ????????????} />
<!-- other controls with bindings -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have no field in class to bind IsChecked and I don't want to add it to class, because it's only interface thing and not data model field. How can I, for example, create another collection of bools and bind it to this ItemControl alongside with FooList.Items?
The best place to add the property is of course in the Foo class.
Creating another collection of some other type, add an object per Foo object in the current collection to this one, and then bind to some property of this new object seems like a really bad solution compared to simply adding a property to your current class.
Foo is not an "interface thing", or at least it shouldn't be. It is view model that is supposed to contain properties that the view binds to. There is nothing wrong with adding an IsChecked property to it. This certainly sounds like the best solution in your case.
I'm not sure if I understand why you would need to add a property in the model.
Can't you just use the command property or add an EventTrigger to your toggle button?
(See Sega and Arseny answer for both examples Executing a command on Checkbox.Checked or Unchecked )
This way, when you check the toggleButton, there is a method in your viewModel which enable or disable the visibility property of your Winform control.
To change the visibility of your control from a command in your viewModel, you could use the messenger functionnality of MVVM LIGHT
MVVM Light Messenger - Sending and Registering Objects
The ViewModel sends a message to you're Windows Forms and this one handles the visibility of your control.

Rebinding Observable collection wpf

I created a WPF window to bind data in Datagrid based on the selection of date by the user.BY default it loads for a specific date which works fine. But When the date is changed, the grid is showing empty rows.but the observable collection I used is having data. The observable collection is of DataTable type.
Note: I used to set itemsource=null when there are no records since I am using the same grid for 2 different tables based on a radio button check.
I have set the public variable as Binding variable in the XAML, used INOtifyChanged interface.
My issues is when the same collection reloads, the Datagrid failed to bind and shows empty rows but generating columns. When the previous attempt set the itemsource as null, the current loading failed to load the column also.
Any generic scenario, I am facing,? Please help
My Code:
private ObservableCollection<DataTable> custInfoCol = new ObservableCollection<DataTable>();
public event PropertyChangedEventHandler PropertyChanged = delegate { };
private DataTable _CustInfo;
public DataTable CustInfo
{
get { return _CustInfo; }
set
{
_CustInfo = value;
PropertyChanged(this, new PropertyChangedEventArgs("CustInfo"));
}
}
private void rbPrev_Checked(object sender, RoutedEventArgs e)
{
custInfoCol.Clear();
custInfoCol.Add(CustInfo = showcustomer(cid));
}
Sounds like you might need to change the UpdateSourceTrigger in your binding:
Height="{Binding Height, ElementName=Day, UpdateSourceTrigger=PropertyChanged}"
I've had problems with the default behavior of it before, so now I just type it out every time.
https://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
Based on this piece of code you provided in the comment:
<DataGrid ItemsSource="{Binding custInfo,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}"
I think there is typo in the Xaml. You should use ... Binding CustInfo... with capital C.
Of course, if AutoGenerateColumns is true, then I guess this is not the problem, because you wrote
Datagrid failed to bind and shows empty rows but generating columns
Which the Binding works. Therefore, you need to check showcustomer(cid) and make sure it contains the required DataRows.
I fixed the issue which is very simple. I had created the datatable instance as global and i changed it to local just before loading the executereader() method.It resolved the issue.

WPF MVVM ListBox/ComboBox ItemsSource won't update UI from ViewModel

i have a container such as a listbox, combobox etc that its ItemsSource property is bound to an observable collection in my view model.
When i'm trying to add/remove items from the collection via some method in my VM it won't reflect in the UI,
The only way the UI would actually refresh is if i assign the collection a new value (i.e another collection with the relevant data) which forces him to re-bind the whole collection.
maybe i'm missing/don't understand something about the collection binding issue, either way if someone has a solution/good explanation/both it would be great.
here is a sample from my View(in this case its a listbox)
<ListBox
Grid.Row="9"
Grid.Column="1"
Grid.ColumnSpan="3"
Width="200"
Height="200"
ItemsSource="{Binding PreSavedRecordingScheduleList,UpdateSourceTrigger=PropertyChanged}"
SelectedItem="{Binding SelectedPreSavedRecordingSchedule,UpdateSourceTrigger=PropertyChanged}"
DisplayMemberPath="Display"/>
and here is my ViewModel:
private ObservableCollection<ScheduledRecordingObject> m_PreSavedRecordingScheduleList;
PreSavedRecordingScheduleList = new ObservableCollection<ScheduledRecordingObject>();
public ObservableCollection<ScheduledRecordingObject> PreSavedRecordingScheduleList
{
get
{
return m_PreSavedRecordingScheduleList;
}
set
{
m_PreSavedRecordingScheduleList = value;
OnPropertyChanged("PreSavedRecordingScheduleList");
}
}
ScheduledRecordingObject also implements INotifyPropertyChanged.
viewmodel
public ObservableCollection<yourType> MyItemsSource {get;set}
initialize once in contructor and use clear, add and remove to alter it
view
<ListBox ItemsSource="{Binding MyItemsSource}"/>
just be sure that the right DataContext is set.
thats how it should look in your code
EDIT:
some hints to your posted code:
//remove the UpdateSourceTrigger=PropertyChanged - makes no sense the Mode is OneWay anyway :)
ItemsSource="{Binding PreSavedRecordingScheduleList}"
//the following line should just called once and at best in ctor
//but the binding will of course work too when you assign a new collection
PreSavedRecordingScheduleList = new ObservableCollection<ScheduledRecordingObject>();
all in all your code looks good, and if the viewmodel is the Datacontext of your Listbox then it should work. let me know what Snoop is showing :)
Remove the OnPropertyChanged("PreSavedRecordingScheduleList"); from the ObservableCollection. Actually you don't need a backing field. Attach the CollectionChanged event on the ObservableCollection, something like this
1- Inside the ViewModel constructor attach the event CollectionChanged
PreSavedRecordingScheduleList = new ObservableCollection<ScheduledRecordingObject>();
PreSavedRecordingScheduleList.CollectionChanged += PreSavedRecordingScheduleList_CollectionChanged;
2- Inject the OnPropertyChanged("PreSavedRecordingScheduleList") in the event handler
void PreSavedRecordingScheduleList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
OnPropertyChanged("PreSavedRecordingScheduleList");
}

How to stop automatic refresh of a WPF ListBox Databinded on a EntityFramework object

I have a Xaml Page with a Databinded ListBox and a detail grid to create or update selected element.
My Page.DataContext is binded on a ADO.NET Entity Data Model table ("Univers").
private void Page_Loaded(object sender, RoutedEventArgs e)
{
SEPDC = new Models.SEP();
universViewSource = new CollectionViewSource();
universViewSource.Source = SEPDC.Univers.Execute(System.Data.Objects.MergeOption.AppendOnly);
DataContext = universViewSource;
}
The Xaml code of the ListBox :
<ListBox DisplayMemberPath="Nom" ItemsSource="{Binding}" Name="universListBox" SelectedValuePath="IdUnivers"/>
When i select an element in the ListBox, the grid detail automatically display the information of the selected element
Here the "Nom" TextBox witch use TwoWay databinding :
<TextBox Name="nomTextBox" Text="{Binding Path=Nom, Mode=TwoWay}" />
When i modify the TextBox "Nom", the ListBox is automatically updated. Great ... But i haven't call the SaveChanges method of my SEPDC DataContext object ...
How can i stop the automatic refresh of my ListBox until i explicit call the SaveChanges method and if possible, without use the Binding UpdateSourceTrigger=Explicit option ?
Regards.
You can use two separate entity data context (SEPDC) objects. Your ListBox is bound to one and your detail grid to the other. When the SelectedValue changes in the ListBox, find the same entity in the detail grid's entity data context and set it. After saving changes from the detail grid's entity data context, refresh the one for the ListBox.
I use this technique but i have to recreate the ListBox SEPDC each time i refresh the ListBox.
List<Models.Univers> list;
using (Models.SEP dc = new Models.SEP())
list = dc.Univers.Execute(System.Data.Objects.MergeOption.AppendOnly).ToList();
universListBox.DataContext = list;
The Refresh method doesn't work.
Regards

Resources