WPF Toolkit datagrid /doesn’t refresh data - wpf

H I use SQL CE and LINQ. I bind property typeof Table on ItemSource of Datagrid control from WPF Toolkit.
Something like this.
public Table<TestNick> MySource
{
get { return _tab; }
set
{
_tab = value;
NotifyPropertyChanged("MySource");
}
}
<Controls:DataGrid Name="Dg"
ItemsSource="{Binding Path=MySource, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="0"/>
I retrieve data from DB with LINQ:
const string connStr = #"Spiri_SQL_CE_DB.sdf";
_dc = new Spiri_SQL_CE_DB(connStr);
MySource = _dc.TestNick;
If I add a breakpoint on last line I see all values from tables TestNick, but it doesn’t load this data in DataGrid.
What is bad?
EDITED:
I check the ItemSource of DataGrid control in code behind, the item source is correct but I see in DataGrid (view) "old data".
So binding must be correct, problem is that DataGrid control doesn’t refresh data.

Make sure datagrid autogeneratecolumns is true
While running check the output window if there are any binding issues
Another trick is to put a button on the view and write a code behind function on click of that button to debug whats the datagrid itemsource, if its empty try to invoke viewModel/Model's getDatagridData function and then see if it loads, in case it loads that means your NotifyPropertyChanged is not yet functional

Related

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.

When does a ComboBox receive its Items if it is bound to ObservableCollection?

I am attempting a save/load mechanism for re-use in a business application. I have the groundwork laid to read/write ObservableCollection<> to/from xml, using attributes to describe my class properties. That part is working. I can save an ObservableCollection to XML, then load the XML back into an ObservableCollection the next time I run the program.
Here's my problem. I have a ComboBox whose ItemsSource.DataContext = ObservableCollection<Flag>;
When I run the program, it accepts the binding just fine, but the ComboBox itself does not populate itself until later. I want to set the SelectedItem to be the first item in the ObservableCollection<Flag> that I have loaded from XML. Nothing happens though, because as the program is executing it's startup methods, the Items.Count remains 0. I'm guessing the ComboBox doesn't populate itself until it gets focus. How do I work around this? Can I force the ComboBox to populate itself? I've tried cb_ARDAR_ARFlag.Items.Refresh();
XAML:
<ComboBox Name="cb_ARDAR_ARFlag"
ItemsSource="{Binding}"
SelectionChanged="cb_ARDAR_ARFlag_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Flag_Desc}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Relevant Code:
public MainWindow()
{
InitializeComponent();
setDataBinding();
loadSavedData();
}
private void setDataBinding()
{
//Returns ObservableCollection<Flag>
cb_ARDAR_ARFlag.DataContext = Flag.getOCAvailableFlags();
}
private void loadSavedData()
{
//When it gets here the ItemCount is 0 so nothing happens.
//Refresh didn't help
cb_ARDAR_ARFlag.Items.Refresh();
Flag f = Enforcement_Save.loadOCARFlag().First();
cb_ARDAR_ARFlag.SelectedItem = f;
}
At this point I'm still not sure the code at the end will successfully identify the correct 'flag' item to be selected, or if I'll end up using Linq. Which, by the way, leads me to another question. Can you Linq to ComboBox.Items somehow?
I have recreated your issue, and your are correct, the items count is = 0 in the loadSavedData method. The combobox doesn't seem to be populated until after the constructor has fully executed.
In the meantime I found you can use the ItemsSource property to load the combobox at the time you want it loaded:
cb_ARDAR_ARFlag.ItemsSource = Flag.getOCAvailableFlags();

WPF DataGrid automatically updates in-memory data?

