Mousebuttonpressed event Issues C# - c#

I have an issue with a custom event i have created. I have made a Usercontrol that looks the following:
public partial class UCListView : UserControl {
public UCListView() {
InitializeComponent();
}
public event EventHandler SubmitClick;
public event EventHandler MouseButtonUpEvent;
private void SubmitButton_OnClick(object sender, RoutedEventArgs e) {
if (SubmitClick != null)
SubmitClick(this, e);
}
private void MouseButtonUp(object sender, RoutedEventArgs e) {
if (MouseButtonUpEvent != null) {
MouseButtonUpEvent(this, e);
}
}
}
Here is the MouseButtonUp event i have.
The following is where i listen to the event:
public partial class RoundsteelWindow : WindowControls {
private UCListView uc;
public RoundsteelWindow() {
InitializeComponent();
uc = new UCListView();
uc.SubmitClick += new EventHandler(ButtonPressed);
uc.MouseButtonUpEvent += new EventHandler(MousePressed);
stkTest.Children.Add(uc);
base.Test<RoundSteel>(uc, "Roundsteel");
}
}
Here is the WindowControls, where the MousePressed method can be seen. This is the same as the code snippet beneath this code. Really don't see the issue:
public abstract class WindowControls : Window {
public IMaterialWith14Elements _ReturnObject { get; set; }
public double amount { get; set; }
private UCListView _uc;
public void Test<T>(UCListView uc, string type) where T: IMaterialWith14Elements, new() {
_uc = uc;
List<T> test = MaterialLogic.GetList(type) as List<T>;
foreach (T material in test) {
uc.listView.Items.Add(material.Name);
}
}
private string str;
public void MousePressed(object sender, EventArgs eventArgs) {
var item = (sender as ListView).SelectedItem;
if (item != null) {
_ReturnObject = _uc.listView.SelectedItems as FlatSteel ;
str = item.ToString();
_uc.amountText.IsEnabled = true;
}
}
public void ButtonPressed(object sender, EventArgs e) {
if (!string.IsNullOrEmpty(_uc.amountText.Text)) {
amount = _uc.amountText.Text.customParseToDouble();
this.Close();
}
else {
MessageBox.Show("Indtast venligst en værdi.");
}
}
}
Now the problem is the following: With the following code it is working, but this class is not using the windowcontrols. It is called by another class which handles all of the buttons.
private void flatsteelListView_PreviewMouseLeftButtonUp(object sender, RoutedEventArgs e) {
var item = (sender as ListView).SelectedItem;
if (item != null) {
_returnObject = flatsteelListView.SelectedItems as FlatSteel;
str = item.ToString();
amountTextbox.IsEnabled = true;
FindObject(str);
}
}
The first picture shows the working window. This is where there is not used a usercontrol. Actually this is a previous issue i have worked with and got help with here on stackoverflow Help for thisissue.
The second picture is showing the next window using the usercontrol that has been created. The button event works and closes the window. Here comes then the issue, when the listview item is pressed. It is doing the same thing as on the first picture(where it works), but it is giving me a null reference, which doesn't make any sense to me. I have also checked the object sender to see if there was a difference between the sender of these two different windows.
I simply can't figure out why this is not working.
greetings darophi

Your sender is an object of UCListView class which is inherited from UserControl and you are trying to use it like ListView. So as result of operation (sender as ListView) you get null because sender is not an instance of ListView class and not inherits it.

Related

Binding TextBox to a Windows Form not working

