private void ItemGet()
{
for (int i = 0; i < this.listview2.VirtualListSize; i++)
{
var address = this.listview2.Items[i].Text;
int item_aid = this.lib.ReadInt32((IntPtr)(long.Parse(address, NumberStyles.HexNumber) + ItemData.oFFSET_AID));
int item_id = this.lib.ReadInt32((IntPtr)(Convert.ToInt32(address, 16) + ItemData.oFFSET_ID));
int item_type = this.lib.ReadInt32((IntPtr)(Convert.ToInt32(address, 16) + ItemData.oFFSET_TYPE));
if ((item_aid.ToString().Length == 6) && (item_aid > 110000 && item_aid < 200000)
&& item_id.ToString().Length == 3 - 6)
{
this._itemslist.Add(new ItemResults(item_aid, item_aid, item_type));
this.ItemDetailsListView.Items.Add(new ListViewItem(new string[] {
item_aid.ToString(),
item_id.ToString(),
item_type.ToString()}));
MessageBox.Show(item_aid.ToString());
}
}
}
when i put messagebox show the messaage box is not pop i use cheat engine library to scan value and put it on listview I have no idea why it's not working
private void ScanTimer_Tick(object sender, EventArgs e)
{
this.ScanTimer.Enabled = false;
this.lib.iResetValues();
this.listview1.Refresh();
this.listview2.Refresh();
if (this.started)
{
var t = Task.Factory.StartNew(() => GetMonster()).ContinueWith((itemgetTask) => ItemGet()).ContinueWith((attackTask) => Attacks()).ContinueWith((teleportTask) => Teleport()).ContinueWith((pickuptTask) => Pickup());
Task.WaitAll(t);
this.lib.iNewScan();
MonsterScannerTimer.Start();
ItemScannerTimer.Start();
}
}
i call it here.
First time answering a question, I hope I can help.
Maybe you would be better off with storing the data you would normally add directly to your list into a ObservableCollection.
Here is a link to the class: https://learn.microsoft.com/de-de/dotnet/api/system.collections.objectmodel.observablecollection-1?view=netframework-4.7.2
There are plenty of ways to add it to your listview.
Related
I'm struggling with one piece of code and I was wondering if anyone could help me.
Here's my problem:
I'm working on a game and I created an inventory with a Dictionary. My Dictionary TKey is the item name and the TValue is a List. Each items has a boolean "isEquipped".
Dictionary<string, List<Item>> itemsInventory;
When equipping an item I want to check if the player has enough of this item and if this item can be equipped. I do that with this code:
public void EquipWeapon(bool tog, Item item)
{
if (tog == true)
{
if (player.weapon == false)
{
player.GetStatByName(item.StatAffectedName).AddModifier(item.StatAffectedValue, StatModifier.ModifierOrigins.Equipment, StatModifier.ModifierType.Flat, item.AssetName);
GameManagerSingleton.Instance.PlayerData.itemsInventory.FirstOrDefault(x => x.Key == item.AssetName && x.Value.Any(x => x.isEquiped == false)).Value.FirstOrDefault().isEquiped = true;
}
}
else
{
if (player.weapon == true)
{
player.GetStatByName(item.StatAffectedName).RemoveModifier(item.AssetName);
GameManagerSingleton.Instance.PlayerData.itemsInventory.FirstOrDefault(x => x.Key == item.AssetName && x.Value.Any(x => x.isEquiped == true)).Value.FirstOrDefault().isEquiped = false;
}
player.weapon = false;
}
player.GetStatByName(item.StatAffectedName).GetValue();
}
Problem with my code is that it changes all the items of the list and not just one.
Anyone could help me please?
From the comment you made "If I update in the debugger it change all items as well." it seems that the values in the list are the same object. This strongly suggests that Item is a class (not a struct).
You need to clone the objects before adding them to the list if they represent different instances.
From Reference types (C# Reference):
With reference types, two variables can reference the same object; therefore, operations on one variable can affect the object referenced by the other variable.
For completeness, you could use a value type (maybe something like record struct available from C#10):
With value types, each variable has its own copy of the data, and it is not possible for operations on one variable to affect the other (except in the case of in, ref and out parameter variables; see in, ref and out parameter modifier).
Use linq to query out the list you want to update and then update the item of the list individually.
Use this as an example:
How to update a single item of liist of objects using LINQ in C#
After I changed from false to true not only the item at index 0 but all objects changes.
When I create the player, I create the Dictionary like this:
itemsInventory = new Dictionary<string, List<Item>>(),
And when I create the list it's like this:
Instance.PlayerData.itemsInventory.Add("weapon", new List<Item>());
Instance.PlayerData.itemsInventory.Add("armour", new List<Item>());
Instance.PlayerData.itemsInventory.Add("shield", new List<Item>());
My code looked like this :
public void AddItemToInventory(Item? item, Ressource? ressource, int number = 1)
{
if (item != null)
{
int totalPrice = (item.Price * number);
ressources.First(x => x.currency == item.Currency).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
if (itemsInventory.ContainsKey(item.AssetName))
{
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(item);
}
}
else
{
itemsInventory.Add(item.AssetName, new List<Item>());
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(item);
}
}
}
if (ressource != null)
{
int totalPrice = (ressource.price * number);
ressources.First(x => x.currency == Currency.credit).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
GameManagerSingleton.Instance.PlayerData.AddResource(ressource.currency, number);
}
}
and I change it to this:
public void AddItemToInventory(Item? item, Ressource? ressource, int number = 1)
{
if (item != null)
{
int totalPrice = (item.Price * number);
ressources.First(x => x.currency == item.Currency).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
if (itemsInventory.ContainsKey(item.AssetName))
{
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(GenerateNewItem(item));
}
}
else
{
itemsInventory.Add(item.AssetName, new List<Item>());
for (int i = 0; i < number; i++)
{
itemsInventory.FirstOrDefault(x => x.Key == item.AssetName).Value.Add(GenerateNewItem(item));
}
}
}
if (ressource != null)
{
int totalPrice = (ressource.price * number);
ressources.First(x => x.currency == Currency.credit).amount -= totalPrice;
DailyReportHandler.GetAndFillTodayReport().moneyForItems += totalPrice;
GameManagerSingleton.Instance.PlayerData.AddResource(ressource.currency, number);
}
}
With GenerateNewItem(item) like this:
public Item GenerateNewItem(Item item)
{
var newItem = new Item
{
AssetName = item.AssetName,
Currency = item.Currency,
DescriptionLocalizationKey = item.AssetName,
isEquiped = false,
itemType = item.itemType,
NameLocalizationKey = item.NameLocalizationKey,
Price = item.Price,
ShortDescriptionLocalizationKey = item.ShortDescriptionLocalizationKey,
StatAffectedName = item.StatAffectedName,
StatAffectedValue = item.StatAffectedValue
};
return newItem;
}
I have xamarin app and I am using SQLite for saving data, if I have 3 rows and delete second row, then data will delete but row will be blank and its still here and problem is, that I need to load one column from every row. I am using for cycle and count to set maximum for it. But count says I have two rows so for cycle load just first and not second because second is on third line and second is blank.
I need to delete blank rows or to discover another solution how to load it. How can i delete blank DB?
Counting algorythm:
public int GetNumberPhotos()
{
var db = new SQLiteConnection(_dbPath);
db.CreateTable<Airplane>();
int count = 0;
if (db.Table<Airplane>().FirstOrDefault(l => l.Id == 1) != null)
count = db.Table<Airplane>().Count();
return count;
}
loading:
public int BetterUniReg()
{
int numberPhotos = GetNumberPhotos();
string[] allReg = new string[numberPhotos];
string[] uniReg = new string[numberPhotos];
int uniRegCnt = 0;
var db = new SQLiteConnection(_dbPath);
//db fill
for (int i = 0; i <= numberPhotos; i++)
{
if (db.Table<Airplane>().FirstOrDefault(b => b.Id == i) != null)
{
var rowData = db.Table<Airplane>().FirstOrDefault(c => c.Id == i);
i--;
allReg[i] = rowData.Registration;
i++;
}
}
Here is delete code:
private async void deleteButton_Clicked(object sender, EventArgs e)
{
var action = await DisplayAlert("Delete", "Do you want delete picture?", "Cancel", "Delete");
if (action)
{
}
else
{
var butto = sender as Button;
var frame = butto.Parent.Parent.Parent.Parent as Frame;
await frame.FadeTo(0, 600);
var button = (Button)sender;
var plane = (Airplane)button.BindingContext;
var db = new SQLiteConnection(_dbPath);
db.Delete<Airplane>(plane.Id);
Refresh();
}
}
I have done walkaround by adding if its last row and its null then do one more cycle.
Here is code:
for (int i = 1; i <= numberPhotos; i++)
{
if (db.Table<Airplane>().FirstOrDefault(c => c.Id == i) != null)
{
var rowData = db.Table<Airplane>().FirstOrDefault(c => c.Id == i);
allReg[regnumber] = rowData.Registration;
regnumber++;
}
if (db.Table<Airplane>().FirstOrDefault(c => c.Id == i) == null && i == numberPhotos)
{
numberPhotos = numberPhotos + 1;
}
}
I have a datagridview that I would like to have rows sorted based on the portion of a string entered from a user. The entered string is compared with all of the strings in a particular column. For instance, if I gave "comp" as the search word, the program would try to compare the search word with the strings on first column and sort the rows in a descending order which starts with "comp", such as "compare", "composition", "computer" etc. Rest of the words that do not match is either left alone or sorted in an alphabetical order (whichever is easier).
In LINQ, I am aware that you can apply the following code to achieve what you wanted with a string array:
var sortedWords = words.Where(x => x.Contains("comp"))
.OrderByDescending(x => x);
How can I achieve the same thing in Datagridview as I need to have the rows sorted, not just the items inside a particular column?
Edit:
The following code is giving a System.InvalidOperationException. (SetCurrentCellAddressCore is being called twice)
private void DGVPointCtrl_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
MatchComparer mc = new MatchComparer();
DGVPointCtrl.Sort(mc); //Error
}
I'm probably doing something wrong but I'm not sure why. Here is the code that programatically adds the rows for testing purposes:
private void BtnRefresh_Click(object sender, EventArgs e)
{
try
{
DGVPointCtrl.Rows.Clear();
int mainIndex = CmbMainDevice.SelectedIndex;
int subIndex = CmbSubDevice.SelectedIndex;
DDCDAO ddcdao = new DDCDAO(DDCGlobal.ddcEngineIP, ddc.Ip);
string pointListType;
object rs;
//Currently only supports IO DDC Request
//TO DO: Change DDCDAO to send proper subdevice requests
if (mainIndex == 0) //IO
{
#region Main Device: IO
}
//First row is for searching items
DGVPointCtrl.Rows.Add(new DataGridViewRow());
for (int i = 1; i < 5; i++)
{
DGVPointCtrl.Rows.Add(new DataGridViewRow());
DGVPointCtrl.Rows[i].ReadOnly = true;
}
DGVPointCtrl.Columns[0].SortMode = DataGridViewColumnSortMode.Programmatic;
DGVPointCtrl.Rows[0].DefaultCellStyle.Font =
new Font(DGVPointCtrl.DefaultCellStyle.Font, FontStyle.Italic | FontStyle.Bold);
if (subIndex == 1) //BI
{
PointDGVColumnGenerate("IO_BI");
}
else if (subIndex == 2) //BO
{
PointDGVColumnGenerate("IO_BO");
}
else if (subIndex == 3) //AI
{
PointDGVColumnGenerate("IO_AI");
}
else if (subIndex == 4) //AO
{
PointDGVColumnGenerate("IO_AO");
}
DGVPointCtrl.Rows[1].Cells[0].Value = "IO12314";
DGVPointCtrl.Rows[2].Cells[0].Value = "IO21948";
DGVPointCtrl.Rows[3].Cells[0].Value = "IO28194";
DGVPointCtrl.Rows[4].Cells[0].Value = "VP12984";
DGVPointCtrl.Rows[2].Cells[1].Value = "asdf";
#endregion
}
catch
{
}
}
private void PointDGVColumnGenerate(string key)
{
int colCount = 0;
DGVColumnTable.Clear();
for (int i = 0; i < COL_MAX; i++)
{
DGVPointCtrl.Columns[i].HeaderText = " ";
DGVPointCtrl.Columns[i].Visible = true;
}
foreach (string s in UIConstant.DDCPCtrlListColumnText[key])
{
DGVPointCtrl.Columns[colCount].HeaderText = s;
DGVColumnTable.Add(DGVPointCtrl.Columns[colCount]);
colCount++;
}
}
Edit2:
public class MatchComparer : IComparer
{
private static IComparer defaultComparer = new CaseInsensitiveComparer();
int IComparer.Compare(object x, object y)
{
DataGridViewRow xr = (DataGridViewRow)x;
DataGridViewRow yr = (DataGridViewRow)y;
string xs = "";
string ys = "";
try
{
xs = xr.Cells[0].Value.ToString();
}
catch
{
}
try
{
ys = yr.Cells[0].Value.ToString();
}
catch
{
}
if (HasMatch(xs) && !HasMatch(ys)) return -1;
else if (!HasMatch(xs) && HasMatch(ys)) return 1;
else return defaultComparer.Compare(xs, ys);
}
This is possible only if you are populating the grid yourself as opposed to binding it to the database.
Set DataGridViewColumn.SortMode to Programmatic.
Use DataGridView.Sort to impose a comparer like this:
public class MatchComparer : IComparer {
int IComparer.Compare(object x, object y) {
if (HasMatch(x) && !HasMatch(y)) return -1;
else if (!HasMatch(x) && HasMatch(y)) return 1;
else return defaultComparer.Compare(x, y);
}
private bool HasMatch(object x) {
return x is string && ((string)x).StartsWith("comp");
}
private static IComparer defaultComparer = new CaseInsensitiveComparer();
}
I have two DropDownLists one for the type of a soldier and one for the number of soldiers the player i allowed to buy. I populate ddlSoldiers with a LinqDataSource in the aspx page like this:
<asp:DropDownList ID="ddlSoldiers" runat="server"
DataSourceID="LinqDataSource2" DataTextField="type"
DataValueField="troopid" AutoPostBack="True">
</asp:DropDownList>
<asp:LinqDataSource ID="LinqDataSource2" runat="server"
ContextTypeName="BrowserSpill.LinqClass1DataContext" EntityTypeName=""
Select="new (type, troopid)" TableName="Troops">
</asp:LinqDataSource>
The other list ddlSoldierNumber is populated in the pageload like this:
protected void Page_Load(object sender, EventArgs e)
{
if (Session["userRole"] == null || Session["userRole"].Equals("admin"))
{
Response.Redirect("Login.aspx");
}
int userid = Convert.ToInt32(Session["userid"]);
if(string.IsNullOrEmpty(ddlSoldiers.SelectedValue))
{
var varTroopType = dc.Troops.Single(t => t.troopid == 1).type;
string troopType = Convert.ToString(varTroopType);
var varBuildingId = dc.Buildings.Single(b => b.soldierType == troopType).buildingid;
int buildingId = Convert.ToInt32(varBuildingId);
var varNumberOfBuildings =
dc.Towns.Single(t => (t.buildingid == buildingId) && (t.userid == userid)).number;
int numberOfBuildings = Convert.ToInt32(varNumberOfBuildings);
for (int i = 1; i < numberOfBuildings + 1; i++)
{
ddlSoldierNumber.Items.Add(i.ToString());
}
}
else
{
ddlSoldierNumber.Items.Clear();
string troopType = ddlSoldiers.SelectedItem.Text;
var varBuildingId = dc.Buildings.Single(b => b.soldierType == troopType).buildingid;
int buildingId = Convert.ToInt32(varBuildingId);
var varNumberOfBuildings =
dc.Towns.Single(t => (t.buildingid == buildingId) && (t.userid == userid)).number;
int numberOfBuildings = Convert.ToInt32(varNumberOfBuildings);
for(int i = 1; i < numberOfBuildings+1; i++)
{
ddlSoldierNumber.Items.Add(i.ToString());
}
}
}
But when i want to get the values from ddlSoldierNumber i only get the first value in that list. I try to get the number with the click of a button like this:
protected void btnBuySoldier_Click(object sender, EventArgs e)
{
string numbertobuy = ddlSoldierNumber.SelectedItem.Value;
lblAntall.Text = numbertobuy;
}
I have tried to put the line:
ddlSoldierNumber.Items.Clear();
other places but without any luck. Does anyone know how i can clear the number list after I press the button and before the ddlSoldierNumber get repopulated?
if you want to populate ddlSoldierNumber on the basis of selection from ddlSoldiers then you can not add values to ddlSoldierNumber in page load event. for that you have to add your page load event code in (ddlSoldiers) selected index change event.
protected void ddlSoldiers_SelectedIndexChanged(object sender, EventArgs e)
{
if (Session["userRole"] == null || Session["userRole"].Equals("admin"))
{
Response.Redirect("Login.aspx");
}
int userid = Convert.ToInt32(Session["userid"]);
if (string.IsNullOrEmpty(ddlSoldiers.SelectedValue))
{
var varTroopType = dc.Troops.Single(t => t.troopid == 1).type;
string troopType = Convert.ToString(varTroopType);
var varBuildingId = dc.Buildings.Single(b => b.soldierType == troopType).buildingid;
int buildingId = Convert.ToInt32(varBuildingId);
var varNumberOfBuildings =
dc.Towns.Single(t => (t.buildingid == buildingId) && (t.userid == userid)).number;
int numberOfBuildings = Convert.ToInt32(varNumberOfBuildings);
for (int i = 1; i < numberOfBuildings + 1; i++)
{
ddlSoldierNumber.Items.Add(i.ToString());
}
}
else
{
ddlSoldierNumber.Items.Clear();
string troopType = ddlSoldiers.SelectedItem.Text;
var varBuildingId = dc.Buildings.Single(b => b.soldierType == troopType).buildingid;
int buildingId = Convert.ToInt32(varBuildingId);
var varNumberOfBuildings =
dc.Towns.Single(t => (t.buildingid == buildingId) && (t.userid == userid)).number;
int numberOfBuildings = Convert.ToInt32(varNumberOfBuildings);
for (int i = 1; i < numberOfBuildings + 1; i++)
{
ddlSoldierNumber.Items.Add(i.ToString());
}
}
}
If I remember correctly, the pageload is run before your eventhandler for the button, have you tried placing the ddlSolderNumber.Items.Clear(); in the Click eventhandler after you change the label?
(I know this doesnt solve the issue with your first question)
For that you could try: (If Im confusing I apologize, Im bad at explaining myself)
You could create a "populate" method for your ddlSoldierNumber list, that you call after your click-event.
In your pageload, you could then on a check of "if (!PostBack)" run your default startup logic.
i'm making a workbook creator in C#.net ( using visual studio )
the book is build from the text part and the question part.
all the answers for the question are inside the text and the user need to click on the right answer. if he's right then the word become green and if he's wrong it become red.
i'm creating the clickeable text with LINKBUTTON, i gave the link button CssStyle class and after the user clicking the word i want to change the class for this link to a different class.
this is the code i using for creating the linksbutton:
public void createQusetion(Panel lefttext, Panel question, string text, string
questionText, string answer)
{
string[] Qbuttonstext = text.Split(' ');
_numberWords = Qbuttonstext.Length;
for (int i = 0; i < _numberWords; i++)
{
LinkButton answerButton = new LinkButton();
if (Qbuttonstext[i] == answer)
{
answerButton.ID = "answer" + i;
}
else
{
answerButton.ID = "word" + i.ToString();
}
answerButton.Text = Qbuttonstext[i].ToString() + " ";
answerButton.CssClass = "textbuttonB4";
answerButton.Click += new EventHandler(checkAnswer);
lefttext.Controls.Add(answerButton);
}
}
and for the checking the question:
private void checkAnswer(object sender, System.EventArgs e)
{
for (int i = 0; i < _numberWords; i++)
{
if (((Control)sender).ID.ToString() != null)
{
if (((Control)sender).ID.ToString() == "answer" + i.ToString())
{
((Control)sender).CssClass = "textbuttonRight";
}
else
{
((Control)sender).CssClass = "textbuttonwrong";
}
}
}
}
the VS2010 giving me misatake for the : ((Control)sender).CssClass .
what is the right way?
You can do a type-independent control this way. It will run for all controls have Id and CssClass Properties.
private void checkAnswer(object sender, System.EventArgs e)
{
var cssClass = sender.GetType().GetProperty("CssClass");
var id = sender.GetType().GetProperty("ID").GetValue(sender, null);
for (int i = 0; i < _numberWords; i++)
{
if (id!=null)
{
if (id.ToString() == "answer" + i.ToString())
{
cssClass.SetValue(sender, "textbuttonRight", null);
}
else
{
cssClass.SetValue(sender, "textbuttonRight", null);
}
}
}
}