Control Validating issue when WPF control hosted in ElementHost is clicked on WinForm Application - wpf-controls

I have a winform application on which there is a mix of Winform and a WPF control hosted on ElementHost. When the winform textbox goes into Validating because the WPF control is clicked, and there is validating error, the ElementHost keeps firing Focus event which makes my application stuck.
Please advice if there is a way to resolve it.
I have created a sample application to replicate the issue.
I have a Form1 containing 2 winform textboxes (textbox1, textbox2) and a WPF control hosted on ElementHost.
textbox1_validating event handler checks if input is not "1", then the event is cancelled by setting the event argument e.Cancel to true. This works well if textbox1 goes into validating because other winform control is clicked.
However, if textbox1 goes into validating due to WPF control gains focus, the cancel event does not work. ElementHost keeps firing Focus event causing textbox1_validating been called again and again.
UserControl Code:
<UserControl x:Class="WpfControlLibrary1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="54" d:DesignWidth="295" >
<Grid Height="43">
<TextBox Height="20" HorizontalAlignment="Left" Name="textBox1" VerticalAlignment="Top" Width="106" Text="Default1" />
<TextBox Height="20" HorizontalAlignment="Left" Margin="130,0,0,0" Name="textBox2" VerticalAlignment="Top" Width="73" Text="Default2" />
</Grid>
WinForm Code:
public partial class Form1 : Form
{
public static bool HasError = false;
public Form1()
{
InitializeComponent();
}
private void textBox1_Validating(object sender, CancelEventArgs e)
{
if (textBox1.Text != "1" && textBox1.Text != "")
{
MessageBox.Show("Input is invalid, expecting \"1\". ");
HasError = true;
e.Cancel = true;
}
}
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.label3 = new System.Windows.Forms.Label();
this._durationCtrlHost = new WindowsFormsApplication1.DurationCtrlHost();
this._durationCtrl = new WpfControlLibrary1.UserControl1();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(120, 23);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(242, 20);
this.textBox1.TabIndex = 0;
this.textBox1.Enter += new System.EventHandler(this.textBox1_Enter);
this.textBox1.Validating += new System.ComponentModel.CancelEventHandler(this.textBox1_Validating);
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(121, 56);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(240, 20);
this.textBox2.TabIndex = 2;
//
// label1
//
this.label1.AutoSize = true;
this.label1.Location = new System.Drawing.Point(24, 30);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(90, 13);
this.label1.TabIndex = 4;
this.label1.Text = "WinformTextbox1";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(25, 63);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(90, 13);
this.label2.TabIndex = 5;
this.label2.Text = "WinformTextbox2";
//
// label3
//
this.label3.AutoSize = true;
this.label3.Location = new System.Drawing.Point(24, 104);
this.label3.Name = "label3";
this.label3.Size = new System.Drawing.Size(64, 13);
this.label3.TabIndex = 6;
this.label3.Text = "WPFControl";
//
// _durationCtrlHost
//
this._durationCtrlHost.Location = new System.Drawing.Point(120, 90);
this._durationCtrlHost.Name = "_durationCtrlHost";
this._durationCtrlHost.Size = new System.Drawing.Size(271, 60);
this._durationCtrlHost.TabIndex = 3;
this._durationCtrlHost.Child = this._durationCtrl;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(420, 282);
this.Controls.Add(this.label3);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this._durationCtrlHost);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
}
public class DurationCtrlHost : ElementHost
{
private const int WM_SETFOCUS = 0x0007;
private const int WM_KILLFOCUS = 0x0008;
private int SetFocusFiredCount = 0;
private int KillFocusFiredCount = 0;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_SETFOCUS)
{
SetFocusFiredCount++;
if (Form1.HasError)
return;
}
else if (m.Msg == WM_KILLFOCUS)
{
KillFocusFiredCount++;
}
base.WndProc(ref m);
}
}

Related

MvvmCross: Cannot add more than one UIPickerView