My environment is:
Windows 11
Windows Form App created by the Windows Forms App template of Visual Studio 2022.
Problem:
I have a simple Windows Form with only a Textbox and a Button.
I am trying to update the Textbox text with new data whenever the button is pressed.
The binding works when the Windows Form is loaded. The text "12.34" appears in the Textbox.But when I click on the button, the Textbox is not updated with the new data.
Here is my code:
namespace WatchChart;
public partial class WatchForm:Form
{
public class BidAsk
{
public string? BidString { get; set; }
}
public WatchForm()
{
InitializeComponent();
}
private void MyForm_Load(object sender, EventArgs e)
{
var bid = new BidAsk() { BidString = "12.34" };
bidTextBox.DataBindings.Add(nameof(TextBox.Text), bid, nameof(BidAsk.BidString));
}
private void displayButton_Click(object sender, EventArgs e)
{
var bidask = new BidAsk();
bidask.BidString = "23.45";
}
}
Any help will be greatly appreciated,Charles
The first potential issue is that you need the bound variable to be a member of the main form (instead of making a local var inside the methods). The other potential issue is making sure to enable two-way binding. The BidString property should be implemented similar to the BidAsk shown in order to fire a PropertyChange event whenever its value changes.
class BidAsk : INotifyPropertyChanged
{
string _bidString = string.Empty;
public string BidString
{
get => _bidString;
set
{
if (!Equals(_bidString, value))
{
_bidString = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Test
Here's the code I used to test this answer::
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
BidAsk = new BidAsk();
textBoxBid.DataBindings.Add(
propertyName: nameof(TextBox.Text),
dataSource: BidAsk,
dataMember: nameof(BidAsk.BidString));
buttonDisplay.Click += onClickButtonDisplay;
}
BidAsk BidAsk { get; set; }
private void onClickButtonDisplay(object? sender, EventArgs e)
{
// Test string gobbledegook
var marklar = Guid.NewGuid().ToString().Substring(0, 11);
BidAsk.BidString = marklar;
}
}
You are creating a new BidAsk (let's call it bidAsk1) on load, and binding to that. Then on the button click, you are creating another BidAsk (bidAsk2) and setting the content. Your textbox is still bound to bidAsk1, not bidAsk2 so it will not be updated.
Try keeping a reference to the bound object:
namespace WatchChart;
public partial class WatchForm:Form
{
public class BidAsk
{
public string? BidString { get; set; }
}
private BidAsk bid;
public WatchForm()
{
InitializeComponent();
}
private void MyForm_Load(object sender, EventArgs e)
{
bid = new BidAsk() { BidString = "12.34" };
bidTextBox.DataBindings.Add(nameof(TextBox.Text), bid, nameof(BidAsk.BidString));
}
private void displayButton_Click(object sender, EventArgs e)
{
bid.BidString = "23.45";
}
}

Classes using other classes/methods

I made a program that essentially contained 150 actions, all in the first form. It has become a nightmare to manage and a friend recommended splitting groups of actions into separate classes.
Ideally going from: Do {1,2,3,4,5} to Do {A,B} where A is {1,2,3} and B is {4,5}.
To practice, I decided to try to work 2 classes:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
public void button_Click(object sender, RoutedEventArgs e)
{
if (checkBox1.IsChecked == true)
{
checkTrue();
}
else
{
checkFalse();
}
}
public void checkTrue()
{
textBox.Text = "checkbox was checked";
}
public void checkFalse()
{
textBox.Text = "unchecked :(";
}
}
How would I go about changing this to a set it as a new class to be called upon?
When creating a new class "checkBool", I wrote the following in a new .cs:
class checkBool
{
public void checkTrue()
{
textBox.Text = "checkbox was checked";
}
public void checkFalse()
{
textBox.Text = "unchecked :(";
}
}
However, the textbox is no longer recognized. How can I make this new class understand the reference?
The textbox is not recognized by the checkbool instance because it doesn't know about it.
One quick way to "let it know about it" is passing the textbox as a parameter to the checkTrue() and checkFalse() operations, like this:
class checkBool
{
public void checkTrue(TextBox textBox)
{
textBox.Text = "checkbox was checked";
}
public void checkFalse(TextBox textbox)
{
textBox.Text = "unchecked :(";
}
}
So the button click handler would be:
public void button_Click(object sender, RoutedEventArgs e)
{
checkBool cb = new checkBool();
if (checkBox1.IsChecked == true)
{
cb.checkTrue(textbox);
}
else
{
cb.checkFalse(textbox);
}
}
Keep in mind that by doing this you are introducing a dependency to your class checkBool (It depends to TextBox now).

How to change event handler of a menu button?

I have a class that derives from ContextMenuStrip. This class has standard buttons and is used throughout the project:
public class ItemMenu : ContextMenuStrip
{
public ItemMenu (IContainer container)
: base(container)
{
MenuItemAdd = new ToolStripMenuItem("Add", null, AddNew);
this.Items.AddRange(new ToolStripItem[]
{
mnuAdd,
});
}
public void AddNew(object sender, EventArgs e)
{
//Code to add new item here...
}
}
And in the form:
cmsMenu = new ItemMenu(this.components);
Now I have a particular situation where I want that the form itself handles the code for adding an item.
How can I change the above class so that in default cases the class itself handles the actions, but in particular situations, other methods (events/delegates?) are used?
The following changes were required to get it to work:
public class ItemMenu : ContextMenuStrip
{
public event EventHandler AddNewItem;
public ItemMenu (IContainer container)
: base(container)
{
MenuItemAdd = new ToolStripMenuItem("Add", null, AddNew);
this.Items.AddRange(new ToolStripItem[]
{
mnuAdd,
});
}
public void AddNew(object sender, EventArgs e)
{
EventHandler handler = AddNewItem;
if (handler != null)
{
handler(sender, e);
}
else
{
OnAddNew(sender, e);
}
}
protected void OnAddNew(object sender, EventArgs e)
{
//Code to add new item here...
}
}

Click event on Custom Control isn't firing (event assigned from containing form)

I have the following control, which just has a TreeView and ToolStrip dropped on it:
public partial class MyTreeView : UserControl
{
private string _nodeName;
public string NodeName { get { return _nodeName;} }
public MyTreeView()
{
InitializeComponent();
}
private void trv_AfterSelect(object sender, TreeViewEventArgs e)
{
if (e.Node == null || e.Node.Parent == null || e.Node.Parent.Parent == null)
return;
nodeName = e.Node.Parent.Parent.Text + #"\" + e.Node.Parent.Text + #"\" + e.Node.Text;
}
}
Then in my main form, which contains an instance of MyTreeView, I tried to add a Click event there:
private void mtv_Click(object sender, EventArgs e)
{
MessageBox.Show(mtv.NodeName.ToString());
}
The AfterSelect event fires and nodeName contains the expected value, but Click does not trigger.
Ultimately I'm going to be loading a file and displaying its contents in a textbox when the TreeView selection changes, but I can't figure out how to 'notify' the form the selection changed happened on the custom control.
Try this
public partial class MyTreeView : UserControl
{
public delegate void ValueSelectedHandler(object sender, EventArgs e, string value);
public event ValueSelectedHandler OnValueSelected;
private string _nodeName;
public string NodeName { get { return _nodeName;} }
public MyTreeView()
{
InitializeComponent();
}
private void trv_AfterSelect(object sender, TreeViewEventArgs e)
{
if (e.Node == null || e.Node.Parent == null || e.Node.Parent.Parent == null)
return;
nodeName = e.Node.Parent.Parent.Text + #"\" + e.Node.Parent.Text + #"\" + e.Node.Text;
if(OnValueSelected!=null)
{
OnValueSelected(sender, e, nodeName);
}
}
}
Now in your form
public Form1()
{
InitializeComponent();
myTreeView1.OnValueSelected += ValueSelected;
}
private void ValueSelected(object sender, EventArgs e, string value)
{
MessageBox.Show(value);
}
you may try this.
rewrite your control like this.
public partial class MyTreeView : UserControl
{
//create a custom event
[Browsable(true)]
public event TreeViewEventHandler AfterSelect;
public MyTreeView()
{
InitializeComponent();
}
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
if (AfterSelect != null) {
//raise the event , as it is subscribed may be in winform
AfterSelect.Invoke(sender, e);
}
}
}
and now in win form subscirbe after Select Event of MytreeView Control.
public Form2()
{
InitializeComponent();
//subscribe myTreeView1.AfterSelect event
myTreeView1.AfterSelect += new TreeViewEventHandler(myTreeView1_AfterSelect);
}
private void myTreeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
//cast sender into TreeView
TreeView tree = sender as TreeView;
if (tree != null) {
//do your logic here
}
}

