Displaying a busy indicator when Entity Framework is loading data - wpf

I've already done it quite easily in the past with Silverlight, by declaring a BusyIndicator as my root element, and binding the IsBusy property to the IsLoading property of the domain context generated by RIA Services:
<toolkit:BusyIndicator IsBusy="{Binding Context.IsLoading}" >
Since there seems to be no IsLoading property on the ObjectContext generated by Entity Framework, how can I bind the IsBusy property in WPF?
Thank you

What I came up with:
Busy Indicator from the WPF Extended Toolkit:
<extoolkit:BusyIndicator IsBusy="{Binding IsBusy}" BusyContent="Loading data..." >
In my base class view model, I've added the following method:
protected void ExecuteBackgroundProcess(Action action)
{
IsBusy = true;
Task task = Task.Factory.StartNew(() => action()).ContinueWith((s) => this.IsBusy = false);
}
When I want to load a collection from the server, I can call from a derived view model:
this.ExecuteBackgroundProcess(() =>
{
var collection = _securityRepo.TakeOfType<Security>(10).ToObservableCollection();
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
Securities = collection;
RaisePropertyChanged("Securities");
});
});
There's also a more robust & complete solution on CodeProject:
http://www.codeproject.com/KB/WPF/ThreadingComponent.aspx?msg=3319891

Related

ReactiveUI, can execute doesn't disable button in WinForm

I got a simple WinForm application with a couple of textboxes and a confirm button, I'm using ReactiveUI.
This is my ViewModel:
public CurrencyViewModel()
{
editCurrency = new Currency();
this.ValidationRule(
viewModel => viewModel.IsoCode,
isoCode => !string.IsNullOrWhiteSpace(isoCode),
"error");
this.ValidationRule(
viewModel => viewModel.Name,
name => !string.IsNullOrWhiteSpace(name),
"error");
NewCommand = ReactiveCommand.Create(() => NewItem());
SaveCommand = ReactiveCommand.Create(() => Save(), this.IsValid());
}
public string IsoCode
{
get => isoCode;
set
{
editCurrency.IsoCode = value;
this.RaiseAndSetIfChanged(ref isoCode, value);
}
}
public string Name
{
get => name;
set
{
editCurrency.Name = value;
this.RaiseAndSetIfChanged(ref name, value);
}
}
private void NewItem()
{
IsoCode = string.Empty;
Name = string.Empty;
Symbol = string.Empty;
}
I then bind my validation and my save command in the view:
this.BindValidation(ViewModel, vm => vm.IsoCode, v => v.errorLabelIsoCode.Text).DisposeWith(disposables);
this.BindValidation(ViewModel, vm => vm.Name, v => v.errorLabelName.Text).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.SaveCommand, v => v.sfButtonOk, nameof(sfButtonOk.Click)).DisposeWith(disposables);
this.BindCommand(ViewModel, vm => vm.NewCommand, v => v.sfButtonNew, nameof(sfButtonNew.Click)).DisposeWith(disposables);
My issue is that sfButtonOk stays enabled when i first launch the application even if isValid() is false, the command doesn't fire as intended so it's just a grapichal problem it seems. The button is disabled only if I write valid text and then cancel it.
It seems that the button is disabled only when isValid goes from true to false
The issue here is probably related to a view model being initialized too late, or due to the view model property not sending change notifications on the view side in time. Make sure you assign the view model to the IViewFor.ViewModel property before a call to WhenActivated, or otherwise implement INotifyPropertyChanged on the view side (also you probably don't need a WhenActivated at all because WinForms doesn't have dependency properties that might introduce a potential for a memory leak)
Additionally worth noting, that we have evergreen sample apps targeting various UI frameworks including Windows Forms in the ReactiveUI.Validation core repository https://github.com/reactiveui/ReactiveUI.Validation/blob/d5089c933e046c5ee4a13149491593045cda161a/samples/LoginApp/ViewModels/SignUpViewModel.cs#L43 Just tested the Winforms sample app, and the button availability seems to perform as we'd expect.

How to OneWayBind to materialDesign:ButtonProgressAssist.IsIndicatorVisible DependencyProperty

I have a login button that I would like to apply an indeterminate progress look to while the login process is happening.
Here is the XAML for the button:
<Button x:Name="LoginButton" Style="{StaticResource MaterialDesignRaisedButton}"
materialDesign:ButtonProgressAssist.Value="-1"
materialDesign:ButtonProgressAssist.IsIndicatorVisible="false"
materialDesign:ButtonProgressAssist.IsIndeterminate="true">
LOGIN
</Button>
So I figure I can just bind a boolean property on my view model to materialDesign:ButtonProgressAssist.IsIndicatorVisible. I'm using code behind binding like so:
public partial class Connection : ReactiveUserControl<ConnectionViewModel>
{
public Connection()
{
InitializeComponent();
ViewModel = ViewModelLocator.ConnectionViewModel;
this.WhenActivated(d =>
{
this.BindCommand(ViewModel, vm => vm.LoginCommand, v => v.LoginButton).DisposeWith(d);
// How do I bind to this property using OneWayBind?
this.OneWayBind(ViewModel, vm => vm.LoggingIn, v => v.LoginButton.ButtonProgressAssist.IsIndicatorVisible).DisposeWith(d);
});
}
}
Intellisense doesn't pick up on that material designs dependency property. How do I reference it?
In case it matters, the WPF project targets .NET Core 3.1
I don't think the OneWayBind method supports attached properties but you could bind to it in the XAML markup:
materialDesign:ButtonProgressAssist.IsIndicatorVisible="{Binding LoggingIn, Mode=OneWay}"
You can of course do OneWayBind for the other properties just like before.

