I am having an issue with the propertyGrid.
I have a class called DummySettings that is mapped to the propertyGrid
I have a property "Name"
When typing something in the propertygrid EG the Name property I would like to raise an event that "TextChanged"
Despite implementing the INotifyPropertyChanged event and raising it and despite hooking all sorts of events I can think of on the propertyGrid
none of this events fires when A text changes.
Am I missing the obvious?
EDITED
Psuedo Code
public class DummySettings : INotifyPropertyChanged
{
private string name;
[DisplayName("Name")]
public string Name
{
get { return name; }
set
{
if (name != value)
{
name = value;
OnPropertyChanged("Name");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
//UserControl
public partial class DummyControl : UserControl
{
private DummySettings settings;
///Constructor
public DummyControl()
{
InitializeComponent();
settings = new DummySettings();
propertyGrid1.SelectedObject = settings;
settings.PropertyChanged += OnDummyPropertyChanged;
//All the events I have hooked up but not firing when text is changed
private void OnDummyPropertyChanged(object sender, PropertyChangedEventArgs e)
{
btnToEnable.Enabled = HasName();
}
private void propertyGrid1_Leave(object sender, EventArgs e)
{
btnToEnable.Enabled = HasName();
}
private void propertyGrid1_Validating(object sender, CancelEventArgs e)
{
btnToEnable.Enabled = HasName();
}
private void propertyGrid1_SelectedObjectsChanged(object sender, EventArgs e)
{
btnToEnable.Enabled = HasName();
}
private void propertyGrid1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
btnToEnable.Enabled = HasName();
}
private bool HasName()
{
return settings.Name.IsNotNullOrEmpty();
}
You can use PropertyValueChanged event to get notified of selected object property changed in PropertyGrid. So, when you are changed Name property value from "Foo" to "Bar", this event will be raised:
void propertyGrid_PropertyValueChanged(object s, PropertyValueChangedEventArgs e)
{
// previous value is e.OldValue, "Foo"
// property name is e.ChangedItem.Label, "Name"
// new value is e.ChangedItem.Value, "Bar"
}
Related
My application in C# has a Textbox with a txt_TextChanged event.
private void txt_TextChanged(object sender, EventArgs e)
{
//Do somthin
}
But there's one specific part that I want to change txt.Text without firing the txt_TextChanged event.
txt.Text ="somthing" //Don't fire txt_TextChanged
How can I do that?
There is no direct way to prevent the raising of events for the text property, however your event handler can use a flag to determine weather or not to perform a task. This i likely to be more efficient than attaching and detaching the event handler. This can be done by a variable within the page or even a specialized class wrapper
With a variable:
skipTextChange = true;
txt.Text = "Something";
protected void TextChangedHandler(object sender, EventArgs e) {
if(skipTextChange){ return; }
/// do some stuffl
}
With specialized event handler wrapper
var eventProxy = new ConditionalEventHandler<EventArgs>(TextBox1_TextChanged);
TextBox1.TextChanged = eventProxy.EventAction;
eventProxy.RaiseEvents = false;
TextBox1.Text = "test";
public void TextBox1_TextChanged(object sender, EventArgs e) {
// some cool stuff;
}
internal class ConditionalEventHadler<TEventArgs> where TEventArgs : EventArgs
{
private Action<object,TEventArgs> handler;
public bool RaiseEvents {get; set;}
public ConditionalEventHadler(Action<object, TEventArgs> handler)
{
this.handler = handler;
}
public void EventHanlder(object sender, TEventArgs e) {
if(!RaiseEvents) { return;}
this.handler(sender, e);
}
}
txt.TextChanged -= textBox1_TextChanged; // dettach the event handler
txt.Text = "something"; // update value
txt.TextChanged += textBox1_TextChanged; // reattach the event handler
You can extend text box and introduce there a new property that will not trigger the TextChanged event.
class SilentTextBox : TextBox
{
// if true, than the TextChanged event should not be thrown
private bool Silent { get; set; }
public string SilentText
{
set
{
try
{
Silent = true;
Text = value;
}
finally
{
Silent = false;
}
}
}
protected override void OnTextChanged(EventArgs e)
{
// raise event only if the control is in non-silent state
if (!Silent)
{
base.OnTextChanged(e);
}
}
}
try this extension method
public static class TextBoxExt
{
private static readonly FieldInfo _field;
private static readonly PropertyInfo _prop;
static TextBoxExt()
{
Type type = typeof(Control);
_field = type.GetField("text", BindingFlags.Instance | BindingFlags.NonPublic);
_prop = type.GetProperty("WindowText", BindingFlags.Instance | BindingFlags.NonPublic);
}
public static void SetText(this TextBox box, string text)
{
_field.SetValue(box, text);
_prop.SetValue(box, text, null);
}
}
you can use textbox.SetText("...") to change text and the TextChanged event will not be fired.
A quick and dirty way is to do an
ctrl.Enable = false;
ctrl.Text = "Something";
ctrl.Enable = true;
and then in the OnChange event, encapsulate the offending code with a
if (ctrl.Enabled) {
// offending code here.
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
EventHandler TextChanged_EventHandler = new EventHandler(textBox1_TextChanged);
textBox1.TextChanged -= TextChanged_EventHandler;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("BUG");
}
}
I found a simple method, suitable for event handlers and controls that are not in the same .cs file
public static void SetTextWithoutRaiseEvent(this TextBox textBox, string content)
{
var scroll = textBox.Template.FindName("PART_ContentHost", textBox);
(scroll as ScrollViewer).Content = content;
}
I would like to create a simple custom control (actually a type of button). I have created the control but the step I am missing is how to add the binding. The control code I have looks like this:
public partial class PopUpButton : UserControl
{
public PopUpButton()
{
InitializeComponent();
_checked = false;
DrawButton();
}
public delegate void ChangedEventHandler(object sender, EventArgs e);
public event ChangedEventHandler OnValueChanged;
private bool _checked;
private String _text;
private void UserControl1_Resize(object sender, EventArgs e)
{
DrawButton();
}
[Bindable(true)]
public bool Checked
{
get
{
return _checked;
}
set
{
_checked = value;
DrawButton();
if (OnValueChanged != null)
{
OnValueChanged.Invoke(this, new EventArgs());
}
}
}
[Bindable(true)]
public String DisplayText
{
get
{
return _text;
}
set
{
_text = value;
DrawButton();
}
}
private void DrawButton()
{
// do some stuff
}
private void PopUpButton_Click(object sender, EventArgs e)
{
_checked = !_checked;
DrawButton();
if (OnValueChanged != null)
{
OnValueChanged.Invoke(this, new EventArgs());
}
}
}
The call to bind to the control looks like this:
regControl1.DataBindings.Clear();
regControl1.DataBindings.Add("Checked", CustomButton1, "Checked");
I know that I need to define a data source and member but cannot see how to implement this. When the above binding is called then regControl1 updates with the value of "Checked" however the function "OnValueChanged" is always null so the binding has failed, thus when "Checked" changes "regControl1" is not updated.
Ideas anyone?
Finally got something working. This solution handles a click both on the body and on the label and re-sizes the component during design. I was almost there but hope this helps:
public partial class PopUpButton : UserControl, INotifyPropertyChanged
{
public PopUpButton()
{
InitializeComponent();
_checked = false;
DrawButton();
}
private bool _checked;
private String _text;
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler ButtonClick;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
protected void Button_Click(object sender, EventArgs e)
{
_checked = !_checked;
DrawButton();
NotifyPropertyChanged("Checked");
if (this.ButtonClick != null)
this.ButtonClick(this, e);
}
private void UserControl1_Resize(object sender, EventArgs e)
{
DrawButton();
}
[Bindable(true)]
public bool Checked
{
get
{
return _checked;
}
set
{
_checked = value;
DrawButton();
NotifyPropertyChanged("Checked");
}
}
[Bindable(true)]
public String DisplayText
{
get
{
return _text;
}
set
{
_text = value;
DrawButton();
}
}
private void HandleClick( )
{
_checked = !_checked;
DrawButton();
NotifyPropertyChanged("Checked");
}
private void DrawButton()
{
//do some drawing stuff here
}
private void PopUpButton_Resize(object sender, EventArgs e)
{
DrawButton();
}
}
I am trying to return a value when a grid cell has been double clicked. Here is my code for setting up my delegate and event handler:
public class SelectedItemEventArgs : EventArgs
{
public string SelectedChoice { get; set; }
}
public event EventHandler<SelectedItemEventArgs> ItemHasBeenSelected;
Here is my code for setting up the double click:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
var handler = ItemHasBeenSelected;
if (handler != null)
{
handler(this, new SelectedItemEventArgs
{ SelectedChoice = txtCustomer.Text.ToString() });
}
}
Handler is always null. If I change the event handler code to this:
private void dataGridView1_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
var handler = ItemHasBeenSelected;
string choice = dataGridView1[0, e.RowIndex].ToString();
if (choice != null)
{
handler(this, new SelectedItemEventArgs
{ SelectedChoice = choice});
}
}
I get the error "Object reference not set to an instance of an object." I did see this: C# Delegate returns back NULL but I couldn't figure out how it worked. I ultimately want the value of dataGridView1[0, e.RowIndex] returned.
You have to ensure method is added into event before calling event.
private void Form1_Load(object sender, EventArgs e)
{
ItemHasBeenSelected += Form1_ItemHasBeenSelected;
}
private void Form1_ItemHasBeenSelected(object sender, SelectedItemEventArgs e)
{
MessageBox.Show("Chosen: " + e.SelectedChoice);
}
However, event is in fact for loosely coupling.
If everything is under your control, just directly call a method and save yourself from events.
I want to refresh my datagrid after adding data from childwindow.
Below is My Home.xaml.cs
public partial class Home : Page
{
ServiceReference1.Service1Client webService;
public Home()
{
InitializeComponent();
webService = new ServiceReference1.Service1Client();
webService.ReadPismaCompleted += WebService_ReadPismaCompleted;
webService.ReadPismaAsync(0);
}
private void WebService_ReadPismaCompleted(object sender, ServiceReference1.ReadPismaCompletedEventArgs e)
{
if(e.Result != null)
{
dataGridPisma.ItemsSource = e.Result;
}
}
private void button_Click(object sender, System.Windows.RoutedEventArgs e)
{
ChildWindow1 childWindow = new ChildWindow1();
childWindow.Closed += ChildWindow_Closed;
childWindow.Show();
}
private void ChildWindow_Closed(object sender, System.EventArgs e)
{
if (( (ChildWindow1)sender).DialogResult.Value) webService.ReadPismaAsync(0);
}
I don't see any changes after adding data (click OK button on childwindow not refresh datagrid). I know that data have been added because I see that in SQL server table and also when I refresh (press F5) on my web browser I see new data.
Use a PagedCollectionView in WebService_ReadPismaCompleted method
private PagedCollectionView _dataGridContext;
private void WebService_ReadPismaCompleted(object sender,serviceReference1.ReadPismaCompletedEventArgs e)
{
if(e.Result != null)
{
DataGridContext = new PagedCollectionView(e.Result)
}
}
public PagedCollectionView DataGridContext
{
get { return _dataGridContext; }
set {
_dataGridContext = value;
OnPropertyChanged("DataGridContext");
}
}
And set your DataGrid.DataContext=DataGridContext
Add this
`[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this,
new PropertyChangedEventArgs(propertyName));
}
}`
add remove datagridPisma.DataContext=DataGridContextfrom your setter.
Here is my code in my userControl
public partial class UserControlHomeScreen : UserControl
{
public event EventHandler SomethingHappened;
public void DoSomething()
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
public void HandleEvent(object sender, EventArgs args)
{
MessageBox.Show("Wafak.");
}
public UserControlHomeScreen()
{
InitializeComponent();
}
private void btnAverageDailyBal_Click(object sender, EventArgs e)
{
this.Tag = 0;
this.Hide();
}
private void btnComputeTransferPricing_Click(object sender, EventArgs e)
{
this.Tag = 1;
this.Hide();
}
}
And here is my code in my main form
private void HomeScreen()
{
uHomeScreen = new UserControlHomeScreen();
uHomeScreen.Dock = DockStyle.Fill;
//uHomeScreen.Disposed += new EventHandler(uHomeScreen_Disposed);
uHomeScreen.SomethingHappened += new EventHandler(uHomeScreen_SomethingHappened);
panelMain.Controls.Add(uHomeScreen);
}
void uHomeScreen_SomethingHappened(object sender, EventArgs e)
{
MessageBox.Show("throw new NotImplementedException();");
}
What i want to happen is that when the usercontrol is hidden i want to fire an event in my main form but does not work, what am i missing? please help. thanks!
Your naming convention for event raiser (DoSomething) is confusing, your code doesn't call DoSomething (or raise the event SomethingHappened), so how could it fire for you? Add the following code in your user control class:
//override the OnVisibleChanged
protected override void OnVisibleChanged(EventArgs e){
if(!Visible) DoSomething();
}