Can I prevent ListBox.RefreshItem(object item) from removing and re-adding the object?

The issue I am having is that when I update my object, the ListBox automatically removes and then re-adds the object to the list, thus calling the index and value changed events. I was able to prevent this by creating a custom ListBox control and when the PropertyChangedEvent was called, I would raise a flag that would prevent those events in the base class from being called. What is happening now is that my entire reference is being replace by a new reference and unless I re-select the item in the ListBox, I have the wrong reference.
What I basically want to do, is to change the Display Value in my object and then have it update only the text in the list box. I do not want it to remove and to re-add the object/reference/whatever it does. It's quite annoying.
Here is the example code I am working with...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.myListBox1.SelectedValueChanged += this.onchange;
}
private void Form1_Load(object sender, EventArgs e)
{
this.myListBox1.Add(new strobj("z"));
this.myListBox1.Add(new strobj("a"));
this.myListBox1.Add(new strobj("b"));
this.myListBox1.Add(new strobj("f"));
this.myListBox1.Add(new strobj("n"));
this.myListBox1.Add(new strobj("h"));
this.myListBox1.Add(new strobj("p"));
this.myListBox1.Add(new strobj("t"));
this.myListBox1.Add(new strobj("c"));
this.myListBox1.Add(new strobj("q"));
}
private void onchange(object sender, EventArgs e)
{
MessageBox.Show("Hello World");
}
int i = 0;
private void button1_Click(object sender, EventArgs e)
{
if (this.myListBox1.SelectedItem != null)
{
strobj item = (strobj)this.myListBox1.SelectedItem;
item.Name1 = i++.ToString();
}
}
}
public partial class MyListBox
{
public MyListBox()
{
InitializeComponent();
}
public void Add(strobj item)
{
item.OnNameChanged += this.MyDispalyMemberChanged;
this.Items.Add(item);
}
bool refreshing = false;
public void MyDispalyMemberChanged(strobj itemChanged)
{
this.refreshing = true;
this.RefreshItem(this.Items.IndexOf(itemChanged));
this.refreshing = false;
}
protected override void OnSelectedValueChanged(EventArgs e)
{
if (!this.refreshing)
{
base.OnSelectedValueChanged(e);
}
}
}
class strobjCollection : List<strobj>
{
NameChangeEventHandler NameChangedEvent;
}
delegate void NameChangeEventHandler(strobj sender);
public class strobj
{
internal NameChangeEventHandler OnNameChanged;
private string _Name1;
public string Name1
{
get { return this._Name1; }
set
{
this._Name1 = value;
if (this.OnNameChanged != null)
{
this.OnNameChanged(this);
}
}
}
public int i = 0;
public string str = "p";
public strobj(string name)
{
this._Name1 = name;
}
public strobj()
{
this._Name1 = "You did not create this object";
}
public override string ToString()
{
return this._Name1;
}
}
This is what the INotifyPropertyChanged interface was made for.
Instead of raising your custom event, you'd raise the PropertyChanged event with the name of the property you changed set in the event args and the listbox would update.
See MSDN.

Categories

Resources