I'm using WPF and MVVM pattern to develop a desktop application. Maybe I'm not clear about how a DataGrid control would work, but if I modify an item (text, checkbox, etc.), the modification persists even if I don't make any permanent database update (using Entity Framework). For example, I may switch to view different data, and when I come back to view the grid with modified data (but without saving to db), the change is there. Somehow the in-memory data has been changed by the DataGrid control and is not refreshed or synced with database.
In other words, the data in the DataGrid remained modified until I stop and re-run it from visual studio.
UPDATED:
Another way to ask this question would be: What actually happens when I update, say, an item of a DataGrid? If it is bound to a ViewModel's property P in two-way mode then I suppose P will be updated. But even if I refresh its value (setting the P to null then calling the data access methods again), the modified data are still there.
Does anybody have any idea of what happened?
Thanks!
UPDATED 2:
Here is the xaml code which binds a DataGrid to a property named UserList in the ViewModel.
<DataGrid
x:Name="UserList"
ItemsSource="{Binding UserList, Mode=TwoWay}"
AutoGenerateColumns="False"
AllowDrop="True"
RowBackground="Orange"
AlternatingRowBackground="#FFC4B0B0">
<!-- define columns to view -->
<DataGrid.Columns>
...
</DataGrid.Columns>
</DataGrid>
Here is the code running in the ViewModel. The method InitialiseData() is called in the constructor of the VM and before I want to do something else with persistent data, so I supposed is always refreshed.
private void InitialiseData()
{
// Retrieves user list from the business layer's response
Response userList = _userBL.GetUserList();
if (userList is FailResponse)
{
MessageBox.Show(userList.Message);
return;
}
else
{
UserList = null;
UserList = (IEnumerable<User>)((SuccessResponse)userList).Data;
}
** UPDATED 3 **:
private IEnumerable<User> _userList;
public IEnumerable<User> UserList
{
get
{
return _userList;
}
set
{
_userList = value;
NotifyOfPropertyChange(() => UserList);
}
}
If you switch back, you are switching to in-memory collection which was updated by DataGrid before. Or do you load data from dtb again?
EDIT:
Ok, now as you have posted the code, I know where is the problem.
DataGrid is not refreshed as I thought. Make sure, you will raise NotifyProperyChanged on the property UserList. Then it will work. See ObservableCollection class as well.

Databinding causing other functions on page not to work when filling datagrid

I have a datagrid in my View. The datagrid's itemssource property is bound as such
ItemsSource="{Binding}"
Addtionally in the codebehind I have set datacontext by doing the following:
DataContext = ProcedureDatabaseViewModel.Procedures();
The Procedures function in the viewmodel successfully outputs a list which the DataGrid successfully displays.
The issue now is that the datacontext of the entire page is now set to the above. The result of this is that other elements that interect with the VM no longer work. I.E. buttons with commands that are found in the VM. I have tried removing the setting of the datacontext in the code behind but cannot figure out how to populate the datagrid otherwise. Please note that when the DataContext is not set in the code behind the context is changed to the VM, I believe, and thus, the other elements begin working again. I have tried changing the Itemssource property to target the list of objects that I wish to populate the datagrid with but it hasnt worked.
The list is
List<procedure> Procedures
and it is in the ProdureDatabaseViewModel. I tried to target it as
ItemsSource="{Binding ProdureDatabaseViewModel.Procedures}"
But this has not worked either.
Can someone please advise me on the correct way to do this?
The cleanest way is to use ItemsSource to bind your Procedures collection to your DataGrid. For this to work, Procedures has to be a Property. To avoid further issues, use an ObservableCollection. It should look like this:
ObservableCollection<procedure> Procedures { get; set; }
Then you should be able to simply bind it via
ItemsSource="{Binding Procedures}"
I prefer to set the DataContext in the constructor of the view to the complete ViewModel (which I created for this special view).
So I do something like this in the constructor of the view:
public View(ProcedureDatabaseViewModel viewModel)
{
this.DataContext = viewModel;
}
This way everything else should still work and you can use more than just the procedures.
Next you bind the procedures to your datagrid:
ItemsSource="{Binding ProcedureList}"
Do note that for this to work, "Procedures" needs to be a property. It's not clear in your question if it is a function, a property or just a simple class member. If it is a function, you can do it like this in your view model:
public List<procedure> ProcedureList
{
get { return this.Procedures(); }
}
I have tried removing the setting of the datacontext in the code
behind but cannot figure out how to populate the datagrid otherwise.
You can set the DataContext of your DataGrid separately like so, MyDataGrid.DataContext = ProcedureDatabaseViewModel.Procedures();.
And apply separate DataContext for your Page.

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