null reference exception error for my windows form app - winforms

I have a Setting.cs file containing the info
[Serializable]
public class Setting
{
public Setting() {}
public String defaultAlertTone = Path.GetDirectoryName(Application.ExecutablePath) + "\\Sounds\\applause-2.wav";
}
and my settingsForm retrieving the info through this code
Setting settingObject;
public SoundPlayer player;
public settingsForm(backgroundForm backgroundFormObject)
{
InitializeComponent();
this.backgroundFormObject = backgroundFormObject;
settingObject = backgroundFormObject.getSetting();
}
private void InitializeSound()
{
// Create an instance of the SoundPlayer class.
player = new SoundPlayer();
player.SoundLocation = settingObject.defaultAlertTone;
// Listen for the LoadCompleted event.
player.LoadCompleted += new AsyncCompletedEventHandler(player_LoadCompleted);
// Listen for the SoundLocationChanged event.
player.SoundLocationChanged += new EventHandler(player_LocationChanged);
}
Why is it that every time I run the app, there would be a null reference exception on the
player.SoundLocation = settingObject.defaultAlertTone;
the backgroundFormObject.getSetting(); is just a method to retrieve the setting object. the code for it are as follows
Setting settingObj = new Setting();
public Setting getSetting()
{
return settingObj;
}

The reasons could be
InitializeSound() is somehow running before settingsForm (not likely, but this would make the settingObject not initialized and refer to null).
If this is the complete code for Setting class, i don't see how calling new Setting() anywhere would make a difference. So use Setting settingObject = new Setting(); when you first define this property in the settingsForm class.
It is not the settingObject which is null.

Related

SignalR WPF server - How to trigger a player?

I am currently working on a standalone app that can handle communication from a mobile and also utilizes VLC player to output a stream.
The way I do it is that output stream object is in the main window, but I receive requests via SignalR.
The request is fairly simple - it's just a string. The problem is I have no clue on how to pass the string from a SignalR hub back to the MediaPlayer object. How do I either get a string passed to an object outside or make a mediaplayer "persist" inside the hub? For now my code concerning it looks like this:
The hub:
[HubName("CommHub")]
public class CommHub:Hub
{
VLCControl outputplayer = new VLCControl();
public void RequestConnectionsList()
{
var databasePath = "--dbpath here--";
var db = new SQLiteConnection(databasePath);
List<string> output = db.Table<VideoSources>().Select(p => p.Name).ToList(); //Gets names from the db
Clients.Client(Context.ConnectionId).CamsInfo(output); //send available connection names to client
}
public void RequestOutStream(string requestedName) //this function is called but i have no idea how to make it work
{
outputplayer.playSelected(requestedName);
}
}
VLCControl:
class VLCControl
{
public Media rtsp;
private const string VIDEO_URL = "rtsp://wowzaec2demo.streamlock.net/vod/mp4:BigBuckBunny_115k.mov";
private MediaPlayer player;
public static string GetConfigurationString() //using this method in mainwindow player as well
{
string address = Properties.Settings.Default.LocalAddress;
string port = Properties.Settings.Default.LocalPort;
string result=
":sout=#duplicate" +
"{dst=display{noaudio}," +
"dst=rtp{mux=ts,dst=" + address +
",port=" + port + ",sdp=rtsp://" + address + ":" + port + "/go.sdp}";
return result;
}
public void playSelected(string inputAddress)
{
var databasePath = "D:\\Projects\\Sowa\\Sowa\\Serwer\\VideoSources.db";
var db = new SQLiteConnection(databasePath);
string input = db.Table<VideoSources>().FirstOrDefault(p => p.Name == "test").Address;
db.Close();
var rtsp = new Media(MainWindow._libvlc, input, FromType.FromLocation);
rtsp.AddOption(VLCControl.GetConfigurationString());
player.Stop();
player.Play(new Media(MainWindow._libvlc, VIDEO_URL, FromType.FromLocation));
}
}
The players are definitely working - when i create a mediaplayer in mainwindow it does indeed output as expected.
I think your question can be rephrased as "How can I call a method on my UI from a SignalR Hub"
For that, you have several options :
If you are using ASP.net core's SignalR, you can use dependency injection to inject either your window or an accessor to your window
You can get your main window with (MyWindow)Application.Current.MainWindow. What you do with it is up to you then
You can create a static class that will hold a reference to your component directly. This example assumes you have only one view at a time in your application.
public static class ViewAccessor {
public static MyView View { get; set; }
}
In your view constructor, after InitializeComponents:
ViewAccessor.View = this;
In your hub :
ViewAccessor.View.Play(...);

