I have this code:
private void HandleGUI()
{
if (_currentForm == null)
{
navigationSideBar1.Visible = false;
pnlToolbar.Visible = false;
return;
}
if (_currentForm.ShowNavigationBar)
{
HandleNavigationButton(_currentForm);
}
btnSave.Visible = _currentForm.ShowSaveButton;
btnClose.Visible = _currentForm.ShowCloseButton;
btnSave.Paint += new PaintEventHandler(btnSave_Paint);
navigationSideBar1.Visible = _currentForm.ShowNavigationBar;
pnlToolbar.Visible = _currentForm.ShowToolBar;
btnSave.Refresh();
btnSave.Invalidate();
}
I am registered on the onpaint event of the save button (btnSave), but this event is not fired, even when I call Refresh or Invalidate. How is this possible?
EDIT:
This is how the saave button class looks like:
public class SaveButton : ButtonX
{
public SaveButton()
{
this.Image = Properties.Resources.Save;
this.Text = "Opslaan";
this.Size = new Size(108, 39);
}
}
Try adding a regular DevComponent button (i.e. not a subclass of it) to a test form and see if it ever fires its Paint event. They may have exposed a Paint event (so that their interface matches that of a regular button) but not actually implemented it.
Setting userpaint to true will fire the onpaint event
this.SetStyle(ControlStyles.UserPaint, true);
From MSDN:
Calling the Invalidate method does not force a synchronous paint; to force a synchronous paint, call the Update method after calling the Invalidate method.
So, you need an Update call. Now, Refresh is just Invalidate w/ update children + Update, so theoretically you're taken care of. All I can think is that Windows doesn't call Paint unless it really needs to, ie when the form is shown on the UI or written to a graphics device ("screenshot" of an invisible window). Are either of these the case?
It looks like you're not calling the base class constructor in the constructor of your SaveButton component.
public class SaveButton : ButtonX
{
public SaveButton() : base()
...
Related
I have an device with an integrated bixolon printer in it. I want to create an app to print on the printer. My OnCreate method looks as follow:
protected override void OnCreate(Bundle bundle){
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
printer = new BixolonPrinter(this, new MyHandler(), Looper.MainLooper);
printer.FindUsbPrinters();
//button connect
Button button = FindViewById<Button>(Resource.Id.buttonConnect);
button.Click += delegate {
printer.ConnectUsb();//in the brackets I would need the value of the Handler back once it is available
}; }
My Handler is as follow:
private class MyHandler : Handler
{
public override void HandleMessage(Message msg)
{
switch (msg.What)
{
case BixolonPrinter.MessageUsbDeviceSet:
Console.WriteLine("U S B device::: " + msg.Obj);
//can not return the msg.Obj back to the button event
break;
}
}
}
The problem is the once the instance of the BixolonPrinter is created it immediately fires the Handler. There is no way to bring back the result of the Handler to the button event. To make that problem a litte bit more complicated, the BixolonPrinter is a Java .jar file. So how can I get the result back to the event button?
When you use MainLooper, everything will be executed on main thread. Create HandlerThread for interaction instead. To postpone execution, use Handler.postDelayed() method, or, what is better, use RxJava library
I use a binding source so that all my controls are bound to datasource. Like this:
var category = categoryRequest.Get(id);
bindingSource.DataSource = category;
This works fine.
I've also implemented INotifyPropertyChanged on the DTO classes (even though this should not be done), so that a change in the object's properties is reflected immediately in the corresponding controls. This also works.
However, if the user loads an object, changes some text in some controls and decides to close the form, I would like to determine if data has been changed and prompt a "Are you sure?" message.
Currently, the way I'm doing it is like this:
public static bool DataChanged(this Form form)
{
bool changed = false;
if (form == null)
return changed;
foreach (Control c in form.Controls)
{
switch (c.GetType().ToString())
{
case "TextBox":
changed = ((TextBox)c).Modified;
break;
//Other control types here...
}
if (changed)
break;
}
return changed;
}
But I don't think this is the best way to do it because:
Each control type needs to the added manually
Checking if lists have changed won't work
Is there a better way to achieve what I need?
Do you want to check it only once? Like before closing the window.. If you do you can
declare public static bool changed=false; in the form class and change its value to true from where you have implimented the INotifyPropertychanged.
you can display a messagebox anywhere in the form as follows.
if(changed)
{
if (MessageBox.Show("Are you sure?","some caption",MessageBoxButtons.YesNo)==DialogResult.Yes)
{
//Do this if user presses YES
}
}
I realize this is an older thread, but I would suggest a simple solution:
if (YourTextBox.Modified)
{
// Your code goes here.
}
I think it has been around since version 1.0. You will find further information here.
Just subscribe to the BindingSource's ListChanged event and set an IsDirty flag based on the event.
categoryBindingSource.ListChanged += new System.ComponentModel.ListChangedEventHandler(categoryBindingSource_ListChanged);
and set IsDirty = true in the event method...
void customerAccountBindingSource_ListChanged(object sender, system.ComponentModel.ListChangedEventArgs e)
{
if (e.ListChangedType == System.ComponentModel.ListChangedType.ItemChanged)
_isDirty = true;
}
As per MSDN guidelines we need to put all the app's settings into the SettingsPane and then the app should update all pages when the settings is applied.
In my app I need to have a reset option which brings the app to the default settings. There are 2 pages, Calendar.xaml and HistoryStatistics.xaml that i need to update when the reset button is pressed. All the data of the app is put in a singleton class called CycleManager. I have used a SettingsFlyout control from the Callisto Toolkit.
App.Xaml
Registered the settings in the App.xaml
SettingsPane.GetForCurrentView().CommandsRequested += OnCommandsRequested;
and in OnCommandsRequested function, created the reset handler
var reset = new SettingsCommand("reset", "Reset", (handler) =>
{
var settings = new SettingsFlyout();
settings.Content = new ResetUserControl();
settings.HeaderBrush = new SolidColorBrush(_background);
settings.Background = new SolidColorBrush(_background);
settings.HeaderText = "Reset";
settings.IsOpen = true;
});
args.Request.ApplicationCommands.Add(reset);
CycleManager.cs
In the CycleManager class, there is a m_Reset variable,its setter and getter and an event handler called ResetClicked
public event EventHandler ResetClicked;
public bool Reset
{
get
{
return m_reset;
}
set
{
m_reset = value;
if (ResetClicked != null)
ResetClicked(this, EventArgs.Empty);
}
}
Next is the part where i have associated this handler in my first class calendar.xaml
Calendar.xaml
In the constructor of the class I declare the event handler
CycleManager pCycMan = CycleManager.Instance;
pCycMan.ResetClicked += this.ResetClicked;
followed by the definition of the event handler
private async void ResetClicked(object sender, EventArgs e)
{
CycleManager pCycMan = CycleManager.Instance;
if (pCycMan.Reset == true)
{
try
{
await Windows.Storage.ApplicationData.Current.ClearAsync(Windows.Storage.ApplicationDataLocality.Local);
pCycMan.InitializeValues();
}
catch (Exception)
{
}
}
CreateCalendar();// UI is loaded
}
In the constructor of the HistoryStatistics.xaml I have done the same thing as above
HistoryStatistics.xaml
public HistoryStatistics()
{
CycleManager pCycMan = CycleManager.Instance;
pCycMan.ResetClicked += this.ResetClicked;
}
and defined
private void ResetClicked(object sender, EventArgs e)
{
CycleManager pCycMan = CycleManager.Instance;
if (pCycMan.Reset == true)
{
await Windows.Storage.ApplicationData.Current.ClearAsync(Windows.Storage.ApplicationDataLocality.Local);
pCycMan.InitializeValues();
LoadListView();// loads the UI
DisplayStatistics();//loads the UI for the page
}
}
Now the problem
Is this the right approach?
When Reset is pressed in the first from the second page(HistoryStatistcs), the reset clicked function declared in the first page(Calendar.xaml.cs) is called first and then the one in HistoryStatistics. And both gets executed async! :(
Is this a right behaviour?
This question is quite long. Hope everybody understood the scenario and question.
There is nothing wrong with the behaviour you outlined. Two pages subscribe to an event and event uses multi cast delegate which means they will both get fired.
I think you need a simpler behaviour here. Each xaml page should subscribe to that event on OnNavigatedTo and should unsubscribe in OnNavigatedFrom.
That way only one of the two actually executes the cleanup.
The complexity/confusion is likely coming because of not using the MVVM (model, view, and view model) separation. you may want to read about this. keeping the separation helps. Below are few pointers on this. but not necessarily a full design for your app.
in this example: CycleManager.Instance is kind of serving the model (the data). You may want to rename ResetClicked to SettingChanged and think of the event as notification for clients that one or more settings properties exposed has changed. It should also expose ResetSettings() method that can be called by ResetUserControl.
// model for the settings
class SettingsManager
{
public event EventHandler SettingsChanged;
public async void ResetSettings()
{
await Windows.Storage.ApplicationData.Current.ClearAsync
(Windows.Storage.ApplicationDataLocality.Local);
// initialize all values to default values;
this._intializeValues();
if (this.SettingsChanged != null)
this.SettingsChanged(this, EventArgs.Empty);
}
}
HistoryStatistics and Calendar class should have view model that should listen for SettingsChanged event and update the properties exposed. Each page view (xaml) binds to the properties exposed by the respective view model. This will require some refactoring of current code.
Without that, ResetClick eventhandlers can be changed to SettingChanged event handlers and take required action. They need not call setting mgr to initialize values.
class HistoryStatistics
{
private void SettingsChanged(object sender, EventArgs e)
{
SettingsManager settingsManager = SettingsManager.Instance;
LoadListView();// loads the UI
DisplayStatistics();//loads the UI for the page
}
}
HTH.
I'm trying to use the DecelerationEnded callback in conjunction with 'Tapped' callbacks on MT.Dialog elements. I can't get the two to work at the same time.
When the DecelerationEnded callback is commented out, the 'tapped' callbacks work. When it's commented in, the 'tapped' callbacks don't get triggered anymore (whereas DecelerationEnded does).
When the DecelerationEnded call is moved above the setting of the Root, then the button 'tapped' callbacks work, but the DecelerationEnded callback doesn't. Delaying the callback setup until ViewWillAppear also doesn't fix anything.
Any solutions?
Example code:
public class TestController : DialogViewController
{
public TestController () : base(UITableViewStyle.Plain, null, true)
{
// Create list of 20 buttons.
Section s = new Section();
for (int i = 0; i < 20; i++ )
{
s.Add(new StringElement("test " + i, () => {
Console.WriteLine("Tapped"); // Tapped callback.
}));
}
Root = new RootElement("Test") {s};
// The following line causes all the "tapped" handlers to not work.
this.TableView.DecelerationEnded += HandleDecelerationEnded;
}
void HandleDecelerationEnded (object sender, EventArgs e)
{
Console.WriteLine ("Deceleration Ended");
}
}
In MonoTouch you can use either the C# style of callbacks or the Objective-C style of callbacks, but they can not be mixed together:
http://docs.xamarin.com/ios/advanced_topics/api_design#Delegates
Internally the MonoTouch.Dialog library implements its features by providing a full subclass that handles all of the events. If you use the C# syntax, it replaces the built-in handler with a proxy that in this case, merely responds to DecelerationEnded.
If you want to hook up to this, you need to subclass the existing "Source" class, and create this by overriding the CreateSizingSource, and it should provide a new instance of your class. This is the virtual method that you need to override to provide the same behavior but with your own classes:
public virtual Source CreateSizingSource (bool unevenRows)
{
return unevenRows ? new SizingSource (this) : new Source (this);
}
You can just subclass SizingSource and override the method there for the deceleration method.
TweetStation has a sample that shows how this is done: it uses the same event to determine when to remove the number of unread tweets from the screen.
C# has gone to great lengths to ensure that you cannot "fire" an event, e.g.:
form.FormClosed(this, new FormClosedEventArgs(CloseReason.UserClosing));
button.Click(this, new EventArgs());
customer.AddressChanged(this, new EventArgs());
don't compile because you cannot fire an event this way.
This seems to have been a conscious decision on the part of the language designers. They seem to be intentionally trying to prevent "bad behavior".
i am trying to find the intended replacement.
Practical Example:
void ShowPopup(Form form)
{
ToolStripDropDown toolDrop = new ToolStripDropDown();
ToolStripControlHost toolHost = new ToolStripControlHost(form);
toolHost.Margin = new Padding(0);
toolDrop.Padding = new Padding(0);
toolDrop.Items.Add(toolHost);
toolDrop.Closed += toolDrop_Closed;
toolDrop.Show(screenLocation);
}
void toolDrop_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
//The form's FormClosed event doesn't fire when shown as a popup
//Fire the event manually
form.FormClosed(this, new FormClosedEventArgs(CloseReason.UserClosing));
}
If i'm not supposed to fire events from outside the object - what is the technique intended to replace it?
If there is no intended replacement for firing events, is there any article, book, or Channel 9 video that explains how i should handle this situation?
An event inside a class has often a public method used by class clients to invoke the event from outside of the class:
public class Foo {
public event FooDelegate FooEvent;
public void RaiseFoo() {
if ( FooEvent != null ) FooEvent();
}
}
If an event is missing such public "trigger", it usually means that for some reason you should not be able to raise the event from outside.
In your example, the event can of course be raised with
form.Close();
with, apart from other things, also raises the event.