variable as type c# WPF - c#

I am using MVVM for my WPF form and now I want to close the new Dialog that I made when a user presses the Cancel button.
The cancel button is part of a seperate XAML that gets used around multiple forms. (similar to scripts in javascript)
this is what I have so far:
private void CloseDialogView(object sender)
{
var currentElement = (DependencyObject)sender;
List<object> windowTypes = new List<object>() {
typeof(fooDialogView),
typeof(barDialogView),
typeof(foobarDialogView) };
Type elementType;
do
{
var parent = VisualTreeHelper.GetParent(currentElement);
currentElement = parent;
elementType = (currentElement.GetType());
}
while (!windowTypes.Contains(elementType));
foreach (var type in windowTypes)
try
{
var Window = (type.GetType())currentElement;
Window.Close();
}
catch
{ }
}
in the do-while I just pass through all the elements in the form untill I hit the element that is the window.
In the foreach I want to check if it is one of the windowtypes (Xaml-forms) and if it is, cast that type to the 'currentElement' and then close it.
It does work if I just do
var Window = (fooDialogView)currentElement;
Window.Close();
but I want to avoid having to manually enter each seperate form-name.

Someone posted the answer
var Window = (Window)sender;
Window.Close();
but it turned out all I needed was
var Window = (Window)currentElement;
Window.Close();
right after the do-while, no need for the foreach-loop.
thanks for the swift help :)

Related

Must disconnect specified child from current parent Visual before attaching to new parent Visual

I'm new to WPF and trying to build my first application which is multiviewer of multi streams together for learning purpose.
I have 24 multimedia element on the main window and I want to Fullscreen selected multimedia element when there will be one more click to minimize this full screened media.
Code is like this
foreach (var item in MediaElements)
{
item.LoadedBehavior = MediaState.Manual;
item.MouseEnter += mediaElement1_MouseEnter;
item.MouseLeave += mediaElement1_MouseLeave;
item.Loaded += mediaElement1_Loaded;
item.MouseLeftButtonUp += (o, args) =>
{
if(!fullscreen)
{
ListOfMedia.Children.Remove(item);
this.Content = item;
this.WindowStyle = WindowStyle.None;
this.WindowState = WindowState.Maximized;
}
else
{
this.Content = ListOfMedia;
ListOfMedia.Children.Add(item);
this.WindowStyle = WindowStyle.SingleBorderWindow;
this.WindowState = WindowState.Normal;
}
fullscreen = !fullscreen;
};
}
When I click it the first time, it's working very well, the window is going on maximum screen size, but when I'm clicking it on next time to minimize it, there is an exception which is saying to me
System.ArgumentException: 'Must disconnect specified child from current parent Visual before attaching to new parent Visual.'
I checked some StackOverflow questions but can't find the correct solution, someone was talking about extension method to delete children from parents tree, I wrote this extension method but I don't know what is the problem and what idea is behind this problem? What I must delete from and what is happening at all.
Please tell me what is happening here.
The whole idea is that if an element already has a logical parent, then you cannot assign it as another elements child.
Imagine the following set up:
CtCtrl = ContentControl
StPnl = StackPanel
br1 = Border
if(CtCtrl.Content != null)
{
var br1 = CtCtrl.Content as Border;
StPnl.Children.Add(br1);
}
The above will result in System.InvalidOperationException:'Specified element is already the logical child of another elelemt. Disconnect it first.'
You can easily orphan that element before adding it to the StackPanel by the following code:
if(CtCtrl.Content != null)
{
var br1 = CtCtrl.Content as Border;
CtCtrl.Content = null;
StPnl.Children.Add(br1);
}
And the exception will be gone!

How to create shortcut of a button on a panel at runtime?

I have a panel that contains a lot of buttons(right panel). I want to add a shortcut of selected button to another panel(left panel) with the same properties and events dynamically at runtime.
Buttons have so many properties like image, text, backcolor, forecolore, ... etc.
Also the buttons will open new form inside main panel:
private void butntest_Click(object sender, EventArgs e)
{
this.main_panel.Controls.Clear();
Form1 myForm = new Form1();
myForm.TopLevel = false;
myForm.AutoScroll = true;
this.main_panel.Controls.Add(myForm);
myForm.Show();
}
How Can i create a shortcut on left panel?
You can create a clone method which accepts a button as input and creates another button based on the input button's properties, also handle click event of the cloned button and just call PerformClick method of the input button:
public Button Clone(Button input)
{
var output = new Button();
output.Text = input.Text;
// do the same for other properties that you need to clone
output.Click += (s,e)=>input.PerformClick();
return output;
}
Then you can use it this way:
var btn = Clone(button1);
panel1.Controls.Add(btn);
Also instead of a panel, it's better to use a FlowLayoutPanel or TableLayoutPanel, so you don't need to handle the location and the layout yourself.
Note: If it's a dynamic UI and users can reorder command buttons or create whatever you called shortcut, the probably for the next step you may need to store the status of the panel to be able to reload buttons at the next load of the application after the application closed. In this case it's better to consider a pattern like command pattern. Then you can have your commands as classes. The then you can say which button is responsible to run which command at run-time and you can simply store the relation between buttons and commands using their names.
Create class Button like so
Button leftpannelbutton = new Button();
leftpannelbutton = button1.Clone();
Now leftpannelbutton is eqaul to button1. Now just add that to your form.
Find Below ( Reflection)
public static class ControlExtensions
{
public static T Clone<T>(this T controlToClone)
where T : Control
{
PropertyInfo[] controlProperties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
T instance = Activator.CreateInstance<T>();
foreach (PropertyInfo propInfo in controlProperties)
{
if (propInfo.CanWrite)
{
if(propInfo.Name != "WindowTarget")
propInfo.SetValue(instance, propInfo.GetValue(controlToClone, null), null);
}
}
return instance;
}
}