IWeakEventListener.ReceiveWeakEvent() called multiple times when PropertyChanged(null) is called on source object

I'm using the PropertyObserver class in my code to avoid doing string comparisons in PropertyChanged event handling and factor out the handling of null or string.Empty as its argument (Which indicates that all properties of an object has changed).
This class uses PropertyChangedEventManager to register callbacks in the target object and implements IWeakEventListener to respond every time PropertyChanged event is invoked on the source object.
But during the creation of a unit test I found out that the IWeakEventListener.ReceiveWeakEvent() is called N number of times, with N as the number of the registered callbacks. This only occurs when null or string.Empty is specified, not when a valid property name is given in the PropertyChanged event.
Does anyone knows why this is happening and how to fix it? My goal is to do a foreach of the registered handlers ONE time when null is given, so I can update my target object by getting all the properties of the source object. But when ReceiveWeakEvent() is called N times then the foreach will be repeated N times!
To illustrate it, the following is a simplified version of the PropertyObserver class and the source class (I'm using MVVM Light's ObservableObject for INotifyPropertyChanged implementation):
public class PropertyObserver : IWeakEventListener {
public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e) {
if (managerType == typeof(PropertyChangedEventManager)) {
string propertyName = ((PropertyChangedEventArgs)e).PropertyName;
if (string.IsNullOrEmpty(propertyName)) {
Console.WriteLine ("Foreach registered handlers and invoke one by one");
} else {
Console.WriteLine ("Invoke handler for property {0}", propertyName);
}
return true;
}
return false;
}
}
public class ViewModel : ObservableObject {
private int mProp1;
private int mProp2;
public int Prop1 {
get { return mProp1; }
set {
mProp1 = value;
RaisePropertyChanged("Prop1");
}
}
public int Prop2 {
get { return mProp2; }
set {
mProp2 = value;
RaisePropertyChanged("Prop2");
}
}
public void RaiseAllPropertyChanged() {
RaisePropertyChanged(null);
}
}
And in a console app's Main we can call them like so:
var vm = new ViewModel();
var obs = new PropertyObserver();
// Normally this is done inside the PropertyObserver class.
PropertyChangedEventManager.AddListener(vm, obs, "Prop1");
PropertyChangedEventManager.AddListener(vm, obs, "Prop2");
vm.Prop1 = 1; // Results in a console line "Invoke handler for property Prop1"
vm.Prop2 = 2; // Results in a console line "Invoke handler for property Prop2"
// Results in two console lines: "Foreach registered handlers and invoke one by one", expected is only 1!
vm.RaiseAllPropertyChanged();
Okay, I didn't understand the AddListener() method before. I only need to register a listener once:
PropertyChangedEventManager.AddListener(vm, obs, string.Empty);
to listen to all PropertyChanged events of a source object. Doing this will produce the correct working of the PropertyObserver class:
vm.Prop1 = 1; // "Invoke handler for property Prop1"
vm.Prop2 = 2; // "Invoke handler for property Prop2"
// Now results in one console line "Foreach registered handlers and invoke one by one"
vm.RaisePropertyChanged();
Each registered listener with non-empty third argument (the property name) will respond to only the specified property name and null or string.Empty. So that's why the foreach was invoked twice on the original code.

