WPF load data from EF async - wpf

I have wpf application with EF6. I use:
context.Set<T>().Local;
as item source for listview. I want to ask, where I should call load data?
private async void MainWindowLoaded(object sender, RoutedEventArgs e)
{
await context.Set<T>().LoadAsync();
Items = context.Set<T>().Local; //Items is observable collection. Listbox is Bind for this
}
I try it in Window Loaded event, but that hangs application on start. What is the best solution?
If I swap this two line or not call with await, then I get exception becouse I could not add to collection from another thread.

Related

WPF Binding: Throttle the binding list's updates

I am binding the xamdatagrid to a list.But since there are too many updates on the list GUI get stuck.How can I stop these updates and refresh the grid after an interval(say 500 ms).Will Reactive extension's throttle method be useful?
You can use the DeferRefresh to defer the binding update until you're done making modifications to the collection:
using (collection.DeferRefresh())
{
// Make changes to the collection
...
}
If the collection is being updated in real time, you could use a timer to update the binding at intervals:
private IDisposable _deferral;
private void refreshTimer_Tick(object sender, EventArgs e)
{
if (_deferral != null)
_deferral.Dispose();
_deferral = collection.DeferRefresh();
}

Responsive UI in async drawing

I am trying to create a drawing with 5000 Shape objects in a background thread on a canvas.
I use the asyn-await pattern:
async void CreateDrawingAsync()
{
await Task.Run(() => CreateDrawing()).ConfigureAwait(false);
}
void CreateDrawing()
{
DrawObjects = new ObservableCollectionEx<DrawObject>();
// or: DrawObjects.Clear();
RaisePropertyChanged("DrawObjects");
// etc ... etc ...
}
ObservableCollectionEx means I use an extension of ObservableCollection to add an object to the collection via the Dispatcher.
When I start CreateDrawingAsync in the Loaded event of the Window (in the ctor of Data) the UI is unresponsive.
Using DispatcherPriority.Background the items are added one by one in the UI, but also in that case, the UI is unresponsive.
Loaded += (object sender, RoutedEventArgs e) =>
{
DataContext = new Data(2000, 1000, 1000);
};
1) I expected the background thread would resolve the unresponsive UI issue, what am I overlooking?
2) Why does RaisePropertyChanged("DrawObjects") (see code above) have no effect? I would have expected the drawing would be cleared due to the propertychanged.
You should not do UI operations on a background thread. This includes:
Drawing on a canvas.
Raising PropertyChanged notifications.
Creating or updating an ObservableCollection.
Creating a fake-UI component like ObservableCollectionEx that just forwards all its work to the UI thread doesn't gain you anything.

What event is raised on Grid.Children.Add

In my WPF application, I have a single Main window with a Grid. The Login and Shell are 2 separate UserControls added as children to a grid. I need to find out when the Shell is loaded and start a timer from the Main window.
I just need to know as to what event is raised when a UserControl is added using Grid.Children.Add method, so that I can check if Login is loaded or the Shell and start the timer.
I'm not quite sure what you're trying,
but it sounds like you're looking for the Load event:
UserControl MyControl = new UserControl();
MyControl.Loaded += new RoutedEventHandler(MyControl_Loaded);
public void MyControl_Loaded(object sender, RoutedEventArgs e)
{
if (((UserControl)sender).IsLoaded)
{
..... do something
}
}
Hope it helps

Call method in view model call which take/consume much of time

Hi I try solve this situation. I have WPF app with MVVM design. I use Caliburn Micro framework and on injection MEF.
In WPF app I use service from external assembly. It works good.
Problem is. I bind observable dictionary to listbox. Listbox can consist from 0 to 400 items.
I have data template on listbox item it consist with image and som texbox. Listbox is like
contact list in skype or google talk.
I call every 3-4 sec method from service, wich returns new data as dictionary. An with this data aj refresh Listbox.
My code look in view model like this:
private DispatcherTimer _dispatcherTimer;
private MyObservableDictionary<string, UserInfo> _friends;
//temp
private MyObservableDictionary<string, UserInfo> _freshFriends;
//bind on listbox
public MyObservableDictionary<string, UserInfo> Friends
{
get { return _friends; }
set
{
_friends = value;
NotifyOfPropertyChange(() => Friends);
}
}
//in constructor of view model I have this:
_dispatcherTimer = new DispatcherTimer();
_dispatcherTimer.Tick += DispatcherTimer_Tick;
_dispatcherTimer.Interval = TimeSpan.FromSeconds(3);
_dispatcherTimer.Start();
// on timer tick I call method from service
private void DispatcherTimer_Tick(object sender, EventArgs eventArgs)
{
//get new data from server
//method GetFriends take much of time
_freshFriends = _service.GetFriends(Account);
//delete old data
_friends.Clear();
//refresh
foreach (var freshFriend in _freshFriends)
{
Friends.Add(freshFriend);
}
}
As I said, problem is that method GetFriends from service take much of time and my app freezes.
How can solve this problem? In winforms app I use background worker, but this is my first WPF app with MVVM. It exist any "patern" or "design" how call method which consume much of time in view model class? Call this method in another thread?
As others have suggested, you can use a BackgroundWorker in a WPF app, or if you are using .NET 4, then use the Task Parallel Library. Stephen Cleary has a nice post on the TPL compared to BackgroundWorker here - http://nitoprograms.blogspot.com/2010/06/reporting-progress-from-tasks.html

Loading the list of items asynchronously in a WPF listbox using Dispatcher

