Run method from another class to scroll listbox to bottom - c#

I want to autoscroll WPF ListBox to bottom automatically. I have two classes - one is Timer.cs and another one is MainWindow.xaml.cs
Here is Timer.cs:
using System;
using System.Configuration;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Importer_WPF
{
class Timer
{
public static readonly string MinutesExecution = ConfigurationManager.AppSettings["MinutesExecution"];
static System.Threading.Timer timer;
public static void StartTimer()
{
var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromMinutes(Convert.ToDouble(MinutesExecution));
timer = new System.Threading.Timer((e) =>
{
Task.Delay(100).ContinueWith(_ => App.Current.Dispatcher.Invoke(() => MainWindow.Names.Add(DateTime.Now.ToString())));
MainWindow.AutoScroll(); // Problem is here
}, null, startTimeSpan, periodTimeSpan);
}
public static void StopTimer()
{
timer.Change(Timeout.Infinite, Timeout.Infinite);
}
}
}
MainWindow.xaml.cs:
using System;
using System.Collections.ObjectModel;
using System.Configuration;
using System.IO;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Input;
namespace Importer_WPF
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public static ObservableCollection<string> Names { get; set; }
public static bool IsCheckedYes { get; set; }
[Obsolete]
public MainWindow()
{
InitializeComponent();
}
public void AutoScroll()
{
int itemCount = ConsoleOutput.Items.Count - 1;
if (itemCount > -1)
ConsoleOutput.ScrollIntoView(ConsoleOutput.Items[itemCount]);
}
}
}
Debugger is giving this message:
Severity Code Description Project File Line Suppression State
Error CS0120 An object reference is required for the non-static field,
method, or property 'MainWindow.AutoScroll()'
Any hints how to edit code structure so it will not produce errors?

You need to get a reference to the instance of mainwindow class which is in memory.
((MainWindow)Application.Current.MainWindow).AutoScroll();

Related

Get window that is NOT MainWindow WPF

I want to call the method from the codebehind of a window that is NOT the MainWindow in my WPF application, casting the window type as I do it.
ClientCallBack.cs:
using ChattingInterfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace ChatClient
{
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ClientCallback : IClient
{
public void GetMessage(string message, string userName)
{
//get casted instance of chat client window (NOT MainWindow!)
}
}
}
ChatWPFClient.xaml.cs:
using ChattingInterfaces;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace ChatClient
{
/// <summary>
/// Interaction logic for ChatWPFClient.xaml
/// </summary>
public partial class ChatWPFClient : Window
{
public static IChattingService Server;
private static DuplexChannelFactory<IChattingService> _channelFactory;
public ChatWPFClient()
{
InitializeComponent();
_channelFactory = new DuplexChannelFactory<IChattingService>(new ClientCallback(), "ChattingServiceEndpoint");
Server = _channelFactory.CreateChannel();
}
private void sendMessage(object sender, RoutedEventArgs e)
{
MessageBox.Show("Not available yet!");
}
public void TakeMessage(string message, string userName)
{
chatBox.Text += userName + ": " + message + "\n";
}
}
}
How can I call the TakeMessage of this method in the other class so I can use that codebehind window to populate the XAML file for ChatWPFClient.xaml? Thanks in advance!
First create an interface that you can pass to the ClientCallback
public interface IMessageHandler
{
void TakeMessage(string message, string userName);
}
Then in the ClientCallBack take the interface as a parameter in the constructor.
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public class ClientCallback : IClient
{
private IMessageHandler messageHandler;
public ClientCallBack(IMessageHandler messageHandler)
{
this.messageHandler = messageHandler;
}
public void GetMessage(string message, string userName)
{
messageHandler.TakeMessage(message, userName);
}
}
Use the interface for the ChatWpfClient and pass the instance in the constructor.
public partial class ChatWPFClient : Window, IMessageHandler
{
...
public ChatWPFClient()
{
InitializeComponent();
_channelFactory = new DuplexChannelFactory<IChattingService>(new ClientCallback(this), "ChattingServiceEndpoint");
Server = _channelFactory.CreateChannel();
}
...
// This is a part of the interface now and needs to be implemented here
public void TakeMessage(string message, string userName)
{
chatBox.Text += userName + ": " + message + "\n";
}
}
Also you could just implement the IClient on your ChatWPFClient class and decorate with the CallBackBehavior attribute and just pass itself as the callback. But don't think this is recommended, seems weird.
_channelFactory = new DuplexChannelFactory<IChattingService>(this, "ChattingServiceEndpoint");

C#: Dynamicly Add Items to Scrollview Control in WPF Application