Autofixture, expected behavior?

Having a test similar to this:
public class myClass
{
public int speed100index = 0;
private List<int> values = new List<int> { 200 };
public int Speed100
{
get
{
return values[speed100index];
}
}
}
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var fixture = new Fixture();
var sut = fixture.Create<myClass>();
Assert.AreEqual(sut.Speed100, 200);
}
}
Would have expected this to work, but I can see why it's not. But how do I argue, that this is not a problem with AutoFixture, but a problem with the code?
AutoFixture is giving you feedback about the design of your class. The feedback is, you should follow a more object-oriented design for this class.
Protect your private state, to prevent your class from entering an inconsistent state.
You need to make the speed100index field, private, to ensure it remains consistent with the values List.
Here is what I see if I run debugger on your test:
Autofixture assigns a random number to speed100index field because it is public, and in your array there is nothing at point 53 (from my screenshot)
If you set speed100index to be private, Autofixture will not re-assign the number and your test will pass.

Collection is empty when returning from JAX-RS/CXF service

I have a service method defined as:
public JaxbList<Deal> getDeal() {
List<Deal> deals = new ArrayList<Deal>();
Deal type = new Deal();
type.setDealID(1);
type.setName("June Discounts");
deals.add(type);
JaxbList list = new JaxbList(deals);
System.out.println("List size -> " + list.getList().size());
return list;
}
My client is defined as:
WebClient client = WebClient.create("....");
JaxbList deals = client.path("exampleservice/getDeal")
.accept("application/xml").get(JaxbList.class);
List<Deal> types = deals.getList();
When I print out the size of the collection in the service method, the result comes back as 1. But, the size of my 'types' list from the client is 0. When I open in a browser, the 1 deal is displayed. So, this issue seems to be my client. I'm not sure where though.
Ideas?
Here is my JaxbList class:
public class JaxbList<T>{
protected List<T> list;
public JaxbList(){}
public JaxbList(List<T> list){
System.out.println("Setting list...");
this.list=list;
}
#XmlElement(name="Item")
public List<T> getList(){
return list;
}
}
As mentioned above by KasunBG your public JaxbList(List<T> list) constructor is never called by JAXB. The default no-arg one is used instead (see some discussion at What JAXB needs a public no-arg constructor for?). Actually Java compiler should complain about this situation with two constructors and "never initialized field list".
The solution is to introduce a setList() setter and throw a runtime exception from a no-arg constructor.

Silverlight cant find page error

I have started a a new project (to refactor some code), and just can't work out why I keep getting "Can't find page /Index" error. The code works fine until I use an add method (on any collection type). So I don't think there is a problem with the navigation, but an issue with my IndexViewModel class.
public partial class Index : Page
{
private IndexViewModel _vm;
public Index()
{
InitializeComponent();
_vm = new IndexViewModel();
...
public class IndexViewModel //: ViewModelBase
{
public SortableCollectionView Rows {get;set;}
public IndexViewModel()
{
// generate some dummy data
Random rand = new Random();
for (int i = 0; i < 200; i++)
{
Row row = new Row();
row["stuff"] = s_names[rand.Next(s_names.Length)];
**Rows.Add(row);**
}
}
Looks like you never new up your Rows variable.
Rows = new SortableCollectionView();
To get to the actual error you can use this trick copied from my answer on another question:
To see what the issue is you need to make one change to your MainPage.xaml.cs:
// If an error occurs during navigation, show an error window
private void ContentFrame_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
Exception ex = e.Exception;
while (ex.InnerException != null)
{
ex = ex.InnerException;
}
e.Handled = true;
ChildWindow errorWin = new ErrorWindow(ex);
errorWin.Show();
}
Once you've made that change when you start the application you should see the exception instead of the page where the exception occurred.
You need
Rows = new SortableCollectionView();
somewhere in your code.

Resources