I'm building an iOS view using Xamarin and MvvmCross and I have come across an interesting little issue. I can't seem to add more than one UIPickerView to a UIView.
Add one view and all works well. Add a second and the simulator just hangs when I try and open the page.
This seems to be related to a UITextField with an InputView as I also have an issue if I try to add a UIDatePicker as well.
Nothing strange in the debug output.
Here is the code:
[Register("EditJobViewJobView")]
public class EditJobView : MvxViewController
{
public new EditJobViewModel ViewModel
{
get { return (EditJobViewModel)base.ViewModel; }
}
private const float _leftMargin = 6;
private const float _labelHeight = 20;
private const float _pickerHeight = 28;
private readonly UIFont _labelFont = UIFont.BoldSystemFontOfSize(18f);
private readonly UIFont _controlFont = UIFont.SystemFontOfSize(18f);
private readonly UIView _paddingInsert = new UIView(new RectangleF(0, 0, 4, 0));
private int _currentTop = 0;
public override void ViewDidLoad()
{
base.ViewDidLoad();
View = new UIView() { BackgroundColor = UIColor.White };
NavigationItem.SetRightBarButtonItem(new UIBarButtonItem("Save", UIBarButtonItemStyle.Bordered,
(sender, args) => ViewModel.OkCommand.Execute(null)), true);
// ios7 layout
if (RespondsToSelector(new Selector("edgesForExtendedLayout")))
EdgesForExtendedLayout = UIRectEdge.None;
Title = "Edit Job";
AddLabel("Job Status");
MvxPickerViewModel jobStatusPickerViewModel;
var jobStatusTextView = AddPickerView(out jobStatusPickerViewModel);
AddLabel("Job Priority");
MvxPickerViewModel jobPriorityPickerViewModel;
var jobPriorityTextView = AddPickerView(out jobPriorityPickerViewModel);
var set = this.CreateBindingSet<EditJobView, EditJobViewModel>();
set.Bind(jobStatusPickerViewModel).For(p => p.SelectedItem).To(vm => vm.SelectedJobStatusType);
set.Bind(jobStatusPickerViewModel).For(p => p.ItemsSource).To(vm => vm.JobStatusTypes);
set.Bind(jobStatusTextView).To(vm => vm.SelectedJobStatusType);
set.Bind(jobPriorityPickerViewModel).For(p => p.SelectedItem).To(vm => vm.SelectedJobPriority);
set.Bind(jobPriorityPickerViewModel).For(p => p.ItemsSource).To(vm => vm.JobPriorities);
set.Bind(jobPriorityTextView).To(vm => vm.SelectedJobPriority);
set.Apply();
}
private void AddLabel(string caption)
{
_currentTop += 10;
var frame = new RectangleF(_leftMargin, _currentTop, 300, _labelHeight);
var label = new UILabel(frame);
label.Font = _labelFont;
label.Text = caption;
AddView(label);
_currentTop += 2;
}
private UITextField AddPickerView(out MvxPickerViewModel pickerViewModel)
{
var textField = AddTextField();
var pickerView = new UIPickerView();
pickerViewModel = new MvxPickerViewModel(pickerView);
pickerView.Model = pickerViewModel;
pickerView.ShowSelectionIndicator = true;
textField.InputView = pickerView;
return textField;
}
private UITextField AddTextField()
{
var frame = new RectangleF(_leftMargin, _currentTop, 300, _pickerHeight);
var textField = new UITextField(frame);
textField.Layer.BorderColor = UIColor.Black.CGColor;
textField.Layer.BorderWidth = 1f;
textField.Font = _controlFont;
textField.LeftView = _paddingInsert;
textField.LeftViewMode = UITextFieldViewMode.Always;
AddView(textField);
return textField;
}
private void AddView(UIView view)
{
View.AddSubview(view);
_currentTop += (int)view.Frame.Height;
}
}
Any ideas?
This was caused by creating a shared padding insert across a number of UITextFields.
To fix this I changed
textField.LeftView = _paddingInsert;
to
textField.LeftView = new UIView(new RectangleF(0, 0, 4, 0));

Arguments and changing the value

A newbie, please excuse the terms and explanation.
I have a program that accepts arguments which are in seconds. This in turn runs a timer that shows on the form. I want to give the user the ability to pause the timer for a set amount of time. I am having difficulty in trying to add time after the user Clicks the button as the method that runs the timer and countdown I have a method that gets the parameters of the argument.
I would like to maybe just get the parameters/arguments globally and then use them in all the different methods or threads. I am trying to do this in c# and wpf.
Code below:
public partial class MainWindow : Window
{
//int TimeOutPeriod = Int32.Parse("3600");
//private Timer timer;
System.Timers.Timer timer = new System.Timers.Timer();
public MainWindow()
{
InitializeComponent();
//timer = new Timer(1000);
timer = new System.Timers.Timer(1000);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
string[] param = Environment.GetCommandLineArgs();
int TimeOutPeriod = Int32.Parse(param[1]);
ProgressBar1.Maximum = TimeOutPeriod;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
string [] param = Environment.GetCommandLineArgs();
int TimeOutPeriod = Int32.Parse(param[1]);
int InYourFaceDisplay = Int32.Parse(param[2]);
this.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, (Action)(() =>
{
if (ProgressBar1.Value < TimeOutPeriod)
{
ProgressBar1.Value += 1;
RebootCDown.Content = "Machine will reboot in : " + (TimeOutPeriod - ProgressBar1.Value) + " Secs";
if ((TimeOutPeriod - ProgressBar1.Value) < InYourFaceDisplay)
{
this.Activate();
}
}
else
{
ShutDownWindows("0");
timer.Stop();
this.Close();
}
}));
}
private void SnoozeNow_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
System.Windows.Forms.NotifyIcon ni = new System.Windows.Forms.NotifyIcon();
ShowInTaskbar = false;
ni.Icon = new System.Drawing.Icon("C:\\temp\\RebootIco.ico");
ni.Visible = true;
ShowInTaskbar = false;
ni.ShowBalloonTip(5000, "Test App", "Notify icon is working! Right click to access the context menu.", System.Windows.Forms.ToolTipIcon.Info);
Task.Delay(10000);
ShowInTaskbar = true;
}
}

