The following code is an example to explain my issue.
I have a textbox in binding. When I click on a button, executes a function. (In this case it's a for loop).
Now I want, the text box updated with the content of the i variable. (public void MyAction())
So, I made a thread, but this doesn't work.
Why ?
Thanks in advance
XAML code
<TextBox Text ="{Binding MyValue}" HorizontalAlignment="Left" Height="47" Margin="4,4,4,4" VerticalAlignment="Top" Width="342"/>
<Button Command="{Binding ClickCommand}" Content="Run" Margin="114,69,283,216"/>
C# code
class Vm_Main : ViewModelBase
{
public string _MyValue { get; set; } //String in my XAML
public string MyValue
{
get { return _MyValue; }
set
{
_MyValue = value;
base.OnPropertyChanged("MyValue");
}
}
private bool _canExecute=true;
private ICommand _clickCommand;
public ICommand ClickCommand
{
get
{
return _clickCommand ?? (_clickCommand = new CommandHandler(() => MyAction(), _canExecute));
}
}
public Vm_Main()
{
MyValue = "Hallo"; //Default value
}
public void MyAction() // This is the function where I want update the TextBox in Binding
{
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
workerThread.Start();
for (int i = 1; i <= 10; i++)
{
MyValue = i.ToString();
workerObject.Value = MyValue;
Thread.Sleep(500);
}
workerObject.RequestStop();
workerThread.Join();
MessageBox.Show("End");
}
}
// The THREAD
public class Worker : ViewModelBase
{
// This method will be called when the thread is started.
public string _Value { get; set; }
public string Value
{
get { return _Value; }
set
{
_Value = value;
base.OnPropertyChanged("Value");
}
}
public void DoWork()
{
while (!_shouldStop)
{
Console.WriteLine("Value is..." + _Value);
}
Console.WriteLine("End.");
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data
// member will be accessed by multiple threads.
private volatile bool _shouldStop;
}
And Class ViewModelBase and Class Command
public abstract class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string strPropertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(strPropertyName));
}
#endregion
#region Messages and Progressbar
private string _errorMessage;
public string ErrorMessage
{
get { return _errorMessage; }
set
{
if (_errorMessage == value) return;
_errorMessage = value;
OnPropertyChanged("ErrorMessage");
}
}
private string _errorTooltip;
public string ErrorTooltip
{
get { return _errorTooltip; }
set
{
if (_errorTooltip == value) return;
_errorTooltip = value;
this.OnPropertyChanged("ErrorTooltip");
}
}
private string _statusMessage;
public string StatusMessage
{
get { return _statusMessage; }
set
{
if (_statusMessage == value) return;
_statusMessage = value;
//pulizia dei messaggi di errore
ErrorMessage = string.Empty;
ErrorTooltip = string.Empty;
OnPropertyChanged("StatusMessage");
}
}
protected void ClearMessage()
{
ErrorMessage = string.Empty;
StatusMessage = string.Empty;
}
private int _currentProgress;
public int CurrentProgress
{
get { return _currentProgress; }
set
{
_currentProgress = value;
OnPropertyChanged("CurrentProgress");
}
}
#endregion
protected ViewModelBase()
{
}
}
public class CommandHandler : ICommand
{
private Action _action;
private bool _canExecute;
public CommandHandler(Action action, bool canExecute)
{
_action = action;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
_action();
}
}
So I think you have to issues.
First use async await pattern.
It goes like this - to not block ur UI thread.
public async Task<object> MyAsyncMethod()
{
return await Task.Run<object>(() =>
{
return null;
});
}
or for ICommand just:
public async void MyAsyncMethod()
{
await Task.Run(() =>
{
});
}
Second is that you may want to update your UI - while processing async. This is a common problem for updating progress for example. You can solve this with SynchronizationContext.
public interface IUpdateProgess
{
void SendMessage(string val);
}
public async Task<object> MyAsyncMethod(IUpdateProgess progress)
{
//UI thread
SynchronizationContext context = SynchronizationContext.Current;
return await Task.Run<object>(() =>
{
//other thread
if (context != null && progress != null)
{
context.Post(new SendOrPostCallback((o) =>
{
progress.SendMessage("Progress");
}), null);
}
return null;
});
}
You can use this obviously to not just update progress - i think you get the idea.
Related
I am working on WPF (MVVM) ..
using this tutorial :
https://www.tutorialspoint.com/mvvm/mvvm_validations.htm
when trying to implement "AddEditCustomerViewModel"
I received two errors for this class:
namespace MVVMHierarchiesDemo.ViewModel
{
class AddEditCustomerViewModel : BindableBase
{
public AddEditCustomerViewModel()
{
CancelCommand = new MyICommand(OnCancel);
SaveCommand = new MyICommand(OnSave, CanSave);
}
private bool _EditMode;
public bool EditMode
{
get { return _EditMode; }
set { SetProperty(ref _EditMode, value); }
}
private SimpleEditableCustomer _Customer;
public SimpleEditableCustomer Customer
{
get { return _Customer; }
set { SetProperty(ref _Customer, value); }
}
private Customer _editingCustomer = null;
public void SetCustomer(Customer cust)
{
_editingCustomer = cust;
if (Customer != null) Customer.ErrorsChanged -= RaiseCanExecuteChanged;
Customer = new SimpleEditableCustomer();
Customer.ErrorsChanged += RaiseCanExecuteChanged;
CopyCustomer(cust, Customer);
}
private void RaiseCanExecuteChanged(object sender, EventArgs e)
{
SaveCommand.RaiseCanExecuteChanged();
}
public MyICommand CancelCommand { get; private set; }
public MyICommand SaveCommand { get; private set; }
public event Action Done = delegate { };
private void OnCancel()
{
Done();
}
private async void OnSave()
{
Done();
}
private bool CanSave()
{
return !Customer.HasErrors;
}
}
}
First one;on this lines :
CancelCommand = new MyICommand(OnCancel);
SaveCommand = new MyICommand(OnSave, CanSave);
an error appear on MyICommand constructor as in :
Error CS0305 Using the generic type 'MyICommand' requires 1 type
arguments
Second one , on this line :
CopyCustomer(cust, Customer);
an error appear for CopyCustomer function as in :
Error CS0103 The name 'CopyCustomer' does not exist in the current
context
the implementation of MyICommand as in :
public class MyICommand<T> : ICommand
{
Action<T> _TargetExecuteMethod;
Func<T, bool> _TargetCanExecuteMethod;
public MyICommand(Action<T> executeMethod)
{
_TargetExecuteMethod = executeMethod;
}
public MyICommand(Action<T> executeMethod, Func<T, bool> canExecuteMethod)
{
_TargetExecuteMethod = executeMethod;
_TargetCanExecuteMethod = canExecuteMethod;
}
public void RaiseCanExecuteChanged()
{
CanExecuteChanged(this, EventArgs.Empty);
}
#region ICommand Members
bool ICommand.CanExecute(object parameter)
{
if (_TargetCanExecuteMethod != null)
{
T tparm = (T)parameter;
return _TargetCanExecuteMethod(tparm);
}
if (_TargetExecuteMethod != null)
{
return true;
}
return false;
}
// Beware - should use weak references if command instance lifetime is
//longer than lifetime of UI objects that get hooked up to command
// Prism commands solve this in their implementation
public event EventHandler CanExecuteChanged = delegate { };
void ICommand.Execute(object parameter)
{
if (_TargetExecuteMethod != null)
{
_TargetExecuteMethod((T)parameter);
}
}
#endregion
}
}
to see the whole Project folder ; please see this link :
https://drive.google.com/drive/folders/1jFDU6vDMW_TO0J88NT53oLVWVYbAYyTv?usp=sharing
I'm trying to report progress to my status bar when creating a zip file.
For reporting the progress of the creation i have used the following guide:
ZipFile Creation Report Progress
My status bar is currently updated using 2 classes:
an INotifyPropertyChanged class called StatusBar
a separate class called Status.
The StatusBar class:
public class StatusBar : INotifyPropertyChanged
{
private string _message;
private string _submessage;
private bool _isindeterminate;
private bool _visible;
private int _min;
private int _max;
private double _progress;
public event PropertyChangedEventHandler PropertyChanged;
public StatusBar() { }
public int Min
{
get { return this._min; }
set
{
this._min = value;
this.OnPropertyChanged("Min");
}
}
public int Max
{
get { return this._max; }
set
{
this._max = value;
this.OnPropertyChanged("Max");
}
}
public double Progress
{
get { return this._progress; }
set
{
this._progress = value;
this.OnPropertyChanged("Progress");
}
}
public string Message
{
get { return this._message; }
set
{
this._message = value;
this.OnPropertyChanged("Message");
}
}
public string SubMessage
{
get { return this._submessage; }
set
{
this._submessage = value;
this.OnPropertyChanged("SubMessage");
}
}
public bool IsIndeterminate
{
get { return this._isindeterminate; }
set
{
this._isindeterminate = value;
this.OnPropertyChanged("IsIndeterminate");
}
}
public bool Visible
{
get { return this._visible; }
set
{
this._visible = value;
this.OnPropertyChanged("Visible");
}
}
void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
The Status class:
public class Status
{
public static void Initialise(StatusBar status, string _message, string _submessage, int _min, int _max, double _progress, bool _visible, bool _isindeterminate)
{
status.Visible = _visible;
if (_isindeterminate == false)
{
status.Message = _message;
status.SubMessage = _submessage;
status.Progress = _progress;
status.Min = _min;
status.Max = _max;
status.IsIndeterminate = _isindeterminate;
}
else
{
status.Message = _message;
status.IsIndeterminate = _isindeterminate;
}
}
public static void UpdateProgress(StatusBar status, double _progress)
{
if (_progress == status.Max)
{
Complete(status);
}
else
{
status.Progress = _progress;
}
}
public static void UpdateMessage(StatusBar status, string _message)
{
status.Message = _message;
}
public static void UpdateSubMessage(StatusBar status, string _submessage)
{
status.SubMessage = _submessage;
}
public static void UpdateProgressMessage(StatusBar status, string _message, double _progress)
{
status.Message = _message;
status.Progress = _progress;
}
public static void Complete(StatusBar status)
{
status.Message = "Ready";
status.SubMessage = " ";
status.Min = 0;
status.Max = 0;
status.Progress = 0;
status.Visible = false;
status.IsIndeterminate = false;
}
}
For creating the zip file and updating the status bar I currently have the following:
string sourceDirectory = "C:\\Access\\Test";
string archive = #"C:\Access\Test.zip";
Status.Initialise(statusbar, "Creating Zip File...", "", 0, 100, 0, true, false);
Backup.CreateFromDirectory(sourceDirectory, archive,
new BasicProgress<double>(p => Status.UpdateProgressMessage(statusbar, $"{p:P2} archiving complete", p)));
The code above is working and the Zip file is created.
However the progress is only reported once the process has been completed and not during the process.
How can I change this to update the progress during the zip file creation?
I am trying to implement a searchbar using MVVM in Xamarin.forms. so far I have managed to borrow some code from around the internet and it seems to do go through the motions of the search. the only issue is I don't know what code to put in the command.
I would like the search bar to search recipeNames from a list of Recipes. this information is all stored on a local database and displayed using an observable collection.
please can you help me work it out.
XAML
<SearchBar x:Name="SearchBar"
Placeholder="Search"
SearchCommand="{Binding SearchCommand}"
SearchCommandParameter="{Binding Text, Source={x:Reference SearchBar}}"
Text="{Binding SearchText, Mode=TwoWay}">
<SearchBar.Behaviors>
<local:TextChangedBehavior />
</SearchBar.Behaviors>
</SearchBar>
<ListView x:Name="ListViewItems"
ItemsSource="{Binding Recipes}"
IsPullToRefreshEnabled="True"
Refreshing="ListViewItems_Refreshing"
SelectedItem="{Binding SelectedRecipe}">
Text changed Behaviour
class TextChangedBehavior: Behavior<Xamarin.Forms.SearchBar>
{
protected override void OnAttachedTo(Xamarin.Forms.SearchBar bindable)
{
base.OnAttachedTo(bindable);
bindable.TextChanged += Bindable_TextChanged;
}
protected override void OnDetachingFrom(Xamarin.Forms.SearchBar bindable)
{
base.OnDetachingFrom(bindable);
bindable.TextChanged -= Bindable_TextChanged;
}
private void Bindable_TextChanged(object sender, TextChangedEventArgs e)
{
((Xamarin.Forms.SearchBar)sender).SearchCommand?.Execute(e.NewTextValue);
}
}
and viewModel
public class RecipeListViewModel : ObservableCollection<Recipe>
{
private ObservableCollection<Recipe> Recipes {get; set;}
public INavigation Navigation { get; internal set; }
public ICommand NewAddPage { get; protected set; }
public RecipeListViewModel(INavigation navigation)
{
this.Navigation = navigation;
Recipes = new ObservableCollection<Recipe>();
this.NewAddPage = new Command(async () => await CreateNewAddPage());
Init();
}
// Gets all recipes from the database and adds them to the observable collection
private void Init()
{
var enumarator = App.RecipeDbcontroller.GetRecipe();
if (enumarator == null)
{
App.RecipeDbcontroller.SaveRecipe(new Recipe { RecipeName = "Moussaka", Serves = 6, PrepTime = "30", CookTime = "2 Hours", MealType = "Dinner" });
enumarator = App.RecipeDbcontroller.GetRecipe();
}
while (enumarator.MoveNext())
{
//cleans database of all empty records
if (enumarator.Current.RecipeName == null || enumarator.Current.CookTime == null)
{
App.RecipeDbcontroller.DeleteRecipe(enumarator.Current.RecipeID);
}
else
Add(enumarator.Current);
}
}
private ICommand _searchCommand;
public ICommand SearchCommand
{
get
{
return _searchCommand ?? (_searchCommand = new Command<string>((text) =>
{
**// THIS IS WHAT I DON'T KNOW WHAT TO DO**
}));
}
}
private string _searchText { get; set; }
public string SearchText
{
get { return _searchText; }
set
{
if (_searchText != value)
{
_searchText = value;
}
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
RecipeDatabaseController Class
public RecipeDatabaseController()
{
this.database = DependencyService.Get<ISQLite>().GetConnection();
this.database.CreateTable<Recipe>();
}
//Recipe CRUD
public IEnumerator<Recipe> GetRecipe()
{
lock (locker)
{
if (database.Table<Recipe>().Count() == 0)
{
return null;
}
else
{
return this.database.Table<Recipe>().GetEnumerator();
}
}
}
public IEnumerator<Recipe> GetRecipeBySearchTerm(text)
{
var enumarator = GetRecipe();
lock (locker)
{
while (enumarator.MoveNext)
{
if(enumarator.Current.RecipeName.Contains(text)
return this.
}
}
}
public int SaveRecipe(Recipe recipe)
{
lock (locker)
{
if (recipe.RecipeID != 0)
{
this.database.Update(recipe);
return recipe.RecipeID;
}
else
{
return this.database.Insert(recipe);
}
}
}
public int DeleteRecipe(int Id)
{
lock (locker)
{
return this.database.Delete<Recipe>(Id);
}
}
right so the search command ought to look like this.
public ICommand SearchCommand => _searchCommand ?? (_searchCommand = new Command<string>((text) =>
{
if (text.Length >=1)
{
Recipes.Clear();
Init();
var suggestions = Recipes.Where(c => c.RecipeName.ToLower().StartsWith(text.ToLower())).ToList();
Recipes.Clear();
foreach (var recipe in suggestions)
Recipes.Add(recipe);
}
else
{
Recipes.Clear();
Init();
ListViewVisible = true;
SuggestionsListViewVisible = false;
}
}));
using System.Linq;
//Recipe CRUD
public IEnumerable<Recipe> GetRecipe()
{
lock (locker)
{
return this.database.Table<Recipe>();
}
}
public IEnumerable<Recipe> GetRecipeBySearchTerm(string text)
{
var recipes = GetRecipe();
lock (locker)
{
return recipes.Where(m => m.RecipeName.ToLower().Contains(text));
}
}
Add the using System.Linq reference
Change those two methods and return IEnumerable
Note. RecipeName is the property you want to filter your Recipe with.
And your search command as below
private ICommand _searchCommand;
public ICommand SearchCommand
{
get
{
return _searchCommand ?? (_searchCommand = new Command<string>((text) =>
{
var filteredRecipes = App.RecipeDbcontroller.GetRecipeBySearchTerm(text);
recipes.Clear();
foreach(var recipe in filteredRecipes )
recipes.Add(recipe);
}));
}
}
I have not tested this code, so not sure where I might get errors, but you can work out the rest because the logic is given to you
Good luck
I have a MvxDialogFragment and I want to show that using ViewModel, similarly when a activity is showed from ViewModel using ShowViewModel. Is it possible? How can I do that?
This is my scenario: I have a page that contains a MvxListView and, when the user click in a listview item, I want to show a MvxDialogFragment.
My ListView layout:
<Mvx.MvxListView
android:id="#+id/lstViewTasks"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:dividerHeight="1px"
android:clickable="true"
android:focusableInTouchMode="true"
android:choiceMode="multipleChoice"
android:layout_alignParentTop="true"
local:MvxBind="ItemsSource Tasks; ItemClick ItemClickCommand"
local:MvxItemTemplate="#layout/projectmytasksitem" />
My ListView ViewModel:
public class ProjectMyTasksViewModel : MvxViewModel
{
#region [Atributos privados]
private ProjectService _service;
#endregion
#region [Propriedades]
private IList<Task> _tasks;
public IList<Task> Tasks
{
get { return _tasks; }
set { _tasks = value; RaisePropertyChanged(() => Tasks); }
}
private bool _isListaVazia;
public bool IsListaVazia
{
get { return _isListaVazia; }
set { _isListaVazia = value; RaisePropertyChanged(() => IsListaVazia); }
}
private Task _selectedTask;
public Task SelectedTask
{
get { return _selectedTask; }
set { _selectedTask = value; RaisePropertyChanged(() => SelectedTask); }
}
private string _mensagemErro;
public string MensagemErro
{
get { return _mensagemErro; }
set { _mensagemErro = value; RaisePropertyChanged(() => MensagemErro); }
}
#endregion
#region [Commands]
private IMvxCommand _itenClickCommand;
public IMvxCommand ItemClickCommand
{
get
{
this._itenClickCommand = this._itenClickCommand ?? new MvxCommand<Task>(this.ExecuteItemClickCommand);
return _itenClickCommand;
}
}
#endregion
#region [Construtores]
public ProjectMyTasksViewModel()
{
_service = new ProjectService();
this.CriaListaTeste();
IsListaVazia = (Tasks.Count > 0) ? true : false;
}
#endregion
#region [Execuções dos Comandos]
private void ExecuteItemClickCommand(Task task)
{
Dictionary<string, Task> parametros = new Dictionary<string, Task>()
{
{"Task", task }
};
this.ShowViewModel<TaskViewModel>(parametros);
}
#endregion
#region [Métodos]
public void CriaListaTeste()
{
Tasks = new List<Task>();
for (int indiceProjeto = 1; indiceProjeto <= 10; indiceProjeto++)
{
Tasks.Add(new Task { Name = $"Tarefa {indiceProjeto}", StartDate = DateTime.Now, FinishDate = DateTime.Now, IsCompleted = false });
}
}
#endregion
}
My Listview Activity:
[Activity(Label = "My Task",
ConfigurationChanges = ConfigChanges.Orientation,
ScreenOrientation = ScreenOrientation.Portrait)]
public class ProjectMyTasksView : MvxActivity
{
public new ProjectMyTasksViewModel viewModel
{
get { return (ProjectMyTasksViewModel)base.ViewModel; }
set { base.ViewModel = value; }
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
this.SetContentView(Resource.Layout.ProjectMyTasksView);
}
}
My Dialog Fragment:
public class ProjectMyTaskDialog : MvxDialogFragment<TaskViewModel>
{
public override Dialog OnCreateDialog(Bundle savedState)
{
base.EnsureBindingContextSet(savedState);
this.BindingInflate(Resource.Layout.ProjectMyTasksDialog, null);
return base.OnCreateDialog(savedState);
}
}
My Dialog Fragment ViewModel:
public class TaskViewModel : BaseViewModel<TaskService, Task>
{
#region [Atributos Privados]
private readonly IMvxPictureChooserTask _pictureChooserTask;
#endregion
#region [Commands]
private MvxCommand _chooseImageCommand;
public MvxCommand ChooseImageCommand
{
get
{
_chooseImageCommand = _chooseImageCommand ?? new MvxCommand(ExecuteChooseImageCommand);
return _chooseImageCommand;
}
}
private MvxCommand _takePictureCommand;
public MvxCommand TakePictureCommand
{
get
{
_takePictureCommand = _takePictureCommand ?? new MvxCommand(ExecuteTakePictureCommand);
return _takePictureCommand;
}
}
private MvxCommand _completeTaskCommand;
public MvxCommand CompleteTaskCommand
{
get
{
_completeTaskCommand = _completeTaskCommand ?? new MvxCommand(ExecuteCompleteTaskCommand);
return _completeTaskCommand;
}
}
#endregion
#region [Construtores]
public TaskViewModel(IMvxPictureChooserTask pictureChooserTask)
{
_pictureChooserTask = pictureChooserTask;
}
#endregion
#region [Execuções dos Comandos]
private void ExecuteChooseImageCommand()
{
_pictureChooserTask.ChoosePictureFromLibrary(400, 95, OnImage, () => { });
}
private void ExecuteTakePictureCommand()
{
_pictureChooserTask.TakePicture(400, 95, OnImage, () => { });
}
public void ExecuteCompleteTaskCommand()
{
throw new NotImplementedException();
}
#endregion
#region [Métodos]
public void Init(Dictionary<string, Task> parametros)
{
Objeto = parametros["Task"];
}
private void OnImage(Stream imageStream)
{
var memoryStream = new MemoryStream();
imageStream.CopyTo(memoryStream);
Objeto.Image = memoryStream.ToArray();
}
#endregion
public class Parametros
{
public string TaskJson { get; set; }
}
}
There is no presenter for DialogFragments.
Instead you could have instantiate the Command from the Activity or have a callback into the Activity which determines what to do when the command is called, i.e. displaying the Dialog.
So for a simple example:
public class MyViewModel : MvxViewModel
{
public Action ShowTaskCommandAction {get;set;}
private MvxCommand _showTaskCommand;
public ICommand ShowTaskCommand =>
_showTaskCommand = _showTaskCommand ?? (_showTaskCommand = new MvxCommand(DoShowTaskCommand));
private void DoShowTaskCommand()
{
CommandAction?.Invoke();
// do other stuff here...
}
}
Then in your Activity or Fragment:
public class MyActivity : MvxActivity<MyViewModel>
{
public void OnCreate(Bundle _)
{
base.OnCreate(_);
ViewModel.ShowTaskCommandAction = () => {
var dialogFragment = new ProjectMyTaskDialog() {
DataContext = task
});
dialogFragment.Show(FragmentManager);
};
// whatever else code
}
}
I have simple app, where ObservableCollection is updating in code and when new item added the UI is updated too. To update UI i am using a Dispatcher which is passed as a property to ViewModel. My code is works, but i don't know right i am or not.
Here is the code:
MainWindow.xaml.cs
/// <summary>
/// Логика взаимодействия для MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
MainWindowViewModel model = new MainWindowViewModel();
public MainWindow()
{
InitializeComponent();
this.DataContext = model;
this.model.dispatcher = this.Dispatcher;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
string url = urlToCheck.Text;
Task task = new Task(() =>
{
model.GetUrls(url);
});
task.ContinueWith((previousTask) =>
{
label.Content = "Все ссылки собраны.";
},
TaskScheduler.FromCurrentSynchronizationContext());
label.Content = "Идёт сбор ссылок...";
task.Start();
}
}
MainWindowViewModel.cs
class MainWindowViewModel
{
public ObservableCollection<Url> Urls { get; set; }
public bool NeedToGetResponseForChildUrls { get; set; }
public bool NeedToDeletePreviousResults { get; set; }
public Dispatcher dispatcher;
some code.....................
**and something like this i am updating ObservableCollection:**
if (NeedToDeletePreviousResults)
{
dispatcher.Invoke(() =>
{
Urls.Clear();
});
}
Url.cs
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace CheckUrl
{
public class Url : INotifyPropertyChanged
{
private string _absoluteUrl;
public string AbsoluteUrl
{
get { return _absoluteUrl; }
set
{
if (_absoluteUrl != value)
{
_absoluteUrl = value;
OnPropertyChanged("AbsoluteUrl");
}
}
}
private int _responseStatusCode;
public int ResponseStatusCode
{
get { return _responseStatusCode; }
set
{
if (_responseStatusCode != value)
{
_responseStatusCode = value;
OnPropertyChanged("ResponseStatusCode");
}
}
}
private string _responseStatusDescription;
public string ResponseStatusDescription
{
get { return _responseStatusDescription; }
set
{
if (_responseStatusDescription != value)
{
_responseStatusDescription = value;
OnPropertyChanged("ResponseStatusDescription");
}
}
}
public enum Status { Working, Broken };
private Status _urlStatus;
public Status UrlStatus
{
get { return _urlStatus; }
set
{
if (_urlStatus != value)
{
_urlStatus = value;
OnPropertyChanged("UrlStatus");
}
}
}
private string _color;
public string Color
{
get { return _color; }
set
{
if (_color != value)
{
_color = value;
OnPropertyChanged("Color");
}
}
}
private ObservableCollection<ChildUrl> _childUrlsValue = new ObservableCollection<ChildUrl>();
public ObservableCollection<ChildUrl> ChildUrls
{
get
{
return _childUrlsValue;
}
set
{
_childUrlsValue = value;
}
}
/// <summary>
/// Конструктор класса Url.
/// </summary>
public Url(string absoluteUrl, int responseStatusCode, string responseStatusDescription, Status urlStatus, string color)
{
this.AbsoluteUrl = absoluteUrl;
this.ResponseStatusCode = responseStatusCode;
this.ResponseStatusDescription = responseStatusDescription;
this.UrlStatus = urlStatus;
this.Color = color;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
ObservableCollection can update your UI automaticaly by using binding. Use a list of ObservableCollection and add / remove items from is. Make the ObservableCollection as a public property.In the MainWindow constructor write:
This.DataContext=This;
Use binding to your listBox / any other control you need to show the items on. ObservableCollection allready implement IINotifyPropertyChanged in it. Once you change the items in your ObservableCollection your UI will change as well.