En un proyecto de C# de windows forms tengo todas las funciones metidas en el Form1.cs, lo que quiero es dividir todas las funciones en archivos .cs y a través de la interfaz del Form1.cs llamar a sus clases.
El main lo que hace es iniciar el form y una vez allí se pulsan botones para llamar a funciones, pero ojo, estas funciones no están en Form1.cs estan en Descargas.cs por ejemplo, vale diréis basta con incluir ese archivo en el Form1.cs y solucionado bien, pero en esas funciones hay controles textbox, de barras de carga, y demás que me dan error, PE:
En descargas.cs tengo una aplicaciones que descarga y va llenando una barra de carga, pero ese archivo no tiene acceso al form para modificar el estado de la barra, ¿como puedo hacerlo? ¿Hay otra alternativa? ¿Qué usáis habitualmente?
Saludos.
La funcionalidad de una función (valga la redundancia) es para devolver "algo", es una mala practica utilizar una función como si fuese un método, o para modificar controles.
La solución es bien facil, en lugar de hacer algo como esto:
function MyFunc() as integer
main.control1.text "lo que sea"
main.control2.enabled = False
Return 0
end function
Deberías hacer:
main.Control1.text = MyFuncControl1
main.Control2.enabled = MyFuncControl2
Value = myFuncValue
Es un ejemplo pobre, pero creo que el contexto se entiende a la perfección, solo tienes que organizar mejor el código...
Cita de: Kaxperday en 6 Diciembre 2014, 00:40 AMen esas funciones hay controles textbox, de barras de carga, y demás que me dan error, PE:
¿Vas a mencionar cual es el mensaje de la excepción?.
Cita de: Kaxperday en 6 Diciembre 2014, 00:40 AMese archivo no tiene acceso al form para modificar el estado de la barra, ¿como puedo hacerlo? ¿Hay otra alternativa? ¿Qué usáis habitualmente?
Sin saber de que errore hablas, intuyo que estás utilizando un thread para intentar modificar controles que no han sido creados desde dicho thread, sino desde el thread principal (el de la UI), y estás sufriendo un error del tipo
cross-threading exception precisamente por intentar hacer ese tipo de modificación ilegal, ya que no es una operación
thread-safe.
Solución:
VB:
If Me.ProgressBar1.InvokeRequired Then
Me.ProgressBar1.Invoke(Sub()
Me.ProgressBar1.PerformStep()
End Sub)
Else
Me.ProgressBar1.PerformStep()
End If
C#:
if (this.ProgressBar1.InvokeRequired) {
this.ProgressBar1.Invoke(() => { this.ProgressBar1.PerformStep(); });
} else {
this.ProgressBar1.PerformStep();
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================
O bien puedes utilizar la misma solución pero dándole un uso más genérico:
VB:
' Invoke Control
' ( By Elektro )
'
' Usage Examples :
' InvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
' InvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
''' <summary>
''' Invokes an <see cref="T:Action"/> delegate on the specified control.
''' This method avoids cross-threading exceptions.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="control">The control to invoke.</param>
''' <param name="action">The encapsulated method.</param>
Public Sub InvokeControl(Of T As Control)(ByVal control As T, ByVal action As Action(Of T))
If control.InvokeRequired Then
control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl),
New Object() {control, action})
Else
action(control)
End If
End Sub
' Begin Invoke Control
' ( By Elektro )
'
' Usage Examples :
' BeginInvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
' BeginInvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
''' <summary>
''' Invokes an asynchronous <see cref="T:Action"/> delegate on the specified control.
''' This method avoids cross-threading exceptions.
''' </summary>
''' <typeparam name="T"></typeparam>
''' <param name="control">The control to invoke.</param>
''' <param name="action">The encapsulated method.</param>
Public Sub BeginInvokeControl(Of T As Control)(ByVal control As T, ByVal action As Action(Of T))
If control.InvokeRequired Then
control.BeginInvoke(New Action(Of T, Action(Of T))(AddressOf BeginInvokeControl),
New Object() {control, action})
Else
action(control)
End If
End Sub
C#:
// Invoke Control
// ( By Elektro )
//
// Usage Examples :
// InvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
// InvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
/// <summary>
/// Invokes an <see cref="T:Action"/> delegate on the specified control.
/// This method avoids cross-threading exceptions.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="control">The control to invoke.</param>
/// <param name="action">The encapsulated method.</param>
public void InvokeControl<T>(T control, Action<T> action) where T : Control
{
if (control.InvokeRequired) {
control.Invoke(new Action<T, Action<T>>(InvokeControl), new object[] {
control,
action
});
} else {
action(control);
}
}
// Begin Invoke Control
// ( By Elektro )
//
// Usage Examples :
// BeginInvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
// BeginInvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
/// <summary>
/// Invokes an asynchronous <see cref="T:Action"/> delegate on the specified control.
/// This method avoids cross-threading exceptions.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="control">The control to invoke.</param>
/// <param name="action">The encapsulated method.</param>
public void BeginInvokeControl<T>(T control, Action<T> action) where T : Control
{
if (control.InvokeRequired) {
control.BeginInvoke(new Action<T, Action<T>>(BeginInvokeControl), new object[] {
control,
action
});
} else {
action(control);
}
}
//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================
⇲ Recursos que deberias leer
- Make Thread-Safe Calls to Windows Forms Controls - MSDN (http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.85%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1)
- [VB/C#] Asynchronous Programming (http://msdn.microsoft.com/en-us/library/hh191443.aspx)
- Control.Invoke Method (Delegate) (http://msdn.microsoft.com/en-us/library/zyzhdc6b%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1)
- Control.BeginInvoke Method (Delegate) (http://msdn.microsoft.com/en-us/library/0b1bf3y3%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1)
Saludos!
Me estoy mirando un poco tus links, pero no me refería a eso no era tema de threads, lo que pasa es que en el proyeco tengo un archivo llamado descargas.cs que tiene algo así:
namespace proyectoname
{
class Descargas
{
private void descargaForos()
{
tboxForos.Text = "";
pbarForos.Value = pbarForos.Minimum;
detenerForos = false;
...
Y eso me da error normal dice que "no existe en el contexto actual" el tboxForos (una textbox del form1 otro archivo ni el detenerForos una variable global del form1 para detener el proceso de descarga si es activada a true.
El problema es que al dividir el proyecto en varios archivos cs con funciones, ¿esas funciones pierden el acceso de control a la interfaz del form no? ¿Como podría hacer para manipular la barra de carga del form1 desde esta funcion de otro archivo del mismo proyecto?
Siempre podría meterlo todas las funciones en el form1 y listo, pero lo que quiero es no tener un archivo de 3000 lineas, quiero dividir en archivos sin que afecte por así decirlo, siguiendo teniendo acceso al control del form como si en el estuviese.
Saludos y gracias por la respuesta no sé ni si será posible xD, la cosa es que las funciones estarían solo para llamarlas ok, perouna funcion de descarga como haces para que te vaya rellenando la barra o una funcion que abre archivo y lo pone en un textbox etc.
Lo que ocurre es que si tratas de acceder fuera del código del Form no puedes porque los controles por defecto se declaran como privados.
La primera solución sería que cambiaras el atributo de los controles a Public, pero esto es una mala práctica ya que, hasta donde nos das a entender, las mismas funciones son llamadas desde el Form.
Lo segundo, que es lo que yo te recomiendo, sería que utilices el modificador partial en la declaración del Form. Después en otro archivo vuelves a declarar el Form como una declaración parcial y ahí colocas las funciones. Con este segundo método ya no te debería más problemas. Te dejo el enlace sobre la declaración partial para que sepas cómo usarla.
http://msdn.microsoft.com/es-es/library/wa80x488.aspx (http://msdn.microsoft.com/es-es/library/wa80x488.aspx)
Lo estoy leyendo pero no entiendo como hacerlo todavía de todas formas, ¿cómo se añade un archivo a otro? En plan "include "descargas.h"", porque no me reconoce las clases de otros archivos en el principal, estoy en ello saludos.
Cita de: Kaxperday en 7 Diciembre 2014, 16:06 PMLo estoy leyendo pero no entiendo como hacerlo todavía de todas formas, ¿cómo se añade un archivo a otro? En plan "include "descargas.h"", porque no me reconoce las clases de otros archivos en el principal, estoy en ello saludos.
⇲ Para incluir un
NameSpace se utiliza la directiva
Using.
using Directive (C# Reference) (http://msdn.microsoft.com/en-us/library/sf0df423.aspx)
Sobre el otro problema (que viene siendo el mismo problema en realidad) que ya aclaraste que no estaba relacionado con los threads, el tema de la visibilidad de miembros se maneja un poco distinto entre C# y VB, así que en eso no me meto ya que podría meter la pata.
Saludos!
OMG que chorrada era vaya bobo xD, se me fue la pinza jaja para lo de incluir lo que pasaba es que no era visible tenia que ponerlo public 8), no vale using descargasl.cs claro xD.
Respecto a lo de partial no me he enterado muy bien, pero estoy dividiendolo en pequeñas funciones todo y llevar el control de la interfaz desde el form con las barras de carga y textboxs, estoy en ello, gracias.
Por cierto aprovecho para decir que, no se si sabréis para devolver unas cookies un cookie container en una funcion, pues tengo una función que inicia sesión y recoge las cookies, pero no se como "returnarlas", ¿a alguien se le ocurre algo xp?
(Es que sino la funcion no vale para nada xD).