Can't click button directly using TestStack.White

I'm trying to click a button on an external windows application. The following code successfully finds the element, brings the parent window into focus and then "manually" clicks the button
This works okay...
Process tProcess = Process.GetProcesses().FirstOrDefault(x => x.MainWindowTitle.StartsWith("MainWindowName"));
if (tProcess != null)
{
TestStack.White.Application application = TestStack.White.Application.Attach(tProcess.Id);
var tWindow = application.GetWindow(SearchCriteria.ByAutomationId("SubWindowName"), InitializeOption.NoCache);
SearchCriteria searchCriteria = SearchCriteria.ByAutomationId("btnCalibrate");
var calibrateBtn = tWindow.Get<TestStack.White.UIItems.Button>(searchCriteria);
tWindow.Focus();
var clickablePoint = calibrateBtn.AutomationElement.GetClickablePoint();
Mouse.Instance.Click(clickablePoint);
}
The problem with this is that Mouse.Instance.Click(clickablePoint); moves the cursor, ideally I don't want the cursor moved.
My initial code tried to click the button directly using the following
Process tProcess = Process.GetProcesses().FirstOrDefault(x => x.MainWindowTitle.StartsWith("MainWindowName"));
if (tProcess != null)
{
TestStack.White.Application application = TestStack.White.Application.Attach(tProcess.Id);
var tWindow = application.GetWindow(SearchCriteria.ByAutomationId("SubWindowName"), InitializeOption.NoCache);
SearchCriteria searchCriteria = SearchCriteria.ByAutomationId("btnCalibrate");
var calibrateBtn = tWindow.Get<TestStack.White.UIItems.Button>(searchCriteria);
tWindow.Focus();
calibrateBtn.Click();
}
but this gives the following error every time
TestStack.White.AutomationException
HResult=0x80131500
Message=Cannot perform action on Button. AutomationId:btnCalibrate, Name:Calibrate, ControlType:button, FrameworkId:WinForm,
Source=TestStack.White
StackTrace:
at TestStack.White.UIItems.UIItem.PerformIfValid(Action action) in c:\TeamCity\buildAgent\work\89a20b30302799e\src\TestStack.White\UIItems\UIItem.cs:line 254
at TestStack.White.UIItems.UIItem.Click() in c:\TeamCity\buildAgent\work\89a20b30302799e\src\TestStack.White\UIItems\UIItem.cs:line 231
at BetfairStreamingAPI.RadForm1.radLabelBetTime_Click(Object sender, EventArgs e) in D:
Does anyone know why the second method is throwing this error and if it's possible to fix this so that the button can be clicked without manually moving the cursor?
Edit: Screenshot of attempt to set togglestate
The solution to this particular problem appears to be use .RaiseClickEvent() instead of .Click()
The following code works
Process tProcess = Process.GetProcesses().FirstOrDefault(x => x.MainWindowTitle.StartsWith("MainWindowName"));
if (tProcess != null)
{
TestStack.White.Application application = TestStack.White.Application.Attach(tProcess.Id);
var tWindow = application.GetWindow(SearchCriteria.ByAutomationId("SubWindowName"), InitializeOption.NoCache);
SearchCriteria searchCriteria = SearchCriteria.ByAutomationId("btnCalibrate");
var calibrateBtn = tWindow.Get<TestStack.White.UIItems.Button>(searchCriteria);
calibrateBtn.RaiseClickEvent();
}
It's not entirely clear from the White docs when/why this is preferred. I found method RaiseClickEvent this on this link https://github.com/TestStack/White/commit/7b6d4dbc0008c3375e2ebf8810c55cb1abf91b60
EDIT2
I think you might have found something interesting. Since your button state is Indeterminate, it could be worth turning it on before clicking it:
calibrateBtn.State = ToggleState.On;
EDIT1
Alright, let's sort this out together.
There are only two reasons for that action to fail:
The button is not enabled, which I guess can't be the case
The button is OffScreen
If you do something like
Console.WriteLine(calibrateBtn.IsOffScreen.ToString());
You should see
true
If so, try this before you click it:
var pattern = calibrateBtn.AutomationElement.GetCurrentPattern(System.Windows.Automation.InvokePattern.Pattern);
(pattern as System.Windows.Automation.InvokePattern).Invoke();