wpf Busy Indicator is not showing up when followed by Application.Current.Dispatcher.BeginInvoke code

I am using wpf busy indicator and setting its Isbusy property from viewModel. Aftersetting Isbusy property I want to filter my ICollectionview and push it on UI. This Filter operation I have put in
IsBusy = true;
await Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background,
new System.Action(() =>
{
this.MyCollectionView.Filter = item =>
{
Iitem IdName = item as Iitem;
return Regex.IsMatch(IdName.Name, SearchText, RegexOptions.IgnoreCase);
};
}));
Workaround: If I put Task.Delay(200).Wait(); after setting IsBusy, busy indicator will be displayed for some cases.
Filter always runs on the UI thread, keeping it too busy to actually update the UI to reflect the IsBusy state.
In most cases, Filter functions should run fast enough that they don't need any special handling. However, if you're sure that you need to run a time-consuming filter, then the best way to do it is to split into two different collections: MyCollection and MyFilteredCollection. Then, any time MyCollection (or the filter) changes, do something like this:
IsBusy = true;
var items = MyCollection.ToList();
var filter = SearchText;
MyFilteredCollection = await Task.Run(() =>
items.Where(x => Regex.IsMatch(x.Name, filter, RegexOptions.IgnoreCase)));
IsBusy = false;
(this assumes that IsBusy will prevent MyCollection and SearchText from changing).

ANGULAR2: Detecting Change in static variable of a class

I am writing a dragDirective. Eements are dragged in dragZones. On mouse releases I do a hitTest against all availabe dragZones. I am maintaining a static boolean flag which ends up being false if all hittests return false. In such a situation I would like to resposition the element in the dragZone it originally belonged to. How do I check against this change in variable value?
this._messageBus.listen("dragStart", (obj, event) => {
DragZoneDirective.HITTEST = false;
});
this._messageBus.listen("dragStop", (obj, event) => {
if (this.hitTest(event.x, event.y))
{
//clone object
let clone: Object = JSON.parse(JSON.stringify(obj));
this.dragZoneElems.push(clone);
DragZoneDirective.HITTEST = true;
}
let index = this.dragZoneElems.indexOf(obj);
if (index > -1)
this.dragZoneElems.splice(index, 1);
});
You can't use Angular binding that is checked by Angular change detection on static fields.
You could add a getter on a component that forwards to that static field, then a binding to that getter would be checked by Angulars change detection.
IMHO the preferred way is to use an Observable that emits an event on change. Interested code can subscribe and get notified about updates.

freeze wpf app during update binding source

I created thumbnails based on ListView control. On ListView.ItemSource I bind ObservableColletion<Photos> Photos{get;set}.
I create thumbnail images in another threads also in parallel way.
I simplified my code.
public class ThumbnailCreator
{
public static List<Photos> CreateThumbnailImage(List<Photos> photos)
{
var thumbnails = new List<Photos>();
Parallel.ForEach(photos, photo =>
{
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.DecodePixelHeight = 128;
bitmap.DecodePixelWidth = 128;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.CreateOptions = BitmapCreateOptions.DelayCreation;
bitmap.UriSource = new Uri(photo.FullPath);
bitmap.EndInit();
if (bitmap.CanFreeze)
bitmap.Freeze();
thumbnails.Add(new Photos{ThumbnailImage = bitmap});
});
return thumbnails;
}
}
Problem is here:
//I break binding before I start refreshing thumbnails
this.Thumbnails.ItemsSource = null;
//load files from folder
List<Photos> photos = _fileManager.LoadFromDir(folderBrowserDialog.SelectedPath);
//create thumbnail images in another threads, not on UI
List<Photos> thumbnails = ThumbnailCreator.CreateThumbnailImage(photos);
//create new source
Photos = new ObservableCollection<Photos>(thumbnails);
//reenable binding, this part of code cause that UI free
this.Thumbnails.ItemsSource = Photos;
When I reenable binding UI freeze, I tried use dispatcher but result is same UI freeze.
this.Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() =>
{
Photos = new ObservableCollection<Photos>(thumbnails);
this.Thumbnails.ItemsSource = Photos;
}));
How can I avoid freeze UI?
EDITED:
I edited my code based on Dean K. advice. I dont break bind before update source of listview.
I updated source of ListView.ItemSource via Dispatcher:
Sync Invoke:
App.Current.Dispatcher.Invoke(new Action(() =>
{
thumbnails.Add(new Photos { ThumbnailImage = bitmap });
}), DispatcherPriority.ContextIdle);
Result - UI behavior.
Images are being added continuously but if collection contains more than 500 images at the and WPF window freezes. For example it is not possible move window, scroll listview.
Async Invoke
App.Current.Dispatcher.InvokeAsync(new Action(() =>
{
thumbnails.Add(new Photos { ThumbnailImage = bitmap });
}), DispatcherPriority.ContextIdle);
Result - UI behavior.
At start app freezes but after several seconds images are being added continously and also is it possible move window, scroll listview.
So my question is what is root of problem that app freezes ? How can I avoid this behaviour. I upload sample application.
Don't break the binding before adding items to the ObservableCollection.
Bind Thumbnails.ItemsSource to Photos OC and than on another thread load and add items to Photos OC. That way your UI will not freeze.
You might want to use the multithreaded ObservableColleciton you can find on code project. Search for ObservableCollectionMt...

Resources