This is a side-related question to this other question:
BackgroundWorker in Silverlight ViewModel
I have a TabControl where I load many TabItems when the user selects menu options. I load this Tabs by binding the TabControl ItemsSource to an ObservableCollection. When I add a new TabItem to this Collection, it is shown perfectly.
The problem is I've realized that since user press a button until the tab is created (ViewModel and View creation takes a couple of seconds), the screen is freezed.
I've tried to set "IsBusy" before calling the "loadTab" but it doesn't shows up... I've tried almost everything with async calls but the UI thread is in use and it throws an exception when I create the new tab control.
Is there any trick I'm loosing??? Any ideas??? Thanks in advance.
have you seen this post?
http://www.dotnetspark.com/kb/3524-doesnt-your-girlfriend-deserves-more-time.aspx
It helps when you avoid heavy stuff in the load event and make Visible=true after you finish to load all your resources, so in that sense you avoid the user feeling tempted to click something that is not ready yet.
Not sure if it helps, but how about this idea?
public void DoStuff(Object values)
{
//your values object could be anything,
//they might even be some objects from your form
//as long as you dont modify them in the other thread
imgLoading.Visible=true;
var client = new Proxy();
client.OnWorkCompletedAsync +=client_OnCompleted() ;
client.Work(values);
}
void client_OnCompletedAsync(object sender, EventArgs e)
{
imgLoading.Visible=false;
//now you can update the UI with other stuff
}
Related
I have a tab control in the GUI and there is WPF 4.0 datagrid in one of the tabs. When I click on a cell in the grid and edit something and then switch tabs, I get a Defer Refresh error:
DeferRefresh' is not allowed during an AddNew or EditItem transaction.
So I call datagrid.CancelEdit(DataGridEditingUnit.Row) when tab is switched to cancel any pending edit and the Defer refresh issue is gone.
But what I really want to do is CommitEdit() so that the user doesn't have to reenter the data again.
And datagrid.CommitEdit(DataGridEditingUnit.Row, true) doesn't work for me.
I get the below error on CommitEnd():
Cannot perform this operation while dispatcher processing is
suspended.
PS: I have tried datagrid.CommitEdit() and datagrid.CommitEdit(DataGridEditingUnit.Column, true) and it didnt work.
I solved this by adding this handler for the DataGrid's Unloaded event:
void DataGrid_Unloaded(object sender, RoutedEventArgs e)
{
var grid = (DataGrid)sender;
grid.CommitEdit(DataGridEditingUnit.Row, true);
}
I've run in to this before. WPF only keeps the current tab's view in memory; when you switch tabs, WPF unloads the current view and loads the view of the selected tab. However, DataGrid throws this exception if is currently executing a AddNew or EditItem transaction and WPF tries to unload it.
The solution for me was to keep all the tab views in memory, but only set the current tab's view to visible. This link shows a method of doing this:
WPF TabControl - Preventing Unload on Tab Change?
This change will also make your tabs load more smoothly when you switch between them because the view doesn't have to be regenerated. In my case, the extra memory usage was a reasonable trade-off.
In Xaml :
Loaded="OnUserControlLoaded"
Unloaded="OnUserControlUnloaded"
In Code Behind Inside OnUserControlLoaded and OnUserControlUnloaded Methods:
dataGrid.CommitEdit()
dataGrid.CancelEdit()
I just solved a similar problem by "commiting" changes to the DataTable that is my source of datas.
So if you have a DataTable in the source you can try the following code :
DataTableSource.AcceptChanges();
I've fixed that issue by adding this piece of code:
private void tabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (tabControl.SelectedIndex == 1)
{
WPFdataGrid.CancelEdit(DataGridEditingUnit.Row);
}
}
I think it's a problem of UI threads.
I have 2 Tab controls (UserControl) in my WPF application. Since both this tab controls are created dynamically based on back end data, I have both the tab controls of same class type but different objects (confirmed it by checking the memory address of both, which are different)
I have this strange situation where Unload event is not getting fired when I switch between the tabs (UserControl) of same type. However, the Unload event gets called when I switch from/to tabs of different type.
Am I suppose to handle some other event apart from Unload event?
Please help me with this.. I am stuck :(
After spending some more time and investigating, I could come to the solution to my question.
The issue was seen because WPF was just changing the DataContext of my UserControl everytime I switch between the Tab controls of same type and since the UsrControl was of same type, even though different object, Unload event was not getting triggered.
The solution to this problem is instead of handling Unload event, handle DataContextChanged event of the UserControl.
Thanks all for the answers !!
Cheers,
Nayan
For this you need to subscribe to the OnSelectionChanged event, like so:
XAML:
<TabControl SelectionChanged="TabControl1_OnSelectionChanged">
Code-behind:
private void TabControl1_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
//do whatever
}
I am just getting familiar with WPF databinding. I've figured out most of the basics but I'm having trouble figuring out a couple of things.
First, let's say I have an object called Synth that has a collection of Banks. In turn, a Bank has a collection of Patches. I have a synth window to which I set the DataContext to a single Synth object. I have one listbox (lstBanks) that shows all the banks ({Binding Banks}) and another (lstPatches) that shows all the patches ({Binding ElementName=lstBanks, Path=SelectedItem.Patches}). This all works great. I see the applicable patches when I select a bank.
Question 1: How can I load a selected Patch into a dialog window with two-way binding, yet cancel those changes if DialogResult = false?
Right now, I have a patch dialog that receives a patch in the constructor which it sets as its DataContext, but I am only using OneWay binding. This happens on the doubleclick of lstPatches.
private void Patch_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Models.Patch patch = (Models.Patch)((ListBoxItem)sender).DataContext;
PatchEdit p = new PatchEdit(patch);
p.Owner = this;
if (p.ShowDialog().GetValueOrDefault())
{
// Do stuff if applicable
}
}
Here is my PatchEdit constructor and OK button event:
public PatchEdit(Models.Patch Patch) : this()
{
this.DataContext = Patch;
}
private void btnOK_Click(object sender, RoutedEventArgs e)
{
Models.Patch p = (Models.Patch)DataContext;
p.Name = txtName.Text;
p.MidiProgramChangeValue = int.Parse(txtPCN.Text);
this.DialogResult = true;
this.Close();
}
If the user clicks OK on the patch dialog, that's when I set the properties from the form back to the DataContext. I wasn't sure if this was the best way to do it. I don't want to really save the changes until the user clicks OK on the main synth window. So all bank and patch edits should only remain local, and only be "locally" committed if the user clicks OK and not Cancel on the dialog.
Question 2: Once a patch is updated via the dialog, how can I get that change reflected in lstPatches?
I understand that directly navigating my models which are essential of type DBSet aren't Observable. I've seen posts regarding using an Observable collection, but doesn't this just complicate something that is supposed to be easy with WPF databinding? If it's the only way, how do I accomplish this easily using my code first models?
Question 1: Bind to a second/temporary object. If the user cancels, throw it away. If they don't, use it to update your original object. Data-binding doesn't really offer an "undo" or "reset" method.
Question 2: No, using ObservableCollection's doesn't complicate things. It is the recommended way of doing things. It is actually much harder to work without them.
I'm relatively new to WPF programming and can't seem to get this working correctly. This is in my mind something rather simplistic that i would like to get working so I didn't try the MVVM framework and decided to keep it simple.
I have a usercontrol treeview with report paths. I have another usercontrol with a reportviewer. Selecting a report path in the treeview should refresh the reportviewer.
I can "call" the method from the treeview usercontrol for refreshing the reportviewer in the report usercontrol but nothing happens.
I was reading other posts and some seem to suggest a button event to a delegate that will allow the other usercontrol method to be executed. I'm not using a button event so I'm a bit puzzled.
I thought I could do something like this:
private void treeViewMenu_Selected(object sender, RoutedEventArgs e)
{
//Get the selected item
....
//Call the method of another user control
ReportUserControl ruc = new ReportUserControl();
ruc.RefreshReport();
}
Obviously that didn't work...I know that it shouldn't be too difficult but i am in a brain freeze moment and can't seem to get it working.
Any suggestions would be greatly appreciated.
Thanks!
I have what I consider to be a stupid problem with a simple Silverlight application that has a datagrid in it. One of my columns lets the user edit an attendance number for the current day. if the user tabs/clicks away after editing, all is saved and good with the binding contract, but if the datagrid edit box has focus and the user closes the browser, the data is not updated in the database. I am using Silverlight 4 with an observable collection through the standard wcf ria services.
Any ideas what I can do?
In your App.xaml.cs there is an Application_Exit() function. That function is launched event when the user closes the browser.
in that method, retrieve your current opened window through the RootVisual like that :
private void Application_Exit(object sender, EventArgs e)
{
if (this.RootVisual is MySLApp.MainPage)
{
MySLApp.MainPage theMainPage = (MySLApp.MainPage)this.RootVisual;
theMainPage.myGrid.Commit() // OR SOMETHING LIKE THAT I DONT THINK THE COMMIT EXISTS :)
}
}