I'm trying to bind data in my data context but service is returning null. I'm using ninject as DI. I'm sharing my app.xaml.cs code. Please guide me.
public partial class App
{
private IKernel container;
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
AutoMapperConfig.RegisterMappings();
ConfigureContainer();
ComposeObjects();
Current.MainWindow.Show();
}
private void ConfigureContainer()
{
this.container = new StandardKernel();
container.Bind(typeof(IAppServiceBase<>)).To(typeof(AppServiceBase<>));
container.Bind<IJvDetailAppService>().To<JvDetailAppService>().InSingletonScope();
container.Bind<IJvMasterAppService>().To<JvMasterAppService>().InSingletonScope();
container.Bind<IJvDimensionAppService>().To<JvDimensionAppService>().InSingletonScope();
container.Bind(typeof(IServiceBase<>)).To(typeof(ServiceBase<>));
container.Bind<IJvDetailService>().To<JvDetailService>();
container.Bind<IJvMasterService>().To<JvMasterService>();
container.Bind<IJvDimensionService>().To<JvDimensionService>();
container.Bind(typeof(IRepositoryBase<>)).To(typeof(RepositoryBase<>));
container.Bind<IJvDetailRepository>().To<JvDetailRepository>();
container.Bind<IJvMasterRepository>().To<JvMasterRepository>();
container.Bind<IJvDimensionRepository>().To<JvDimensionRepository>();
}
private void ComposeObjects()
{
Current.MainWindow = this.container.Get<MainWindow>();
Current.MainWindow.Title = "JustApp";
}
}
MainWindowViewModel
public class MainWindowViewModel : ViewModelBase
{
private readonly BackgroundWorker _worker = new BackgroundWorker();
private ObservableCollection<JvDetailViewModelBase> _jvDetailMenu;
private readonly IJvDetailAppService _jvDetailAppService;
public ObservableCollection<JvDetailViewModelBase> JvDetailMenu
{
get { return this._jvDetailMenu; }
set
{
_jvDetailMenu = value;
RaisedPropertyChanged("JvDetailMenu");
}
}
public MainWindowViewModel()
{
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
}
readonly ObservableCollection<JvDetailViewModelBase> _tempProductMenu = new ObservableCollection<JvDetailViewModelBase>();
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
_tempProductMenu.Add(new ModifyJvDetailViewModel(_jvDetailAppService));
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (_tempProductMenu.Any())
{
JvDetailMenu = _tempProductMenu;
}
}
}
ModifyJvDetailViewModel.cs
public class ModifyJvDetailViewModel : JvDetailViewModelBase
{
private readonly BackgroundWorker _worker = new BackgroundWorker();
private IEnumerable<JvDetail> _tempLoadJvDetails;
private readonly IJvDetailAppService _jvDetailAppService;
private void worker_DoWork(object sender, DoWorkEventArgs e)
{
int ab = _jvDetailAppService.GetByCompanyId(3).Count(); // it is returning null here and everywhere which is fetching records.
_tempLoadJvDetails = _jvDetailAppService.GetByCompanyId(3);
}
private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
JvDetails = _tempLoadJvDetails;
}
public override string Name
{
get { return JustAppHelper.JvDetail; }
}
public override string Icon
{
get { return JustAppHelper.JvDetailIcon; }
}
public ModifyJvDetailViewModel(IJvDetailAppService jvDetailAppService)
{
_jvDetailAppService = jvDetailAppService;
var ab = _jvDetailAppService.GetAll().Count();
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
BindGrid();
}
protected void BindGrid()
{
JvDetails = _jvDetailAppService.GetByCompanyId(3);
}
private IEnumerable<JvDetail> _jvDetails;
public IEnumerable<JvDetail> JvDetails
{
get { return _jvDetails; }
set
{
_jvDetails = value;
RaisedPropertyChanged("JvDetails");
}
}
}
Mainwindow.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainWindowViewModel();
ListBoxProducts.SelectedIndex = 0;
}
}
One approach would be to change MainWindowViewModel constructor:
public MainWindowViewModel(IJvDetailAppService detailAppService)
{
_jvDetailAppService = detailAppService;
_worker.DoWork += worker_DoWork;
_worker.RunWorkerCompleted += worker_RunWorkerCompleted;
_worker.RunWorkerAsync();
}
and MainWindow constructor:
public MainWindow(IJvDetailAppService detailAppService)
{
InitializeComponent();
this.DataContext = new MainWindowViewModel(detailAppService);
ListBoxProducts.SelectedIndex = 0;
}
Related
I'm working on a C# app,that searches for song names on youtube (using youtube api) and displaying the data, I have a custom SongItem (UserControl) and I add them to a FlowLayoutControl. I added a "Favourite" button to the UserControl, and I need that to add itself to another FlowLayoutControl that's the Favourited song list, but I can't get that working, I can't have multiple base classes in the UserControl,and adding a public method to Form1, doesn't solve my issue, (it's not adding anything,tried it with listbox,but nothing).
I'm really stuck here,if someone can at least suggest something I would rly appreciate it.
Here is my SongItem
[Serializable]
public partial class SongItem : UserControl,Form
{
private String songName = "Song Name";
private String artistName = "Artist Name";
private Image thumbNail;
private String length;
private int maxLengthSongName = 25;
private int maxLengthArtistName = 25;
private Color colorHoverOn = Color.FromArgb(53,53,53);
private Color colorNormal = Color.FromArgb(53,53,53);
private SongData songData;
public SongItem()
{
InitializeComponent();
this.MouseClick += Control_MouseClick;
MouseEvents(this);
}
private void SongItem_Load(object sender, EventArgs e)
{
try
{
LoadData();
}
catch { }
LoadDataToUI();
}
#region GettersAndSetters
public int MaxLengthSongName
{
get { return maxLengthSongName; }
set { maxLengthSongName = value; }
}
public int MaxLengthArtistName
{
get { return maxLengthArtistName; }
set { maxLengthArtistName = value; }
}
public Color ColorHoverOn
{
get { return colorHoverOn; }
set { colorHoverOn = value; }
}
public Color ColorNormal
{
get { return colorNormal; }
set { colorNormal = value; }
}
public SongData SongData {
get{return songData; }
set { songData = value; }
}
#endregion
public void LoadData()
{
songName = songData.SongName;
artistName = songData.ArtistName;
thumbNail = songData.ThumbNail;
length = songData.Length;
}
void MouseEvents(Control container)
{
foreach (Control c in container.Controls)
{
c.MouseEnter += (s, e) => SongItem_MouseEnter(e);
c.MouseLeave += (s, e) => SongItem_MouseLeave(e);
c.MouseClick += Control_MouseClick;
MouseEvents(c);
};
}
private void SongNameLbl_MouseHover(object sender, EventArgs e)
{
if (songName.Length > maxLengthSongName) {
toolTip1.SetToolTip(songNameLbl, songName);
}
}
private void ArtistNameLbl_MouseHover(object sender, EventArgs e)
{
if (artistName.Length > maxLengthArtistName) {
toolTip1.SetToolTip(artistNameLbl, artistName);
}
}
private void SongNameLbl_Click(object sender, EventArgs e)
{
Clipboard.SetText(artistName + " " +songName);
}
#endregion
#region CurrentlySelected
public event EventHandler<EventArgs> WasClicked;
private void Control_MouseClick(object sender, MouseEventArgs e)
{
var wasClicked = WasClicked;
if (wasClicked != null)
{
WasClicked(this, EventArgs.Empty);
}
IsSelected = true;
}
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
this.BorderStyle = IsSelected ? BorderStyle.FixedSingle : BorderStyle.None;
}
}
#endregion
private void Fovourite_Click(object sender, EventArgs e)
{
Main newMain = new Main();
// newMain.AddSongToFavorite();
newMain.listBox1.Items.Add("Test");
}
}
}
Here is the the Form1 code
public void AddSongToFavorite() {
listBox1.Items.Add("Test");
//songList2.AddSong("Dire Straits - Sultans Of Swing");
MessageBox.Show("Hello", "Test");
// flowLayoutPanel1.Controls.Add(song);
}
Message shows up,but nothing else
I add the SongItem from another class
public partial class SongList : FlowLayoutPanel
{
public SongList()
{
InitializeComponent();
SongList_Load();
}
private void SongList_Load()
{
this.AutoScroll = true;
this.FlowDirection = FlowDirection.TopDown;
this.AutoSize = false;
this.WrapContents = false;
}
public async void AddSong(String songName) {
SongData song = await YoutubeSearch.GetSongInfo(songName);
// SongData song = XmlSerialization.ReadFromXmlFile<SongData>(Application.StartupPath + #"\test.txt");
SongItem songItem = new SongItem { SongData = song };
songItem.WasClicked += UsersGrid_WasClicked;
this.Controls.Add(songItem);
}
I fixed the problem by creating an EventHandler
In the main I created this public void
public void FavoriteWasClicked(object sender, EventArgs e) {
if (sender is SongItem)
{
songList2.AddSong(((SongItem)sender).SongData);
}
}
and on Form1 load I added (songList1 is the FlowLayoutPanel already added in the Form1 designer)
songList1.List_FavoriteWasClicked += FavoriteWasClicked;
I added this line to the FlowLayoutPanel class I created
public event EventHandler<EventArgs> List_FavoriteWasClicked;
and when creating new Controls(SongItems inside it)(Still part of FlowLayoutPanel)
public void AddSong(SongData song)
{
SongItem songItem = new SongItem { SongData = song };
songItem.FavoriteWasClicked += List_FavoriteWasClicked; ()
this.Controls.Add(songItem);
}
And now on the SongItem I created the custom event
public event EventHandler<EventArgs> FavoriteWasClicked;
and on the button I wanted to be the press to add to favorite list I added the following
FavoriteWasClicked(this, EventArgs.Empty);
Now when I press the button to add one Song to the liked/favorited list it's actually adding it.
I'm just trying to get a grasp of MVVM pattern in WPF (currently without any framework).
Scenario:
I have a main window, I click a button "Start work" that is bound to some command in the viewmodel. Progress dialog should open with "Cancel" button, it should show on the center of the owner window(so I need to pass the owner), I press cancel and I invoke "CancelAsync" method on background worker.
The principle of MVVM is that the view model should never know anything about the view and in my case I'm violating this rule.
Code-behind (No MVVM) solution:
Main window part:
private void Button_Click(object sender, RoutedEventArgs e)
{
backgroundWorker.RunWorkerAsync();
progressWindow = new ProgressWindow(backgroundWorker);
progressWindow.Owner = this;
progressWindow.ShowDialog();
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
progressWindow.Close();
}
Progress window part:
private void btnCancel_Click(object sender, RoutedEventArgs e)
{
backgroundWorker.CancelAsync();
}
My attempt to convert this code to MVVM (this is wrong)
public class MainViewModel
{
public ICommand DoSomething { get; }
private BackgroundWorker backgroundWorker;
private PleaseWaitView pleaseWaitView;
public MainViewModel()
{
backgroundWorker = new BackgroundWorker() { WorkerSupportsCancellation = true };
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
var pleaseWaitViewModel = new PleaseWaitViewModel(backgroundWorker);
pleaseWaitView = new PleaseWaitView();
pleaseWaitView.Owner = Application.Current.MainWindow;
pleaseWaitView.DataContext = pleaseWaitViewModel;
DoSomething = new ActionCommand<object>(DoSomethingImpl);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
pleaseWaitView.Close();
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Some work
Thread.Sleep(5000);
}
private void DoSomethingImpl(object parameter)
{
pleaseWaitView.ShowDialog();
}
}
How to solve this? I did what I wanted in code-behind in a matter of 20 minutes, I wanted to try MVVM pattern and it takes me few hours to solve simple problem.
I was looking at some solutions with EventAggregator but that requires using a framework like Prism, Caliburn.Micro. So I get some kind of communication between VM and the View.
You can pass an interface to MainViewModel which contains the needed methods
interface IMainView
{
void Init(PleaseWaitViewModel viewModel);
void ShowDialog();
void Close();
}
public class MainViewModel
{
private IMainView _view;
public MainViewModel(IMainView view)
{
_view = view;
backgroundWorker = new BackgroundWorker() { WorkerSupportsCancellation = true };
backgroundWorker.DoWork += BackgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted +=
BackgroundWorker_RunWorkerCompleted;
var pleaseWaitViewModel = new PleaseWaitViewModel(backgroundWorker);
_view.Init(pleaseWaitViewModel);
}
private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
_view.Close();
}
private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
// Some work
Thread.Sleep(5000);
}
private void DoSomethingImpl(object parameter)
{
_view.ShowDialog();
}
}
Messenger approach
public class PersonsViewModel
{
private RelayCommand _addPersonCommand = null;
public RelayCommand AddPersonCommand
{
get
{
return _addPersonCommand ?? (_addPersonCommand = new RelayCommand(
() =>
{
Action<Person> callback = (person) =>
{
_persons.Add(person);
RaisePropertyChanged("Persons");
};
Messenger.Default.Send<NotificationMessageAction<Person>>(new NotificationMessageAction<Person>(this, new Person(), "myNotification", callback), this);
}));
}
}
}
private PersonsViewModel _viewModel = null;
public PersonsView()
{
InitializeComponent();
DataContext = _viewModel = new PersonsViewModel();
Messenger.Default.Register<NotificationMessageAction<Person>>(this, _viewModel, message =>
{
if(message.Notification == "myNotification")
{
Person person = (Person)message.Target;
Action<Person> callback = message.Execute;
ModalView view = new ModalView(person);
if(true == view.ShowDialog())
{
callback.Invoke(view.Person);
}
}
});
}
Action property on view model approach
1) Add action property on the viewmodel
2) Wire it up in the view code behind
3) Invoke action it in the viewmodel logic where needed
using System;
using System.Windows;
using System.Windows.Input;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// Wire up CancelAction in the View
var windowToClose = new Window();
var castedContext = (ViewModel) DataContext;
castedContext.CancelAction = () => windowToClose.Close();
}
}
public class ViewModel
{
private ICommand _doSomethingCommand;
public Action CancelAction { get; set; }
public ICommand DoSomethingCommand
{
get
{
if (_doSomethingCommand != null)
return _doSomethingCommand;
_doSomethingCommand = new MyCommandImplementation(() =>
{
// Perform Logic
// If need to cancel - invoke cancel action
CancelAction.Invoke();
});
return _doSomethingCommand;
}
}
}
// Stubbed out for the sake of complete code
public class MyCommandImplementation : ICommand
{
public MyCommandImplementation(Action action)
{
throw new NotImplementedException();
}
public bool CanExecute(object parameter)
{
throw new NotImplementedException();
}
public void Execute(object parameter)
{
throw new NotImplementedException();
}
public event EventHandler CanExecuteChanged;
}
}
I am working on a project which requires to start a Timer on load of the Form1 that increments the TimerCount Property of Class TimeCounter in the tick event.
The Project has also Form2 which when open I want to read the increment updates from TimeCounter class which is being incremented by the Form1 because Form1 is parent and will not close I tried to read from TimeCounter but got default set value which is 0.
Here is code:
Timer Class
public class TimeCounter
{
public int timer=0;
public int TimerCount { get; set; }
public int GetTime()
{
return timer;
}
}
Form1 Increment TimerCount After 1 Second
private void Form1_Load(object sender, EventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += timer_Elapsed;
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
sk++;
Timer t = new Timer();
t.TimerCount = sk;
}
Form2 Which Receive Counter Continuously(But Not Working)
private void Form1_Load(object sender, EventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += timer_Elapsed;
timer.Enabled = true;
timer.Start();
}
void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Timer t1 = new Timer();
B01CountDown.Text = t1.GetTime().ToString();
}
You are not passing the Timer object correctly to Form2. You need to pass the instance of Timer being used by form 1 to form 2.
Timer:
public class Timer
{
public int timer = 0;
public int TimerCount { get; set; }
public int GetTime()
{
return timer;
}
}
Form1:
public partial class Form1 : Form
{
private Timer _timer;
public Form1()
{
InitializeComponent();
_timer = new Timer();
timer1.Start();
}
private void Form1_Load(object sender, EventArgs e)
{
timer1.Tick += timer1_Tick;
}
void timer1_Tick(object sender, EventArgs e)
{
_timer.TimerCount++;
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm2 = new Form2(_timer);
frm2.ShowDialog();
}
}
Form2:
public partial class Form2 : Form
{
public Timer _timer;
public Form2(Timer timer)
{
InitializeComponent();
_timer = timer;
timer1.Start();
}
private void Form2_Load(object sender, EventArgs e)
{
timer1.Tick += timer1_Tick;
}
void timer1_Tick(object sender, EventArgs e)
{
label1.Text = _timer.TimerCount.ToString();
}
}
Output:
I have modified the code you have posted as follows. If you do not understand, then you need to start learning C#.
TimeCounter:
public class TimeCounter
{
public static int timer = 0;
public static int TimerCount
{
get
{
return timer;
}
set
{
timer = value;
}
}
}
Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
new Form2().Show();
}
private void Form1_Load(object sender, EventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += timer_Elapsed;
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
TimeCounter.TimerCount++;
}
}
Form 2:
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += timer_Elapsed;
timer.Enabled = true;
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (B01CountDown.InvokeRequired)
{
B01CountDown.Invoke((MethodInvoker)(() =>
{
B01CountDown.Text = TimeCounter.TimerCount.ToString();
}));
}
}
}
Actually you don't require TimeCounter Class and also Timer in Form2
see below code
Form1
public partial class Form1 : Form
{
int sk = 0;
Form2 form2 = new Form2();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = 1000;
timer.Elapsed += timer_Elapsed;
timer.Start();
}
private void button1_Click_1(object sender, EventArgs e)
{
form2.Show();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// Do your Stuff
sk++;
form2.UpdateLabel(sk.ToString());
}
}
Form2
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public void UpdateLabel(string Message)
{
if (B01CountDown.InvokeRequired)
{
B01CountDown.Invoke((MethodInvoker)(() =>
{
B01CountDown.Text = Message;
}));
}
}
}
I'm trying to make a helper function to make BackgroundWorkers.
Here is what I have so far.
using System.ComponentModel;
using System;
public class BackgroundThread {
BackgroundWorker worker;
public BackgroundThread(Delegate workerFunction, Delegate workerCallback) {
this.worker = new BackgroundWorker();
this.worker.DoWork += new DoWorkEventHandler(workerFunction);
this.worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(workerCallback);
}
public void Start(object argument) {
this.worker.RunWorkerAsync(argument);
}
}
Although I am getting this error.
Expression denotes a 'variable', where a 'type' or 'method group' was expected
It makes sense since normally you pass a reference to a function to the Handlers but I don't know how to do it in this context. Or is this just not possible. I don't know enough about C# delegates and such to know what to do.
Like this?
public class BackgroundThread
{
System.ComponentModel.BackgroundWorker worker;
public BackgroundThread(System.ComponentModel.DoWorkEventHandler workerFunction, System.ComponentModel.RunWorkerCompletedEventHandler workerCallback)
{
this.worker = new System.ComponentModel.BackgroundWorker();
this.worker.DoWork += workerFunction;
this.worker.RunWorkerCompleted += workerCallback;
}
public BackgroundThread(Action<object> anyWorkFunctionWithObjectArgument, Action<object> anyCallback)
{
this.worker = new System.ComponentModel.BackgroundWorker();
this.worker.DoWork += (sender, e) => { anyWorkFunctionWithObjectArgument.Invoke(e.Argument); };
this.worker.RunWorkerCompleted += (sender, e) => { anyCallback.Invoke(e.Result); };
}
public void Start(object argument)
{
this.worker.RunWorkerAsync(argument);
}
public static BackgroundThread GetDoNothingInstance()
{
return new BackgroundThread(
(sender, e) =>
{
// e is DoWorkEventArgs
},
(sender, e) =>
{
// e is RunWorkerCompletedEventArgs
});
}
public static BackgroundThread GetDoNothingInstance2()
{
Action<object> workfunction = delegate(object argument)
{
// Do nothing
};
Action<object> callback = delegate(object result)
{
// Do nothing
};
return new BackgroundThread(workfunction, callback);
}
}
Just saw your comment. This should allow you to just pass a "plain old function" without having to shape it like a handler:
class Program
{
protected static void plainOldWorkerFunction(object argument)
{
return;
}
protected static void plainOldCallbackFunction()
{
return;
}
static void Main(string[] args)
{
BackgroundThread bt = new BackgroundThread(plainOldWorkerFunction, plainOldCallbackFunction);
bt.Start(1234);
}
}
public class BackgroundThread
{
BackgroundWorker worker;
Action<object> workerAction;
Action callbackAction;
protected void doWork(object sender, DoWorkEventArgs e)
{
workerAction(e.Argument);
}
protected void callback(object sender, RunWorkerCompletedEventArgs e)
{
callbackAction();
}
public BackgroundThread(Action<object> workerFunction, Action workerCallback)
{
this.workerAction = workerFunction;
this.callbackAction = workerCallback;
this.worker = new BackgroundWorker();
this.worker.DoWork += doWork;
this.worker.RunWorkerCompleted += callback;
}
public void Start(object argument)
{
this.worker.RunWorkerAsync(argument);
}
}
Original answer:
Try this constructor instead:
public BackgroundThread(DoWorkEventHandler workerFunction, RunWorkerCompletedEventHandler workerCallback)
{
this.worker = new BackgroundWorker();
this.worker.DoWork += workerFunction;
this.worker.RunWorkerCompleted += workerCallback;
}
And just make sure your workerFunction and workerCallback have these parameters:
protected static void workerFunction (object sender, DoWorkEventArgs e)
{
return;
}
protected static void workerCallback (object sender, RunWorkerCompletedEventArgs e)
{
return;
}
I am developing Windows Store Application. I need to implement a metronome. This metronome should have bpm settings. User should be able to increase/decrease it.
Here is my code so far:
namespace App1
{
public sealed partial class MainPage : Page
{
public class TickArgs : EventArgs
{
public DateTime Time { get; set; }
}
public class Metronome
{
public event TickHandler Tick = (m, e) => { };
public delegate void TickHandler(Metronome m, TickArgs e);
public void Start()
{
while (true)
{
System.Threading.Tasks.Task.Delay(3000);
Tick(this, new TickArgs { Time = DateTime.Now });
}
}
}
public class Listener
{
public void Subscribe(Metronome m, TextBlock tb, MediaElement mmx)
{
m.Tick += (mm, e) => mmx.Play();
}
}
public MainPage()
{
this.InitializeComponent();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m, tbcheck, mediaElement1);
m.Start();
}
}
}
How can i modify this code to have BPM settings?
My regards
Instead of uisng Task.Delay it may be easier to just use a Timer
An you can just pass the BBM into the Start method and set the interval based on that
public class Metronome
{
private DispatcherTimer _timer;
public event TickHandler Tick;
public delegate void TickHandler(Metronome m, TickArgs e);
public Metronome()
{
_timer = new DispatcherTimer();
_timer.Tick += Timer_Tick;
}
private void Timer_Tick(object sender, EventArgs e)
{
if (Tick != null)
{
Tick(this, new TickArgs { Time = DateTime.Now });
}
}
public void Start(int bbm)
{
_timer.Stop();
_timer.Interval = TimeSpan.FromSeconds(60 / bbm);
_timer.Start();
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Metronome m = new Metronome();
Listener l = new Listener();
l.Subscribe(m, tbcheck, mediaElement1);
m.Start(8); // 8bbm
}