Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: Kaxperday en 6 Diciembre 2014, 00:40 am



Título: Problemas al dividir proyecto en archivos C#
Publicado por: Kaxperday en 6 Diciembre 2014, 00:40 am
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.


Título: Re: Problemas al dividir proyecto en archivos C#
Publicado por: Eleкtro en 6 Diciembre 2014, 10:24 am
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:
Código:
function MyFunc() as integer
    main.control1.text "lo que sea"
    main.control2.enabled = False
    Return 0
end function

Deberías hacer:
Código:
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...




en 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?.

ese 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
  1.        If Me.ProgressBar1.InvokeRequired Then
  2.            Me.ProgressBar1.Invoke(Sub()
  3.                                       Me.ProgressBar1.PerformStep()
  4.                                   End Sub)
  5.  
  6.        Else
  7.            Me.ProgressBar1.PerformStep()
  8.  
  9.        End If

C#:
Código
  1. if (this.ProgressBar1.InvokeRequired) {
  2. this.ProgressBar1.Invoke(() => { this.ProgressBar1.PerformStep(); });
  3.  
  4. } else {
  5. this.ProgressBar1.PerformStep();
  6.  
  7. }
  8.  
  9. //=======================================================
  10. //Service provided by Telerik (www.telerik.com)
  11. //=======================================================

O bien puedes utilizar la misma solución pero dándole un uso más genérico:

VB:
Código
  1.    ' Invoke Control
  2.    ' ( By Elektro )
  3.    '
  4.    ' Usage Examples :
  5.    ' InvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
  6.    ' InvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
  7.  
  8.    ''' <summary>
  9.    ''' Invokes an <see cref="T:Action"/> delegate on the specified control.
  10.    ''' This method avoids cross-threading exceptions.
  11.    ''' </summary>
  12.    ''' <typeparam name="T"></typeparam>
  13.    ''' <param name="control">The control to invoke.</param>
  14.    ''' <param name="action">The encapsulated method.</param>
  15.    Public Sub InvokeControl(Of T As Control)(ByVal control As T, ByVal action As Action(Of T))
  16.  
  17.        If control.InvokeRequired Then
  18.            control.Invoke(New Action(Of T, Action(Of T))(AddressOf InvokeControl),
  19.                           New Object() {control, action})
  20.  
  21.        Else
  22.            action(control)
  23.  
  24.        End If
  25.  
  26.    End Sub
  27.  
  28.    ' Begin Invoke Control
  29.    ' ( By Elektro )
  30.    '
  31.    ' Usage Examples :
  32.    ' BeginInvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
  33.    ' BeginInvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
  34.  
  35.    ''' <summary>
  36.    ''' Invokes an asynchronous <see cref="T:Action"/> delegate on the specified control.
  37.    ''' This method avoids cross-threading exceptions.
  38.    ''' </summary>
  39.    ''' <typeparam name="T"></typeparam>
  40.    ''' <param name="control">The control to invoke.</param>
  41.    ''' <param name="action">The encapsulated method.</param>
  42.    Public Sub BeginInvokeControl(Of T As Control)(ByVal control As T, ByVal action As Action(Of T))
  43.  
  44.        If control.InvokeRequired Then
  45.            control.BeginInvoke(New Action(Of T, Action(Of T))(AddressOf BeginInvokeControl),
  46.                                New Object() {control, action})
  47.  
  48.        Else
  49.            action(control)
  50.  
  51.        End If
  52.  
  53.    End Sub



C#:
Código
  1. // Invoke Control
  2. // ( By Elektro )
  3. //
  4. // Usage Examples :
  5. // InvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
  6. // InvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
  7.  
  8. /// <summary>
  9. /// Invokes an <see cref="T:Action"/> delegate on the specified control.
  10. /// This method avoids cross-threading exceptions.
  11. /// </summary>
  12. /// <typeparam name="T"></typeparam>
  13. /// <param name="control">The control to invoke.</param>
  14. /// <param name="action">The encapsulated method.</param>
  15. public void InvokeControl<T>(T control, Action<T> action) where T : Control
  16. {
  17. if (control.InvokeRequired) {
  18. control.Invoke(new Action<T, Action<T>>(InvokeControl), new object[] {
  19. control,
  20. action
  21. });
  22.  
  23. } else {
  24. action(control);
  25.  
  26. }
  27.  
  28. }
  29.  
  30. // Begin Invoke Control
  31. // ( By Elektro )
  32. //
  33. // Usage Examples :
  34. // BeginInvokeControl(TextBox1, Sub(x As TextBox) x.AppendText("Hello"))
  35. // BeginInvokeControl(CheckBox1, Sub(x As CheckBox) x.Checked = True)
  36.  
  37. /// <summary>
  38. /// Invokes an asynchronous <see cref="T:Action"/> delegate on the specified control.
  39. /// This method avoids cross-threading exceptions.
  40. /// </summary>
  41. /// <typeparam name="T"></typeparam>
  42. /// <param name="control">The control to invoke.</param>
  43. /// <param name="action">The encapsulated method.</param>
  44. public void BeginInvokeControl<T>(T control, Action<T> action) where T : Control
  45. {
  46. if (control.InvokeRequired) {
  47. control.BeginInvoke(new Action<T, Action<T>>(BeginInvokeControl), new object[] {
  48. control,
  49. action
  50. });
  51.  
  52. } else {
  53. action(control);
  54.  
  55. }
  56.  
  57. }
  58.  
  59. //=======================================================
  60. //Service provided by Telerik (www.telerik.com)
  61. //=======================================================


⇲ 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!


Título: Re: Problemas al dividir proyecto en archivos C#
Publicado por: Kaxperday en 6 Diciembre 2014, 18:32 pm
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
  1. namespace proyectoname
  2. {
  3.    class Descargas
  4.    {
  5.        private void descargaForos()
  6.        {
  7.            tboxForos.Text = "";
  8.            pbarForos.Value = pbarForos.Minimum;
  9.            detenerForos = false;
  10. ...

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.


Título: Re: Problemas al dividir proyecto en archivos C#
Publicado por: El Benjo en 6 Diciembre 2014, 20:42 pm
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)


Título: Re: Problemas al dividir proyecto en archivos C#
Publicado por: Kaxperday en 7 Diciembre 2014, 16:06 pm
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.


Título: Re: Problemas al dividir proyecto en archivos C#
Publicado por: Eleкtro en 7 Diciembre 2014, 17:46 pm
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.

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!


Título: Re: Problemas al dividir proyecto en archivos C#
Publicado por: Kaxperday en 7 Diciembre 2014, 18:50 pm
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).