Je suis en train de jouer avec le (MVVM) Model View Voir le modèle motif de motif mais j'ai rencontré un problème avec le motif. Dans mon scénario, j'utilise un DataTable comme Voir le modèle. Ce modèle de vue est défini en tant que DataSource d'un DataGridView. Normalement, lorsque le Présentateur ajoute une nouvelle ligne au Modèle de Vue, une nouvelle ligne est ajoutée au DataGridView. Toutefois, si le Présentateur met à jour le Modèle de Vue depuis un thread autre que le thread d'affichage, il ne met pas correctement à jour DataGridView. Il existe plusieurs solutions de contournement, en fait j'en ai un couple dans mon exemple, mais ils semblent apporter trop de connaissances inférées sur l'interface utilisateur à la couche Presenter. Je n'ai pas besoin de savoir pourquoi cela se produit, je cherche plutôt des retours sur une approche de meilleure pratique pour traiter ce problème.(MVVM) Voir le modèle Voir le modèle et le filetage
Merci,
// Implements View
namespace WinApp
{
using System.Data;
using System.Windows.Forms;
using MVVC;
class View : Form, IView
{
[System.STAThread]
static void Main()
{
Application.Run(new View());
}
private Presenter _presenter;
private int _topOffset;
public View()
{
_presenter = new Presenter(this);
AddDataGridView();
AddButton(OperationTypes.PreferredApproach);
AddButton(OperationTypes.ControlInvoke);
AddButton(OperationTypes.SynchronizationContextSend);
}
void AddDataGridView()
{
DataGridView c = new DataGridView() { Top = _topOffset, Width = this.Width - 10, Height = 150 };
c.DataSource = this.ViewModel;
_topOffset += c.Height + 5;
this.Controls.Add(c);
}
void AddButton(OperationTypes operationTypes)
{
Button c = new Button() { Text = operationTypes.ToString(), Top = _topOffset, Width = this.Width - 10 };
c.Click += delegate
{
this.ViewModel.Clear();
_presenter.LoadProgressBars(operationTypes);
};
_topOffset += c.Height + 5;
this.Controls.Add(c);
}
#region IView Members
public void Send(SendCallback sendCallback)
{
// If calling thread is not the display thread then we must use the invoke method.
if (InvokeRequired)
{
Invoke(new MethodInvoker(delegate
{
sendCallback();
}));
}
else
{
sendCallback();
}
}
public DataTable ViewModel { get; set; }
#endregion
}
}
// Doesn't have a notion of UI implementation (System.Windows.Forms)
namespace MVVC
{
using System.Collections;
using System.Data;
using System.Threading;
public delegate void SendCallback();
public interface IView
{
DataTable ViewModel { get; set; }
void Send(SendCallback sendCallback);
}
public enum OperationTypes
{
PreferredApproach,
ControlInvoke,
SynchronizationContextSend
}
public class Presenter
{
private IView _view;
private Thread _thread;
public Presenter(IView view)
{
_view = view;
_view.ViewModel = new DataTable("TridTable");
_view.ViewModel.Columns.Add("Column1", typeof(int));
}
public void LoadProgressBars(OperationTypes operationType)
{
SynchronizationContext context = SynchronizationContext.Current;
if (_thread != null)
{
_thread.Abort();
}
_thread = new Thread(delegate()
{
string[] batch = new string[10];
for (int i = 0; i < batch.Length; i++)
{
// Emulate long running process. (e.g. scanning large file, creating images, figuring out the meaning of life ...)
Thread.Sleep(500);
switch (operationType)
{
case OperationTypes.PreferredApproach:
// Doesn't Work
// Different thread so the bindings won't get notified.
_view.ViewModel.Rows.Add(i);
break;
case OperationTypes.ControlInvoke:
// Does Work
// Send back to view to delegate work
_view.Send(delegate
{
_view.ViewModel.Rows.Add(i);
});
break;
case OperationTypes.SynchronizationContextSend:
// Does Work
// Dispatch a synchronous message to the Synchronization Context of the display thread
context.Send(delegate
{
_view.ViewModel.Rows.Add(i);
}, null);
break;
}
}
});
_thread.Start();
}
}
}