Null Reference Exception being given when trying to play sound - c#

I am trying to insert a sound whenever there is a match in my game. However, I keep getting a NullReferenceException when I get the match. It goes to the line soundEffectInstance.Play();. Any help is greatly appreciated. I've attempted everything when trying to get it to work. Here is my code:
using System.Collections.Generic;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
namespace AndyKlax.KlaxGame
{
internal class Grid
{
private const int GridOrigin = 660;
SoundEffect soundEffect;
SoundEffectInstance soundEffectInstance;
private readonly List<Block>[] _grid = new List<Block>[Klax.NumberOfColumns];
public void LoadContent(ContentManager content)
{
soundEffect = content.Load<SoundEffect>(#"Sounds/24372^pop2.mp3");
soundEffectInstance = soundEffect.CreateInstance();
}
internal Grid()
{
for (int i = 0; i < Klax.NumberOfColumns; i++ )
{
_grid[i] = new List<Block>();
}
}
private bool RemoveBlocks()
{
var foundBlocksToRemove = false;
//Mark all blocks in the grid as unmatched
for (int column = 0; column < Klax.NumberOfColumns; column++)
{
for (int row =_grid[column].Count -1 ; row >=0 ; row--) //Loop backwards do its safe to remove
{
if (_grid[column][row].Delete)
{
_grid[column].RemoveAt(row);
foundBlocksToRemove = true;
}
}
}
return foundBlocksToRemove;
}
private void SearchForMatches()
{
//Search the whole grid - look for matches in each direction and set the deleted flag for anything you find
for (int column = 0; column < Klax.NumberOfColumns; column++)
{
for (int row = 0; row < _grid[column].Count; row++)
{
SearchForMatches(column, row, 1, 0); //Horizontal
SearchForMatches(column, row, 0, 1); //Vertical
SearchForMatches(column, row, 1, 1); //Diagonal one way
SearchForMatches(column, row, 1, -1); //Diagonal the other way
}
}
}
private void SearchForMatches(int column, int row, int xStep, int yStep)
{
int startColorIndex = _grid[column][row].ColorIndex;
int matchCount = 0;
int x = column;
int y = row;
//Loop in the given direction till we run out of color or grid
do
{
matchCount++;
x += xStep;
y += yStep;
} while (x < Klax.NumberOfColumns && y < _grid[x].Count && y>0 && startColorIndex == _grid[x][y].ColorIndex);
//If the match is long enough
if (matchCount >= 3)
{
//Then mark all those blocks for removal
x = column;
y = row;
//Loop in the given direction till we run out of color or grid
do
{
_grid[x][y].Delete = true;
x += xStep;
y += yStep;
soundEffectInstance.Play();
} while (x < Klax.NumberOfColumns && y < _grid[x].Count && startColorIndex == _grid[x][y].ColorIndex);
}
}
private void ResetDeleteFlags()
{
//Mark all blocks in the grid as unmatched
for (int column = 0; column < Klax.NumberOfColumns; column++)
{
for (int row = 0; row < _grid[column].Count; row++)
{
_grid[column][row].Delete = false;
}
}
}
internal void Draw(SpriteBatch spriteBatch)
{
//Like the paddle the position of the block is inferred by its position in the grid
spriteBatch.Begin();
for (int column = 0; column < Klax.NumberOfColumns; column++)
{
for (int row = 0; row < _grid[column].Count; row++)
{
_grid[column][row].Draw(spriteBatch, column, GridOrigin - row * Klax.Texture.Height);
}
}
spriteBatch.End();
}
internal void Add(int column, Block block)
{
_grid[column].Add(block);
//Search for matches
do
{
ResetDeleteFlags();
SearchForMatches(); //Look for matches and mark their deleted flag
} while (RemoveBlocks()); //If we removed any then iterate again as there may be new matches
}
public bool HasSpace(int column)
{
//Is there room in this column
return _grid[column].Count < Klax.NumberOfRows;
}
}
}

From what I'm seeing in your code you are using ContentManager.Load from the Microsoft.Xna.Framework framework.
Under this assumption your code probably won't ever work and always will return null.
The problem here is twofold:
ContentManager.Load supports only specific types as given by its definition (I'll post a link further below). SoundEffects are not part of these types
This load method thinks that all files given have no extension by themselves but instead have an ungiven .xnb extension (and are of the xnb format).
Thus your Sounds/24372^pop2.mp3 translates to Sounds/24372^pop2.mp3.xnb for it.
One example directly from the documentation how it is used:
Model model = contentManager.Load<Model>( ".\\content\\models\\box" );
This would load box.xnb as a model.
The full documentation for that method is here:
https://msdn.microsoft.com/en-us/library/bb197848.aspx
Like I mentioned if my assumption that you are using THAT method is correct then it is clear why the loading fails with that as it is looking for a file that does not exist. But even if that is corrected according to the documentation it should still not work as it is not of a supported type (I find it strange though that the method does not throw an exception when you try to use it to load something not supported but that developer oversight has nothing to do with your problem at all in essence).

Related

DGV doesn't update value

I Inerted a DGV called MarksDGV1 into my application while each cell inside of it has a default value of "0". So, after the user changes the value of some of them, when I try to reach the value for the last edited cell it gives me 0 instead of what the user typed even though it's shown correctly
(Please note: the unselected cells -which doesn't appear in Blue color- show value correctly)
How could I fix that?
Here is my code:
MarksDGV1.Refresh();
MessageBox.Show(MarksDGV1.Rows[0].Cells[1].Value.ToString());
And this is How I built the DGV:
using (DataGridViewTextBoxColumn tmp = new DataGridViewTextBoxColumn())
{
tmp.Width = 90;
tmp.ReadOnly = true;
tmp.HeaderText = "פרק מס.";
MarksDGV1.Columns.Add(tmp);
}
for (int i = 1; i <= 30; i++)
{
using (DataGridViewTextBoxColumn tmp = new DataGridViewTextBoxColumn())
{
tmp.Width = 50;
tmp.HeaderText = "שאלה מס." + i;
MarksDGV1.Columns.Add(tmp);
}
}
for (int i = 0; i < 8; i++)
{
using (DataGridViewRow tmp = (DataGridViewRow)MarksDGV1.Rows[i].Clone())
{
tmp.Cells[0].Value = i + 1;
for (int j = 1; j <= 30; j++)
{
tmp.Cells[j].Value = 0;
//tmp.Cells[j].Value = CurrentExam.Psy[i].Answers[j - 1];
}
MarksDGV1.Rows.Add(tmp);
}
}
Update: I tried typing DataGridView.Refresh(); but didn't work!
Update2: I was able to fix this by selecting another cell -different from the one that I'm concerned in- before I get the values. But that's not a solution for me
From the comments, you are using a button that doesn't take the focus away from the grid, so it remains in edit mode. Try it like this:
MarksDGV1.EndEdit();
MessageBox.Show(MarksDGV1.Rows[0].Cells[1].Value.ToString());

edit corner case, check null in c#

My code is save datagrid to csv. when process to
value = dr.Cells[i].Value.ToString();
Error message is the following:System.Windows.Forms.DataGridViewCell.Value.get return null.
Then, I add corner case to check cell is null and replace those cells by "Null".
foreach (DataGridViewRow rw in this.dataGridView1.Rows)
{
for (int i = 0; i < rw.Cells.Count; i++)
{
if (rw.Cells[i].Value == System.DBNull.Value)
{
swOut.Write("Null");
}
}
}
But the error message is there still.
The following is my code:
public void writeCSV(DataGridView gridIn, string outputFile)
{
//test to see if the DataGridView has any rows
if (gridIn.RowCount > 0)
{
string value = "";
DataGridViewRow dr = new DataGridViewRow();
StreamWriter swOut = new StreamWriter(outputFile);
foreach (DataGridViewRow rw in this.dataGridView1.Rows)
{
for (int i = 0; i < rw.Cells.Count; i++)
{
if (rw.Cells[i].Value == System.DBNull.Value)
{
swOut.Write("Null");
}
}
}
//write header rows to csv
for (int i = 0; i <= gridIn.Columns.Count - 1; i++)
{
if (i > 0)
{
swOut.Write(",");
}
swOut.Write(gridIn.Columns[i].HeaderText);
}
swOut.WriteLine();
//write DataGridView rows to csv
for (int j = 0; j <= gridIn.Rows.Count - 1; j++)
{
if (j > 0)
{
swOut.WriteLine();
}
dr = gridIn.Rows[j];
for (int i = 0; i <= gridIn.Columns.Count - 1; i++)
{
if (i > 0)
{
swOut.Write(",");
}
value = dr.Cells[i].Value.ToString();
//replace comma's with spaces
value = value.Replace(',', ' ');
//replace embedded newlines with spaces
value = value.Replace(Environment.NewLine, " ");
swOut.Write(value);
}
}
swOut.Close();
}
}
The current code appears to work… IF the DataGridView.AllowUserToAddRows is false! The default is true. If the grid allows users to add rows, the code will crash at the line…
value = dr.Cells[i].Value.ToString();
when it hits the “new” row. The cells in the “new” row are null not DBNull. If you want to allow the user to add rows (which I assume is the case since the code is stripping out commas and new lines), then the code will need to check for this “new” row and ignore it when exporting the grid.
With that said, I believe you are making this way more complicated than it has to be. The goal is to export the cells in a DataGridView to a comma delimited file (CSV). This can be done with much less code and still avoid the dreaded null values in the cells.
From the perspective of the CSV file, if a cell is “null” that means that we want to output an “empty” string to the CSV file. This will maintain the column schema. Therefore, a simple double loop through the grids cells is all that needs to be done. While looping through the cells and writing the values to the file, a simple check is needed before we try and grab a cells value.ToString(). If value is null, the code will crash as a null does not have a ToString() method. Therefore if value “is” null then write an empty string to the file… problem solved!
Therefore, to help, I recommend you use a different strategy to export the grids cells. There appears no reason for the dr variable nor the value variable. In addition, I would assume that the cells text does “NOT” contain commas (,). If you “know” the grid is going to be exported to a CSV file… I would set the grids cells such that the user would “not” be able to type a comma. Therefore, the code below does not strip out commas or new lines. Hope that makes sense.
public void writeCSV(DataGridView gridIn, string outputFile) {
try {
using (StreamWriter swOut = new StreamWriter(outputFile)) {
//write header rows to csv
for (int i = 0; i < gridIn.Columns.Count; i++) {
swOut.Write(gridIn.Columns[i].HeaderText);
if (i < gridIn.ColumnCount - 1) {
swOut.Write(",");
}
else {
swOut.WriteLine();
}
}
//write DataGridView rows to csv
for (int row = 0; row < gridIn.Rows.Count; row++) {
if (!gridIn.Rows[row].IsNewRow) {
for (int col = 0; col < gridIn.Columns.Count; col++) {
if (dataGridView1.Rows[row].Cells[col].Value != null) {
swOut.Write(dataGridView1.Rows[row].Cells[col].Value.ToString());
}
else {
swOut.Write("");
}
if (col < gridIn.Columns.Count - 1) {
swOut.Write(",");
}
else {
swOut.WriteLine();
}
}
}
}
}
}
catch (Exception e) {
MessageBox.Show("Error: " + e.Message);
}
}

Loop through selected rows C# DevExpress

I have a function that sets column values for all rows:
The code that sets this:
//Update the engineers for all rows
Btn_ValidateClick_ItemClick(object sender,ItemClickEventArgs e)
{
UpdateTotalTime(gridView);
}
private void UpdateEngineers(DevExpress.XtraGrid.Views.Base.ColumnView View)
{
//Column name that need to be updated (set)
DevExpress.XtraGrid.Columns.GridColumn col = View.Columns.ColumnByFieldName("Engineers");
try
{
int dataRowCount = View.DataRowCount;
for (int i = 0; i < dataRowCount; i++)
{
GridView detail = (GridView)gridView.GetDetailView(i, 0);
string language = gridView.GetRowCellValue(i, "Language").ToString();
for (int y = 0; y < gridView.GetDetailView(i, 0).RowCount; y++)
{
//Add all values found in a detail column to an arraylist
values.Add(detail.GetRowCellValue(y, "EngineerInitials").ToString());
}
if (values.Count >0 )
object t = //string join ...
View.SetRowCellValue(i, col, t);
}
else
{
object t = "No engineers"
View.SetRowCellValue(i, col, t);
}
}
}
}
}
The problem is that now, I want it only to set it for the rows that are selected.
I tried using the .GetSelectedRows()-function and adding the rows to an ArrayList, but this doesn't allow customability really:
private void UpdateTotalTime(DevExpress.XtraGrid.Views.Base.ColumnView View)
{
ArrayList selectedRows = new ArrayList();
for (int i = 0; i < gridView.SelectedRowsCount; i++)
{
if (gridView.GetSelectedRows()[i] >= 0)
selectedRows.Add(gridView.GetDataRow(gridView.GetSelectedRows()[i]));
}
try
{
int count = View.GetSelectedRows().Count();
for (int i = 0; i < selectedRows.Count; i++)
{
//This gets the first row of the count, not the first selected row
GridView detail = (GridView)gridView.GetDetailView(i,0);
}
}
If I select the 3 bottom rows, the first 3 get updated. Why is this?
You are adding all the selected rows to your selectedRows ArrayList. But after that, you are not using it for anything.
I guess what you want (I've never used devexpress controls) is using those selectedrows RowHandle to pass it to the GetDetailView method. According to the GetSelectedRows documentation, the method returns the int handles of the selected rows, so your code should look like this:
First, you must save the DataRow handles, not the DataRow itself, so you must change in your code this line:
selectedRows.Add(gridView.GetDataRow(gridView.GetSelectedRow‌​s()[i]));
into this:
selectedRows.Add(gridView.GetSelectedRows()[i]);
And then, change your loop into this:
for (int i = 0; i < selectedRows.Count; i++)
{
int rowHandle = (int)selectedRows[i];
GridView detail = (GridView)gridView.GetDetailView(rowHandle,0);
}
In fact, you could do everything in just one loop:
private void UpdateTotalTime(DevExpress.XtraGrid.Views.Base.ColumnView View)
{
for (int i = 0; i < gridView.SelectedRowsCount; i++)
{
int rowHandle = gridView.GetSelectedRows()[i];
GridView detail = (GridView)gridView.GetDetailView(rowHandle,0);
}
}

How to get the column counts of StackedHeaders?

In my project, I have checked with many test cases and in one test case, I have dragged the stacked column header, I need to get the column counts belongs to that StackedHeader because I have to do some customization with their column index. Please anyone suggest me how to achieve this.
Thanks!
Define your code like:
private int RecursiveIteration(GridFieldCollection field) {
int count = 0;
for (int i = 0; i < field.Count ; i++)
{
if (field[i].GetType() == typeof(GroupField))
{
count += RecursiveIteration((field[i] as GroupField).Columns);
}
count++;
}
return count; }
To get total count: int colCount = RecursiveIteration(WebDataGrid1.Columns);

Trying to select from a list the first previous eligible index

I have a List<List<Object>> in which one of these objects has the property isCurrentlySelected = true. This nested list represents a grid of these objects that might be constructed in any configuration (i.e. the grid may be any dimensions, and may even be jagged).
Now, some of these objects have the property isSelectable = false, so I'm trying to create a method which takes a single parameter for "direction" and returns the first eligible index in the specified direction from the one currently marked as selected.
So far I've only been able to do this using several nested for loops and if-else statements, and even then, it will only work for one direction. I'm wondering if there's a more elegant way to check for the first eligible element, preferably using a single method.
Thanks in advance for any help,
~KWiP
EDIT: with code sample
So I have the Menu class:
public class Menu
{
public int x;
public int y;
public int width;
public int height;
public int lineHeight;
public float menuTimer = 0.0f;
public bool menuKeysPressed = false;
public List<List<Selection>> selections = new List<List<Selection>>();
public int selectedList = 0;
public int selectedItem = 0;
in which is the child class Selection:
public class Selection
{
public int x;
public int y;
public bool isCurrentlySelected = false;
public bool isSelectable = true;
public Color selectedColor = Color.White;
public Color unselectedColor = Color.Gray;
public bool isNonText = false;
public string displayText = "";
public int textSize;
public Selection(int xPos, int yPos, string text, int size, bool selectable)
{
x = xPos;
y = yPos;
displayText = text;
textSize = size;
if (!selectable)
{
isCurrentlySelected = false;
}
}
}
Each Selection in a Menu object has X and Y coordinates in the form of its indices in the nested lists found in Menu.selections. In each Menu, there is typically exactly one Selection with its isCurrentlySelected property set to true.
public Menu(int xPos, int yPos, int wdth, int hght, int lists = 0, int items = 0, bool allSelectable = true)
{
x = xPos;
y = yPos;
width = wdth;
height = hght;
if (items > 0 && lists <= 0)
{
lists = 1;
}
for (int i = 0; i < lists; i++)
{
selections.Add(new List<Selection>());
for (int j = 0; j < items; j++)
{
selections.ElementAt(i).Add(new Selection(((wdth / items) * j) + xPos, ((hght / lists) * i) + yPos, "", 20, allSelectable));
}
}
if (items > 0)
{
selections.ElementAt(0).ElementAt(0).isCurrentlySelected = true;
}
}
Now, within the Menu class, I'm trying to make a method which will deselect the currently selected index, and then select the next closest eligible index in a particular direction, wrapping around to the other side if the end of the range of indices is reached. Unfortunately, all I've been able to come up with is this mess, which currently only works going North, and would need to be expanded to roughly 4x its size to accommodate all directions.
public void nav(Point currentSelected, int dir) // The 4 cardinal directions are represented by an int: 0 for North and continuing clockwise from there.
{
int newRow = currentSelected.Y;
int newIndex = currentSelected.X;
switch (dir)
{
case 0: // Operations to select next eligible N index.
if (this.selections.Count <= 1)
{
return;
}
else
{
int firstOpenRow = this.selections.Count;
for (int i = 0; i < this.selections.Count; i++)
{
int difference = i - currentSelected.Y;
if (difference > 0 && difference < firstOpenRow && this.selections.ElementAt(i).ElementAt(currentSelected.X).isSelectable == true)
{
firstOpenRow = i;
}
}
if (firstOpenRow == this.selections.Count)
{
for (int i = 0; i < this.selections.Count; i++)
{
int difference = i - currentSelected.Y;
if (difference < 0 && difference < firstOpenRow && this.selections.ElementAt(i).ElementAt(currentSelected.X).isSelectable == true)
{
firstOpenRow = i;
}
}
if (firstOpenRow == this.selections.Count)
{
firstOpenRow = currentSelected.Y;
}
}
this.selections.ElementAt(currentSelected.Y).ElementAt(currentSelected.X).isCurrentlySelected = false;
this.selections.ElementAt(firstOpenRow).ElementAt(currentSelected.X).isCurrentlySelected = true;
}
break;
case 1:
// Add operations for E here
break;
case 2:
// Add operations for S here
break;
case 3:
// Add operations for W here
break;
}
}
Your choice of data-structure isn't really well made for the kind of queries you need to make. Maybe you should consider investing a little more time into creating a linked grid. Something like:
class Item
{
Item North { get; private set; }
Item South { get; private set; }
Item West { get; private set; }
Item East { get; private set; }
}
Like that, if you look for the next 'left' item, you can just go West until you either reach null or you encounter an item that is selectable.
Otherwise, it makes sense to distinguish between the different kinds of directions. Just because you have less code doesn't mean your program runs faster. Think of your algorithm in terms of how many operations you have to make to reach your goal, instead of how long it is.
Sorry if that's not the answer your're looking for.

Categories

Resources