Currently I am trying to code a WPF application that will store books and users for an imaginary library(I need to prove someone wrong). In my code, I have a class for Books and one for users. Inside of each will be a static list that keeps track of them all. What I would like to do is list out all the books and users so the viewer can see them. I thought I could do this with a scrollview and add labels to it that store the information(This would be in a separate window than the main screen, you would get there by pressing a button). However, I have been having some trouble with this.
LibraryCore:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LibraryCore
{
class User
{
}
class Books
{
public static List<Books> bookslist = new List<Books>();
public static void NewBook(string _title, string _author, string _publisher, int _isbn, int _count = 1)
{
bookslist.Add(new Books(_title, _author, _publisher, _isbn, _count));
}
public static void AddBook(string _title, int _amount)
{
bookslist[bookslist.FindIndex(b => b.Title.ToUpper() == _title.ToUpper())].Count += _amount;
}
public List<Books> currentLoans = new List<Books>();
public string Publisher { get; private set; }
public string Author { get; private set; }
public string Title { get; private set; }
public int ISBN { get; private set; }
public int Count { get; private set; }
Books(string _title, string _author, string _publisher, int _isbn, int _count = 1)
{
Title = _title;
Author = _author;
Publisher = _publisher;
ISBN = _isbn;
Count = _count;
}
}
}
MainWindow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using LibraryCore;
namespace LibraryLikeWpf
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void btnNewBook_Click(object sender, RoutedEventArgs e)
{
Books.NewBook("Odessy", "SOME OLD GUY", "Athens Inc.", 0);
//Books.NewBook("OLD YELLER", "SOME OLD GUY", "Athens Inc.", 2);
//Books.NewBook("This old man", "SOME OLD GUY", "Athens Inc.", 1);
}
private void btnInfo_Click(object sender, RoutedEventArgs e)
{
BookList bookList = new BookList();
bookList.Show();
}
}
}
BookListWindow:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using LibraryCore;
namespace LibraryLikeWpf
{
/// <summary>
/// Interaction logic for BookList.xaml
/// </summary>
public partial class BookList : Window
{
public BookList()
{
InitializeComponent();
for(int b = 0; b < Books.bookslist.Count; b++)
{
Label lbl = new Label();
lbl.VerticalAlignment = VerticalAlignment.Top;
lbl.Content = String.Format("Title: {0} Author: {1} Publisher: {2} ISBN: {3}",Books.bookslist[b].Title,Books.bookslist[b].Author, Books.bookslist[b].Publisher, Books.bookslist[b].ISBN);
lbl.Width = 100000;
scrollGrid.Children.Add(lbl);
}
}
}
}
This code works, but if I add several Books, the BookListWindow will just overlap the labels and I would like to know how to change their position when they are instantiated. Also, the labels get cut off even though their width shouldn't inhibit that. Why does that happen and how can I fix it? Also, is there a better way to list out ALL of the items in a list in a better looking way?
If your are using XAML, try to use ListView with Binding.
Create a ObservableCollection of Books and bind this to your ListView, this way you can control show your items are shown.

NSubstitute Checking received calls don't work

Hey guys im new with the NSubstitute framework. I'm trying to test some of my classes, but when i use NSubstitute to check received calls it says received no matching calls.
I'm trying to test if the method Tick() is receiving update() from track class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ATM_System.Event;
using ATM_System.EventDetection;
using ATM_System.Region;
using ATM_System.Track;
namespace ATM_System
{
public class ATM
{
private List<ITrack> _tracks;
private IRegion _region;
private List<IEventDetection> _eventdetects;
private List<IEvent> _events;
public ATM()
{
_tracks = new List<ITrack>();
_region = new Region.Region(100000,100000); //could be changed by user
_events = new List<IEvent>();
_eventdetects = new List<IEventDetection>();
}
public void Tick()
{
// update track positions
foreach (var track1 in _tracks)
{
track1.update();
}
//check for events
foreach (var detector in _eventdetects)
{
_events.AddRange(detector.DetectEvent(_tracks));
}
//handle events and output
foreach (var event1 in _events)
{
event1.HandleEvent();
event1.LogEvent();
}
}
public void IncomingTrack(ITrack track)
{
//add incoming track
_tracks.Add(track);
}
}
}
TEST FILE
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ATM_System.Event;
using ATM_System.EventDetection;
using ATM_System.Track;
using NUnit.Framework;
using NSubstitute;
namespace ATM_System.Tests.Unit
{
[TestFixture]
class ATMUnitTests
{
private ATM _uut;
private ITrack _track;
private IEvent _event;
private IEventDetection _eventDetection;
[SetUp]
public void Setup()
{
_track = Substitute.For<ITrack>();
_event = Substitute.For<IEvent>();
_eventDetection = Substitute.For<IEventDetection>();
_uut = new ATM();
}
[Test]
public void Tick_UpdateTracks_TracksUpdated()
{
_uut.Tick();
_track.Received().update();
}
}
}
You forgot to include _track in notification receivers. It simply hasn't subscribed to event and as a result is not notified. To fix simply call your IncomingTrack method:
[Test]
public void Tick_UpdateTracks_TracksUpdated()
{
_uut.IncomingTrack(_track);
_uut.Tick();
_track.Received().update();
}

Current Context error