How to get GTKSharp TreeView widget to display expanders?

So I am creating a treeview selector with C#/GTKSharp. I have the basic tree view selector functionality working: The data is loaded into my model and I can click on a node to collapse/expand.
The part I can't work out is how to tell the cell renderer to display the collapse/expand toggle button. In the examples it appears as a triangle that points right or down depending on whether the node is opened or collapsed. I just have a blank space that works as expected as I click but shows nothing.
One possibility is that I have a white on white text issue but I doubt it as my labels show up fine and I have not done any formatting yet.
I tried adding code for ShowExpanders but that was already true.
TreeView = new Gtk.TreeView();
// We add the event handlers (i.e. the control part) to the tree
TreeView.RowActivated += SelectorActivated; //On double click
TreeView.Selection.Changed += SelectorSelected; // On select (single click)
// Raise a context menu here??
// Connect to the ButtonPressEvent
// Raise a popup button
// Create columns [View]
Gtk.TreeViewColumn TreeViewColumTitle = new Gtk.TreeViewColumn();
TreeViewColumTitle.Title = "Profile";
Gtk.CellRendererText NameCellTitle = new Gtk.CellRendererText();
TreeViewColumTitle.PackStart(NameCellTitle, true);
TreeViewColumTitle.SetCellDataFunc(NameCellTitle, new Gtk.TreeCellDataFunc(RenderTitle));
NameCellTitle.Mode = CellRendererMode.Activatable;
// Populate the model
// Note that we could dispense with this step if we generated an ITreeModel
// interface in the Object class.
BindModel(Model);
// Attach everything to the pane
TreeView.Model = GTKModel;
TreeView.AppendColumn(TreeViewColumTitle);
TreeView.ShowExpanders = true;
TreeView.ExpanderColumn.Visible = true;
...
private void BindModel(Model Model) {
GTKModel = new Gtk.TreeStore(typeof(Object));
foreach (Object Object in Model.Selector) {
var BindingData = new BindingDataGTK(this, Object);
BindingData.Iter = GTKModel.AppendValues(Object);
Object.BindingData = BindingData;
BindChildren(GTKModel, BindingData);
}
}
private void BindChildren(TreeStore TreeStore, BindingDataGTK ObjectBinding) {
foreach (var Child in ObjectBinding.Object) {
var BindingData = new BindingDataGTK(this, Child);
BindingData.Iter = TreeStore.AppendValues(ObjectBinding.Iter, Child);
Child.BindingData = BindingData;
BindChildren(TreeStore, BindingData);
}
}
private void RenderTitle(Gtk.TreeViewColumn Column, Gtk.CellRenderer Cell,
Gtk.ITreeModel GTKModel, Gtk.TreeIter Iter) {
Object Object = (Object)GTKModel.GetValue(Iter, 0);
(Cell as Gtk.CellRendererText).Text = Object.Title;
Console.WriteLine("Render {0}", Object.Title);
}
So far as I know this is pretty much an automatic feature, I don't think anything special is needed to make it happen (I've certainly never needed to). You might want to try using a TreeIter to construct your tree instead?
E.g. assuming you already have a TreeView on your form with 0 (zero) columns in it called "treeview" and a list of "MyObject"s called "myListOfObjects"...
treeview.AppendColumn ("Some Title", new CellRendererText(), "text", 0);
Gtk.TreeStore _ts = new TreeStore (typeof(string));
foreach (IMyObject _mo in myListOfObjects) {
Gtk.TreeIter _it = _ts.AppendValues (_mo.SomeText);
RecurseInto (_ts, _it, _mo);
}
treeview.Model = _ts;
...
void RescureInto(Gtk.TreeStore ts, Gtk.TreeIter it, IMyObject mo)
{
foreach (IMyObject _child_mo in mo.Children) {
Gtk.TreeIter _it = ts.AppendValues (it, _child_mo.SomeText);
RecurseInto (ts, _it, _child_mo);
}
}
In theory this should work fine.

Winforms Prevent to open same forms Dynamic

If i click to button , my below code works very well.
if (Application.OpenForms["StockCardForm"] == null)
{
var stockCardForm = new StockCardForm();
stockCardForm.MdiParent = this;
stockCardForm.Show();
}
else
Application.OpenForms["StockCardForm"].Focus();
Instead of "StockCardForm" how can i give form name dynamic or how can i prevent to open same forms second time as dynamic ?
Any help will be appreciated.
Thanks.
You can check if there are any forms of some type already open and then do whatever you want.
if (!Application.OpenForms.OfType<StockCardForm>().Any())
{
var form = new StockCardForm();
form.Show();
}
else
Application.OpenForms.OfType<StockCardForm>().First().Focus();

Categories