I am working on creating a WPF solution which uses MVVM pattern to load searched items in a search control asynchronously. The search control which is a WPF usercontrol is created with a textbox to enter search text and search button and a hidden listbox which would be visible when it loads the searched items list in it. This user control is in turn embedded into another WPF view which has a treeview of certain items. This view has a view model in which the logic to load the searched items of the tree view would be loaded in the search control. All the while, this has been happening synchronously without the use of any Dispatcher call. But, after a change request, I would like to make this happen asynchronously in a different thread using Dispatcher.
Could anyone please let me know how to get handle of the Dispatcher of the Search control in the view model class so as to call BeginInvoke on it using MVVM pattern wherein my View model is not aware of the view? Any clue would be highly appreciated.
public ObservableCollection<Details> CatalogSearchResults { get; private set; }
private void ExecuteSearchCommand(object parameter)
{
CatalogSearchResults.Clear();
if (string.IsNullOrEmpty(parameter.ToString())) return;
searchtext = (string)parameter;
searchtext.Trim();
SetSearchResults();
}
private void SetSearchResults()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += LoadResults;
bw.RunWorkerCompleted += this.LoadResultsCompleted;
bw.RunWorkerAsync();
}
private void LoadResults(object sender, DoWorkEventArgs args)
{
IsSearchInProgress = true;
foreach (var category in _rootCategory.Recurse(FindChildren))
{
if (category.CommentDetails != null)
{
//limitation - there is no direct way to add range to observable collection.
//Using linq query would result in two loops rather than one.
foreach (var node in category.Details)
{
if (node.Name.IndexOf(searchtext, StringComparison.CurrentCultureIgnoreCase) >= 0
|| node.PrecannedText.IndexOf(searchtext, StringComparison.CurrentCultureIgnoreCase) >= 0)
{
Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
(ThreadStart)delegate { CatalogSearchResults.Add(node); });
Thread.Sleep(100);
}
}
}
}
IsSearchInProgress = false;
}
In the xaml, I am biding the Items property of the Search control to the CatalogSearchResults:
<ctrl:SearchControl x:Name="Ctrl" Grid.RowSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Top" ToolTip="Search" Command="{Binding SearchCommand}" Grid.ColumnSpan="3"
CommandParameter="{Binding Text, RelativeSource={RelativeSource Self}}"
Items ="{Binding CatalogSearchResults}" > </ctrl:SearchControl>
Thanks,
Sowmya
Here's a simple implementation showing how to use BackgroundWorker to update objects on the UI thread while DoWork is running - in this example, there's a ListBox in the UI that's bound to FilteredItems, and ItemsSource is a property of the UserControl of type IEnumerable:
FilteredItems = new ObservableCollection<object>();
BackgroundWorker bw = new BackgroundWorker();
bw.WorkerReportsProgress = true;
bw.DoWork += bw_DoWork;
bw.RunWorkerCompleted += bw_RunWorkerCompleted;
bw.ProgressChanged += bw_ProgressChanged;
bw.RunWorkerAsync();
private void bw_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bw = (BackgroundWorker) sender;
var result = ItemsSource
.OfType<object>()
.Where(x => x.ToString().Contains(_FilterText));
foreach (object o in result)
{
// Pass each object found to bw_ProgressChanged in the UserState argument.
// This updates the UI as each item is found.
bw.ReportProgress(0, o);
}
}
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// FilteredItems is bound to the UI, but it's OK to update it here because
// the ProgressChanged event handler runs on the UI thread.
FilteredItems.Add(e.UserState);
}
private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(e.Error.Message);
}
}
Note that calling ReportProgress every time you find an item is pretty inefficient, as you're marshalling every item found across threads with an Invoke call. Depending on how long the filtering is actually taking, it may be better to accumulate a bunch of results and pass a List<object> to bw_ReportProgress instead of just a single object.
It depends on a lot of factors (and your description is a bit confusing), but I've given a lengthy answer here that may shed some light on the matter. Basically, using the dispatcher alone will not automatically make the code multi-threaded; you'll need some real multi-threading mechanism like BackgroundWorker or the Task Parallel Library. Depending on how you have things set up and on exactly what you do in the other thread, you may indeed need to invoke some actions on the dispatcher thread - however BackgroundWorker does this automatically in most cases so I'd go with that for simple things. The Task Parallel Library also has special handling for the dispatcher, you should find more info on that on MSDN or any TPL tutorial.
The best advice I'd give if you didn't deal heavily with multi-threading until now is to gather as much information as possible on it, because, as it has been said countless times until now, multi-threading is hard! :)
Modify as necessary. 'Items' is just an observableCollection of strings exposed from the VM
private void SetSearchResults()
{
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += LoadResults;
bw.RunWorkerCompleted += this.LoadResultsCompleted;
bw.RunWorkerAsync();
}
private void LoadResultsCompleted(object sender, RunWorkerCompletedEventArgs e)
{
}
private void LoadResults(object sender, DoWorkEventArgs args)
{
List<string> results = GetResults();
foreach (string result in results)
{
Application.Current.Dispatcher.Invoke(
DispatcherPriority.Normal, (ThreadStart)delegate { Items.Add(result); } //Dont worry about access to modified closure in this case
Thread.Sleep(100);
}
}
In XAML
<ListBox ItemsSource={Binding Items}/>
All views in the application have the same dispatcher, you can access it with Application.Current.Dispatcher.
But anyway, you don't need the dispatcher to perform operations on a worker thread. You only need it to perform actions on the UI, because UI elements can only be accessed from the UI thread. But even then, you usually don't need to explicitly manipulate the dispatcher. You can update a property of your ViewModel from the worker thread, controls bound to this property will be updated alright, because the PropertyChanged event is automatically marshalled to the UI dispatcher.
What doesn't work is modifying an bound ObservableCollection<T> from a worker thread: you need to do it from the UI thread using Dispatcher.Invoke. You can also use a specialized ObservableCollection<T> that raises event on the UI thread.

Resources