I am having trouble calling out Method Globals.Global.InstantiateBlowerObj(); in public frmMain(). I am getting the error "The name 'Globals.Global.InstantiateBlowerObj' does not exist in the current context." I have all the classes and methods as public and I cant figure this out.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WetVacClient;
using Globals;
using Globals.Global;
namespace Globals
{
public class Global
{
public Blower[] _Blower = new Blower[4];
public void InstantiateBlowerObj()
{
for (int i = 1; i < 4; i++)
_Blower[i] = new Blower(i);
}
}
}
namespace WetVacClient
{
public partial class frmMain : Form
{
public frmMain()
{
InitializeComponent();
Globals.Global.InstantiateBlowerObj();
}
}
}
You need to make both the method and _Blower Property Static
public static Blower[] _Blower = new Blower[4];
public static void InstantiateBlowerObj()
{
for (int i = 1; i < 4; i++)
_Blower[i] = new Blower(i);
}
Otherwise create an intance of Global and call it's instance method (but that's not what you want I think).
Globals.Global g=new Globals.Global();
g.InstantiateBlowerObj();
Make it static.
You are trying to access a non-static member in an static context.
public static void InstantiateBlowerObj()
{
for (int i = 1; i < 4; i++)
_Blower[i] = new Blower(i);
}

how can I add items to my ListView

I keep getting this error and I know why but I need help figuring out how I can solve it. The only way I have been able to add my items it to make a new form but that seems silly.
It wont work if I make all my methods static =(
I keep getting,
"An object reference is required for the non-static field, method, or
property 'Handicap_Calculator.FormMain.listViewLog'
\Form1.cs 74 13 Handicap Calculator"
HereĀ“s my code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Handicap_Calculator
{
public partial class FormMain : Form
{
//FormAddScore FormAddNewScore = new FormAddScore();
public static bool addScoreIsShown = false;
public static FormAddScore _FormAddScore;
public static ListViewItem Item;
//public static List<string> ScoreInfo = new List<string>();
public FormMain()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
try
{
if (_FormAddScore == null || _FormAddScore.IsDisposed)
{
_FormAddScore = new FormAddScore();
}
_FormAddScore.Show();
if (_FormAddScore.WindowState == FormWindowState.Minimized)
{
_FormAddScore.WindowState = FormWindowState.Normal;
}
_FormAddScore.BringToFront();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
public static void AddScore()
{
int Round = 1;
DateTime date = _FormAddScore.date;
string course = _FormAddScore.course;
int holes = _FormAddScore.holes;
int score = _FormAddScore.score;
float courseRating = _FormAddScore.courseRating;
float slopeRating = _FormAddScore.slopeRating;
string[] ScoreInfo = new string[7];
ScoreInfo[0] = Round.ToString();
ScoreInfo[1] = date.ToString();
ScoreInfo[2] = course;
ScoreInfo[3] = holes.ToString();
ScoreInfo[4] = score.ToString();
ScoreInfo[5] = courseRating.ToString();
ScoreInfo[6] = slopeRating.ToString();
AddToList(ScoreInfo);
}
public static void AddToList(string[] ScoreInfo)
{
Item = new ListViewItem(ScoreInfo);
//listViewLog.Items.Add(Item);
}
}
}
Edit...
Here is the class im calling it from:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Handicap_Calculator
{
public partial class FormAddScore : Form
{
public DateTime date;
public string course;
public int holes;
public int score;
public float courseRating;
public float slopeRating;
public FormAddScore()
{
InitializeComponent();
}
private void FormAddScore_FormClosing(object sender, FormClosingEventArgs e)
{
FormMain.addScoreIsShown = false;
}
public void getscore()
{
try
{
date = dateTimePicker1.Value;
course = textBoxCourse.Text;
holes = Convert.ToInt16(textBoxHoles.Text);
score = Convert.ToInt16(textBoxScore.Text);
courseRating = Convert.ToSingle(textBoxCourseRating.Text);
slopeRating = Convert.ToSingle(textBoxSlopeRating.Text);
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
private void button1_Click(object sender, EventArgs e)
{
getscore();
FormMain.AddScore();
}
}
}
The simple solution is to define your methods AddScore and AddToList as non-static.
public void AddScore()
{
//your code
}
public void AddToList(string[] ScoreInfo)
{
// your code
}
If you want to use static methods you should pass the instance of your Form to the method, on which you want to add items to the ListView.
public static void AddScore(FormMain mainForm)
{
//your code
AddToList(mainForm, ScoreInfo);
}
public static void AddToList(FormMain mainForm, string[] ScoreInfo)
{
// your code
}
Update:
According to your updated code the solution is to pass the instance of your FormMain to your FormAddScore when you create it. In FormAddScore you store the reference to the FormMain instance to call the methods on.
public partial class FormAddScore : Form
{
// your code
private FormMain _mainForm;
public FormAddScore(){
InitializeComponent();
}
public FormAddScore(FormMain mainForm) : this(){
_mainForm = mainForm;
}
In your FormMain when you create the instance of FormAddScore you should use the constructor that expects an instance of FormMain
_FormAddScore = new FormAddScore(this);
With this setup you can change your methods to non-static and you can call the methods of FormMain in your FormAddScore, by using the stored reference in variable _mainForm.
_mainForm.AddScore();

Categories

Resources