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

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.

Related

Run method from another class to scroll listbox to bottom

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();

How do I make Affectiva call my callback functions?

I recently installed the Affectiva SDK (http://www.affectiva.com/) and followed the tutorial on analyzing input from the camera (http://developer.affectiva.com/v3/android/analyze-camera/). Unfortunately, the project does not seem to be working. It is my understanding that the interface/callback functions from FaceListener, ImageListener, ProcessStatusListener need to be called when a face is detected etc (is this correct).
I am not getting any errors, but these functions are never called either (I've put Console.WriteLine statements in there, as well as placed breakpoints in Visual Studio). From time to time, a series of "Image Captured" statements are printed to the console, but I cannot yet reproduce how or why that happens. Does anyone know what I did wrong? Thank you in advance for any help.
Below is my code so far:
App.xaml.cs
using Affdex;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Affectiva
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application, FaceListener, ImageListener, ProcessStatusListener
{
public static CameraDetector detector;
int camId = 10;
int camFPS = 60;
public App(){
detector = new CameraDetector();
String classifierPath = "C:\\Program Files (x86)\\Affectiva\\Affdex SDK\\data";
detector.setClassifierPath(classifierPath);
detector.setCameraId(camId);
detector.setCameraFPS(camFPS);
detector.setFaceListener(this);
detector.setImageListener(this);
detector.setProcessStatusListener(this);
detector.setDetectSmile(true);
detector.setDetectJoy(true);
detector.setDetectAllExpressions(true);
detector.setDetectAllEmotions(true);
detector.setDetectAllEmojis(true);
detector.setDetectAllAppearances(true);
}
public void onFaceFound(float f, int i)
{
Console.WriteLine("Face Found!");
}
public void onFaceLost(float f, int i)
{
Console.WriteLine("Face Lost!");
}
public void onImageResults(Dictionary<int, Face> faces, Frame f){
Console.WriteLine("OnImageResults - " + faces.Count);
if(faces.Count > 0)
Console.WriteLine(faces.First().Value.Appearance.Age);
}
public void onImageCapture(Frame f){
Console.WriteLine("Image Captured " + f.getHeight());
}
public void onProcessingFinished()
{
Console.WriteLine("Processing Finished");
}
public void onProcessingException(AffdexException e)
{
Console.WriteLine(e.Message);
}
}
}
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
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 System.Windows.Threading;
using WebEye.Controls.Wpf;
namespace Affectiva
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void OnStartButtonClick(object sender, RoutedEventArgs e)
{
var cameraId = webCameraControl.GetVideoCaptureDevices().First();
webCameraControl.StartCapture(cameraId);
App.detector.start();
}
}
}
I think you are looking at the wrong documentation.You can find the right documentation for Windows SDK here. A quick look at the code snippet, you are setting int camId = 10; which means that the detector is looking for Camera with id 10 on the system. By default the inbuilt camera has an id = 0. We set the default CameraId to 0 and the rate at which we process the frames to 30.Here is the default constructor definition for CameraDetector.
You can analyze the camera feed using this example. We also have some ready to go application available on github mainly Affdex-Me and csharp-sample-apps.

How to modify and show a queue in a WPF c#

I'm trying to show in a TextBox in a Windows Presentation Foundation a queue after adding some items, I know it must be something simple, I've checked the code with a breakpoint, the Add Item button works good but once I press it again the queue is empty and I'm always adding just an item and once I add it and I press the same button Add Item button again or the Show Button the queue is empty, I would like to add items and show the queue with the items I added, I made a class named QueueClas. Here below is all the code, thanks beforehand!!
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;
namespace Queue2
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
QueueClas queuec = new QueueClas();
buttonAdd.Click += ButtonAdd_Click;
buttonShow.Click += ButtonShow_Click;
}
private void ButtonShow_Click(object sender, RoutedEventArgs e)
{
QueueClas queuec = new QueueClas();
textBoxShow.Text = queuec.ShowQueue();
}
private void ButtonAdd_Click(object sender, RoutedEventArgs e)
{
QueueClas queuec = new QueueClas();
queuec.AddQueue(int.Parse(textBoxQueue.Text));
textBoxQueue.Clear();
}
public class QueueClas
{
Queue<int> myqueue;
public QueueClas()
{
myqueue = new Queue<int> { };
}
public void AddQueue(int x)
{
myqueue.Enqueue(x);
}
public string ShowQueue()
{
return string.Join(" ", myqueue);
}
public void DeleteItem(int x)
{
myqueue.Dequeue();
}
public string NumberOfItems()
{
int counter = 0;
counter = myqueue.Count();
return "The queue contains " + counter.ToString() + " elements";
}
public string MinQueue()
{
return "The minimun value of the queue is: " + myqueue.Min().ToString();
}
public string MaxQueue()
{
return "The maximum value of the queue is: " + myqueue.Max().ToString();
}
public string FindElement(int x)
{
foreach (int item in myqueue)
{
if (x == item)
{
return "The item is in the queue";
}
}
return "The item is not in the queue";
}
}
}
}
In both the add and show buttons you are initialising your list with QueueClas queuec = new QueueClas();. This is completely erasing the list ans starting fresh. You already initialise it in your MainWindow constructor so there's no need to do it again.

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");

wpf listview argumentoutofrangeexception in mscorlib

I have a listview in a simple wpf application, and it throws an unhandled exception: http://www.picz.ge/img/s2/1407/6/4/4d2baa8909d8.png
An unhandled exception of type 'System.ArgumentOutOfRangeException' occurred in mscorlib.dll
Additional information: Index was out of range. Must be non-negative
and less than the size of the collection.
I can't understand where is the mistake.
when I set time=2000; code works fine;
here is the code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
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 System.Diagnostics;
namespace Wpftemp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Thread t;
List<Something> listview_source;
int time;
public MainWindow()
{
InitializeComponent();
listview_source = new List<Something>();
listview.ItemsSource = listview_source;
t = new Thread(f);
time = 100;
t.Start();
}
private void f()
{
while (true)
{
listview_source.Clear();
refreshe_source();
App.Current.Dispatcher.Invoke( delegate()
{
listview.Items.Refresh();
});
Thread.Sleep(time);
}
}
private void refreshe_source()
{
for (int i = 0; i < 150; i++)
{
listview_source.Add(new Something(DateTime.Now.Second));
}
}
struct Something
{
public Something(double i)
{
this.i = i;
}
double i;
public double var
{
get { return i; }
set { i = value; }
}
}
}
}
I think the problem is in Using Dispatcher because the code inside dispatcher.Invoke() will be executed after the Main Thread is ready to execute it, so it is not guaranteed when exactly the code inside Dispatcher.Invoke() will be executed, so when you increased the value of time you guarantee that the code has been executed. Remove Dispatcher or Increase the value time.

Categories

Resources