WinRT RichEditBox Limitations

In Windows Store app (XAML/C#), I've created a custom control with 'RichEditBox' in it. I want to limit number of characters (MaxLength) for it or at least vertical scroll bar should be disabled. How can I achieve it?
I think it's not possible to set a limit for the number of characters in a declarative manner, but you may handle the text changed event and do your checks in code behind.
For the scroller you can set the ScrollViewer.VerticalScrollBarVisibility property to Disabled.
Here try this out:
<RichEditBox x:Name="TextElementControl"
Background="{Binding Background, ElementName=userControlModified}"
ManipulationMode="None"
ScrollViewer.HorizontalScrollMode="Disabled"
AcceptsReturn="True" TextWrapping="Wrap"
SizeChanged="TextElementControlSizeChanged"
IsDoubleTapEnabled="False"
BorderThickness="0"
BorderBrush="{x:Null}"
Padding="10,10,10,10"
/>
Code Behind:
TextElementControl.TextChanged += TextElementControlTextChanged;
More Code Behind:
private void TextElementControlTextChanged(object sender,
RoutedEventArgs e)
{
string str;
TextElementControl.Document.GetText(Windows.UI.Text.TextGetOptions.None,
out str);
TextElementControl.Height = double.NaN;
if (str.Trim().Length > 502 && !_loading)
{
if (popUpReminder == null)
{
popUpReminder = new Popup();
popUpReminder.IsLightDismissEnabled = true;
var panel = new StackPanel();
panel.Background = BlackSolidColorBrush;
panel.Height = 60;
panel.Width = 220;
var reminderText = new TextBlock();
reminderText.FontSize = 14;
reminderText.Text = "You have exceeded the maximum number of characters for this textbox.";
reminderText.TextWrapping = TextWrapping.Wrap;
reminderText.Focus(Windows.UI.Xaml.FocusState.Programmatic);
reminderText.Margin = new Thickness(10, 5, 10, 5);
panel.Children.Add(reminderText);
Border brder = new Border();
brder.BorderBrush = RedSolidColorBrush;
brder.BorderThickness = new Thickness(2);
brder.Child = panel;
popUpReminder.Child = brder;
popUpReminder.HorizontalOffset = Window.Current.CoreWindow.Bounds.Width - panel.Width - 10;
popUpReminder.VerticalOffset = Window.Current.CoreWindow.Bounds.Bottom - 100 - panel.Height - 10;
}
popUpReminder.IsOpen = true;
TextElementControl.Document.Undo();
} }

Add New Row in GridView winform on Button Click

Add New Row in GridView winform on Button Click.
Need to have single button in grid rather than DataGridViewButtonColumn
you can add it by using
GridView1.DataSource = datatable;
and then add new row by this
datatable.Rows.Add();
this will add new row and give control id into add().
use this
public partial class Form1 : Form
{
Button textBoxDgv1 = new Button();
Label labelDgv1 = new Label();
the next is on the Form_Load event
private void Form1_Load(object sender, EventArgs e)
{
labelDgv1.Text = "Delete";
labelDgv1.Height = 20;
labelDgv1.AutoSize = false;
labelDgv1.BorderStyle = BorderStyle.FixedSingle;
labelDgv1.TextAlign = ContentAlignment.MiddleCenter;
int Xdgv1 = this.dataGridView1.GetCellDisplayRectangle(2, -1, true).Location.X;
labelDgv1.Width = this.dataGridView1.Columns[2].Width + Xdgv1;
labelDgv1.Location = new Point(0, this.dataGridView1.Height - textBoxDgv1.Height);
this.dataGridView1.Controls.Add(labelDgv1);
and one more section is in dataGridView1_CellPainting
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
int sum = 0;
for (int i = 0; i < this.dataGridView1.Rows.Count; i++)
{
if (dataGridView1.Rows[i].Cells[3].Value != string.Empty)
{
sum += Convert.ToInt32(this.dataGridView1[3, i].Value);
}
}
textBoxDgv1.Text = sum.ToString();
int Xdgvx = this.dataGridView1.GetCellDisplayRectangle(2, -1, true).Location.X;
labelDgv1.Width = this.dataGridView1.Columns[2].Width + Xdgvx;
labelDgv1.Location = new Point(0, this.dataGridView1.Height - textBoxDgv1.Height);
textBoxDgv1.Width = this.dataGridView1.Columns[3].Width;
Xdgvx = this.dataGridView1.GetCellDisplayRectangle(3, -1, true).Location.X;
textBoxDgv1.Location = new Point(Xdgvx, this.dataGridView1.Height - textBoxDgv1.Height);
}

After first click_event was fired, the second click_event does not fire

I have two linkbuttons which are added dynamically depending on conditions, whether to display one or another. These buttons have events also.
Firstly displayed button's event fires, but when conditions change and second button displayed, it's event does not fire.
source code:
//conditions
bool wantToChangeBlogPost = false;
string textBoxOnChangeID = "";
protected void displayBlogPost()
{
SomeArraylist[] arr = valuesFromDdataBase();
foreach(BlogPost y in arr)
{
string contentStr = y.BlogMailingText;//"some content in mailing";
//div for displaying content in webpage
System.Web.UI.HtmlControls.HtmlGenericControl contentDIV = new
System.Web.UI.HtmlControls.HtmlGenericControl("div");
contentDIV.InnerHtml = contentStr;
//TB for changes
TextBox TBcontent = new TextBox();
TBcontent.Text = contentStr;
TBcontent.AutoPostBack = true;
TBcontent.TextMode = TextBoxMode.MultiLine;
TBcontent.Wrap = true;
TBcontent.ReadOnly = true;
TBcontent.EnableViewState = true;
//two different buttons for cases, whether or not want to change the text
//of blogPost
LinkButton changePost = new LinkButton();
changePost.Text = "Change MailingText";
LinkButton savePost = new LinkButton();
savePost.Text = "Save Changes";
//id 's are needed for controls
TBcontent.ID = "content-" + y.Id;
contentDIV.ID = "contentDIV-" + y.Id;
changePost.ID = "changePost-" + y.Id;
savePost.ID = "savePost-" + y.Id;
changePost.CommandArgument = "content-" + y.Id;
savePost.CommandArgument = "content-" + y.Id;
//Add these controls to the placeholder, which is defined in asmx:
//initially add only the contentDiv
myPlaceHolder.Controls.Add(contentDiv);
///////////////////////////
// HERE IS THE PROBLEM: //
///////////////////////////
//Conditions determing when to display one or another linkbutton and
//TBcontent
if (wantToChangeBlogPost == true && textBoxOnChangeID == "content-" + y.Id)
{
savePost.Click += new EventHandler(save_click);
//HERE IS THE PROBLEM: this event never fires :(
contentDIV.InnerHtml = "";
TBcontent.ReadOnly = false;
TBcontent.Visible = true;
// this button is displayd when someone has clicked on button
//'changePost'
myPlaceHolder.Controls.Add(savePost);
}
else
{
changePost.Click += new EventHandler(changePost_Click);
contentDIV.InnerHtml = contentStr;
TBcontent.ReadOnly = true;
TBcontent.Visible = false;//initially the TB is not visible
//initially the bool is false and
// this button is displayd
myPlaceHolder.Controls.Add(changePost);
}
}
//event methods for both buttons
//AFTER THIS METHOD COMPLETED I WANT TO DISPLAY THE ANOTHER LINKBUTTON
//'savePost' WITH ANOTHER EVENT 'save_click'
protected void changePost_Click(object sender, EventArgs e)
{
LinkButton LB = sender as LinkButton;
//CONDITIONS
textBoxOnChangeID = LB.CommandArgument;
wantToChangeBlogPost = true;
//GO TO THE DISPLAYING METHOD AGAIN
displayBlogPost();
}
//THIS METHOD NEVER EVEN FIRES! WHY??????
protected void save_click(object sender, EventArgs e)
{
LinkButton LB = sender as LinkButton;
//CONDITIONS
textBoxOnChangeID = "";
wantToChangeBlogPost = false;
//some logic to send changed data to the database to upload
//datatable
uploadWithChangedDataInTextBox();
//GO TO THE DISPLAYING METHOD AGAIN
displayBlogPost();
}
}
if you are adding controls dynamically then you have to recreate those on every post back keeping the id same then only the event wiil fire
or if ur adding the controls throught any other method like client side then u can call
__doPostBack(eventTarget,eventArg) and check for the id on the server side and then call sm function accordingly

Resources