I am trying to make a simple image viewer that loads images at start, creates Items with pulled SQL data and then creates Dictionary with all the Item parameters.
Then another method builds what's needed and fills StackPanel with UserControls (ITEM) that act as "links" to images.
Trying to add another image, from UserControl (NEW_ITEM) nested in View that is loaded to ContentControl in MainWindow.
public partial class fileUpload : UserControl
{
public fileUpload()
{
InitializeComponent();
}
string PathSource = #"SOURCE";
string PathToCopy = #"DESTINATION";
private void Border_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
PathSource = FU_source.Text;
if (!FU_fileName.Text.Contains("."))
{
MainWindow V = new MainWindow();
V.LoadCollection(); //This seems to work, but the content on MainWindow stays visible.
////Copy Inserted Item
File.Copy(PathSource,PathToCopy + FU_fileName.Text + ".png", true);
////Remove Item Preview From List
((ItemsControl)this.Parent).Items.Remove(this);
}
else
{
MessageBox.Show("ERR TEST", "ERR TEST HEADER");
}
}
}
Running LoadCollection() method does work OK if it's called from the MainWindow but does not work if called from fileUpload Class. (Program seems to do what's needed, but the user control won't disappear.)
Basically, it should refresh the whole process and refresh/refill StackPanel with new items.
I have encountered this problem many times and I think that I'm missing a key part in this.
TL;DR: I am trying to refresh MainWindows StackPanel with new Items, but the controls won't disappear if method taking care of this is called from UC Class.
Related
I'm trying to create a custom container as UserControl.
My Goal: I want to be able to drag controls inside the designer and handle incoming controls inside the code of my usercontrol.
Example: I place my container somewhere and then add a button. In this momemt I want my usercontrol to automatically adjust the width and position of this button. Thats the point where Im stuck.
My code:
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public partial class ContactList : UserControl
{
public ContactList()
{
InitializeComponent();
}
private void ContactList_ControlAdded(object sender, ControlEventArgs e)
{
e.Control.Width = 200; // Nothing happens
e.Control.Height = 100; // Nothing happens
MessageBox.Show("Test"); // Firing when adding a control
}
}
The MessageBox is working well. The set width and height is ignored.
The question is just "why?".
EDIT
I've just noticed, when placing the button and recompiling with F6 the button gets resized to 200x100. Why isnt this working when placing?
I mean... the FlowLayoutPanel handles added controls right when you place it. Thats the exact behaviour im looking for.
Using OnControlAdded
To fix your code, when you drop a control on container and you want to set some properties in OnControlAdded you should set properties using BeginInvoke, this way the size of control will change but the size handles don't update. Then to update the designer, you should notify the designer about changing size of the control, using IComponentChangeService.OnComponentChanged.
Following code executes only when you add a control to the container. After that, it respects to the size which you set for the control using size grab handles. It's suitable for initialization at design-time.
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (this.IsHandleCreated)
{
base.BeginInvoke(new Action(() =>
{
e.Control.Size = new Size(100, 100);
var svc = this.GetService(typeof(IComponentChangeService))
as IComponentChangeService;
if (svc != null)
svc.OnComponentChanged(e.Control,
TypeDescriptor.GetProperties(e.Control)["Size"], null, null);
}));
}
}
I have a small design question which I couldn't find relevant google hits for some reason.
I have a user control which I use in my application.
The main form opens a second form as a dialog. T
his second form is using the user control which includes a list box.
Naturally I want to preserve the list box items when the forms dispose so I am keeping a private list in the main form.
List<string> _listofFirstCoordinates = new List<string>();
Now the question is, should the dialog form be the one responsible for relaying the list to the main form or should the code be in the user control?
Should the one populating the list be the user control
lst_Coordinates.Items.AddRange(ListOfCoordinates.Cast<object>().ToArray());
or should the form using it populate it (The subform)
uc_EditCoordinates.ListOfCoordinates = ListOfCoordinates;
Also is it feasible to just have the user control be a public variable for the form holding it so it may be changed directly or would that be bad design?
Edit:
By the way, the data is saved for now in variables going back and forth between the forms as the user has to finish all subforms before submitting and finally saving it to the database. So it is a
var _listofFirstCoordinates = new List<string>();
going back and forth.
The "correct" solution is to abstract-away the View-level concern (in this case, anything to do with Form, UserControl, and UI controls) away from the Controller and Model-level concerns (in this case, your application's data).
Without completely rearchitecturing your system, you can still apply this separation-of-concerns within your example.
You can conceptually argue the "code-behind" of your MainForm class acts as a kind of Controller (purists would disagree). It will have to know about creating the child form, but it does not need to know about the user-control hosted within the child form - that would be the concern of the child form's.
I suggest defining a class that represents a ViewModel - albeit as we're using WinForms we will use it as a kind of crude "one-way" ViewModel, like so:
class MainForm : Form {
private void ShowChildFormModal() {
ChildViewModel vm = new ChildViewModel();
vm.CoordinatesList = ...
vm.OtherData = ...
ChildForm child = new ChildForm();
child.LoadFromViewModel( vm );
child.ShowDialog();
child.SaveToViewModel( vm );
SaveToDatabase( vm );
}
}
class ChildViewModel { // this is a POCO
public List<String> CoordinatesList;
public Int32 OtherData;
}
class ChildForm : Form {
public void LoadFromViewModel(ChildViewModel vm) {
// save time and trouble by using the List as a datasource directly, or you can manually populate the combobox as well
this.childUserControl.LoadFromViewModel( vm );
this.someOtherControl.Value = vm.OtherData;
}
public void SaveToViewModel(ChildViewModel vm) {
// completing this is an exercise for the reader
// but basically copy values from the controls on the form into the `vm` instance
}
}
class ChildUserControl : UserControl {
public void LoadFromViewModel(ChildViewModel vm) {
this.comboBox.DataSource = vm.CoordinatesList;
}
}
I am new to C#. I am using windows forms and I have Form1 which contains 2 buttons ( one to create user control at run time and the other creates buttons on user control at run time).
This code creates user control and FlowLayoutPanel (to organize button position) if you click add_UserControl button. And then it creates buttons on FlowLayoutPanel if you click Add_Buttons button and it is all done at run time.
Now in Form1 let's say I created user control and FlowLayoutPanel and then created 5 buttons , how can I save the properties/details of this user control with its FlowLayoutPanel and 5 buttons in SQL database so I can use them later when I run the program? I have been thinking about an idea and I reached the internet but no luck.
Any idea? Please help me. Thank you
public partial class Form1 : Form
{
FlowLayoutPanel FLP = new FlowLayoutPanel();
UserControl uc = new UserControl();
private void add_UserControl_Click(object sender, EventArgs e)
{
uc.Height = 700;
uc.Width = 900;
uc.BackColor = Color.Black;
Controls.Add(uc); //add UserControl on Form1
FLP.Height = 600;
FLP.Width = 800;
FLP.BackColor = Color.DimGray;
uc.Controls.Add(FLP); // add FlowLayoutPanel to UserControl
}
private void Add_Buttons_Click(object sender, EventArgs e)
{
//####### add buttons to FlowLayoutPanel ############
Button dynamicButton = new Button();
dynamicButton.Height = 50;
dynamicButton.Width = 200;
dynamicButton.BackColor = Color.Green;
dynamicButton.ForeColor = Color.Blue;
dynamicButton.Text = "";
FLP.Controls.Add(dynamicButton);
}
}
OK, First you need to create a class that will represent one of the buttons with the properties you need.
class MyButton
{
public string ButtonText {get;set;}
}
Everytime you click and create a button, you actually create an object of this class and add it to a collection or list. Then you would have some other code watching over the collection, and every time it gets a new entry, it creates a new button and sets its Button text to the text property. when a member of list is gone, it removes the button.
If you need more properties to be remembered (color, size, font, ...) you add them to the class as well. If you need for other controls, as well, .... you can always create common parent controls.
Simple.
If you want to be able to reload it, you could define the MyButton class as serializable and store it in xml file, and upon build, reload it.
You should watch into WPF and it's MVVM pattern. It's pretty much similar to it. Also have a look into command pattern, usefull pattern when it commes to this.
You can remember the FlowLayoutsPanels in one SQL table and in another table you could save the buttons which belong to these FlowLayoutPanels.
On Form Load or Application Load, you could check if there are already FlowLayoutPanels and correspending Buttons do exist in the SQL db and if yes then create them, else do nothing.
I have a WPF main window, which contains a toolbar with buttons and a tabcontrol that is displaying a page with a listbox. The page is hosted on a frame, and the frame is set on the tab I selected.
When I click on a button on my toolbar, a new window pops up with a textbox and a submit button. When I press the submit button, I want to insert the textbox contents into the listbox that's on the main window. However, nothing displays in the listbox. I tried listbox.Items.Add() but it still won't display.
public partial class AddNewCamper : Window
{
public AddNewCamper()
{
InitializeComponent();
}
private void btnNewSubmit_Click(object sender, RoutedEventArgs e)
{
CampersPage c;
// Converting string to int b/c thats what camper() takes in.
int NewAge = Convert.ToInt16(txtNewAge.Text);
int NewGrade = Convert.ToInt16(txtNewGrade.Text);
// Create a new person
Camper person = new Camper(NewAge, NewGrade, txtNewFirstName.Text);
txtNewFirstName.Text = person.getName();
// Trying to add the first name of the person to display on the listbox of another window.
c.testListBox.Items.Add(txtNewFirstName.Text);
}
You can follow any of the following approaches. But based on your comments I guess solution 3 suits you.
1) Try initializing c first. You can't use an object without allocating memory for it.
2) If you want to use the same object, use the reference of the object created in the MainWindow
in the required class.
something like this should work:
CampersPage c = [reference to CampersPage object in MainWindow]
then add items to your listbox
3) If you want to use the listbox object, make your CampersPage Class static.
Making it static would not require you to initialize your class explicitly.
public static CampersPage {
// do something here
}
Make sure that you declare your listbox in CampersPage as public.
Then in the class requiring your listbox defined in CampersPage, do the following
CampersPage.testListBox.Items.Add(txtNewFirstName.Text);
4) If the classes are in the same namespace, you can declare listbox as a global public property and access it from rest of the classes in the same namespace.
I have a C# WPF app that every time the user opens a new file, the contents are displayed in a datagrid.
public partial class MainWindow : Window
{
public TabControl tc = new TabControl();
public MainWindow()
{
InitializeComponents();
}
private FromFile_click(object sender, RoutedEventArgs e)
{
//gets information from file and then...
if (numberOfFiles == 0)
{
masterGrid.Children.Add(tc);
}
TabItem ti = new TabItem();
tc.Items.Add(ti);
DataGrid dg = new DataGrid();
ti.Content = dg;
dg.Name = "Grid"+ ++numberOfFiles;
dg.ItemSource = data;
}
private otherMethod(object sender, RoutedEventArgs e)
{
}
}
My question is, how do I use the data in dg in the method "otherMethod"? Also, is it possible to change the parent of dg from the method "otherMethod"?
Assuming you're not calling otherMethod within FromFile_Click, you need to make it an instance variable - like your TabControl is, except hopefully not public. I'm assuming otherMethod is actually meant to handle an event of some kind, rather than being called directly.
Now this is assuming that you want one DataGrid per instance of MainWindow, associated with that window. If that's not the case, you'd need to provide more information.
You have to pass it as a parameter to the other method otherMethod or make it a member variable.
set the DataGrid dg as a property instead of declaring inside the FromFile_click.
This way when you assign "dg" it will work from any other method (few restrictions apply)