Problemas al dividir proyecto en archivos C#

Iniciado por Kaxperday, 6 Diciembre 2014, 00:40 AM

0 Miembros y 2 Visitantes están viendo este tema.

Kaxperday

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.
Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.

Eleкtro

#1
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:
Código (vbnet) [Seleccionar]
       If Me.ProgressBar1.InvokeRequired Then
           Me.ProgressBar1.Invoke(Sub()
                                      Me.ProgressBar1.PerformStep()
                                  End Sub)

       Else
           Me.ProgressBar1.PerformStep()

       End If


C#:
Código (csharp) [Seleccionar]
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:
Código (vbnet) [Seleccionar]
   ' 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#:
Código (csharp) [Seleccionar]
// 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

Saludos!








Kaxperday

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í:

Código (csharp) [Seleccionar]
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.
Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.

El Benjo

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
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

Kaxperday

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.
Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.

Eleкtro

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)

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!








Kaxperday

#6
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).
Cuando el poder económico parasita al político ningún partido ni dictador podrá liberarnos de él. Se reserva el 99% ese poder.