मैं स्क्रैच से WinForms एप्लिकेशन को फिर से लिखने की प्रक्रिया में हूं (और यह में है WinForms होने के लिए, जितना मैं WPF और MVVM का उपयोग करना चाहता हूं)। ऐसा करने के लिए मैंने एमवीसी पैटर्न का उपयोग करने और निर्भरता इंजेक्शन (डीआई) का उपयोग करने का प्रयास किया है जहां टेस्टेबिलिटी, रखरखाव इत्यादि को बढ़ाने के लिए संभव होनिर्भरता इंजेक्शन के साथ WinForms एमवीसी
मेरी समस्या एमवीसी और डीआई के उपयोग के साथ है। बैसिक एमवीसी पैटर्न के साथ, नियंत्रक के पास दृश्य तक पहुंच होनी चाहिए और दृश्य में नियंत्रक तक पहुंच होनी चाहिए (WinForms उदाहरण के लिए here देखें); यह सीटीओआर इंजेक्शन का उपयोग करते समय एक परिपत्र संदर्भ की ओर जाता है और यह मेरे प्रश्न का क्रूक्स है। सबसे पहले मेरी कोड पर विचार करें
Program.cs (मुख्य प्रवेश WinForms आवेदन के बिंदु):
static class Program
{
[STAThread]
static void Main()
{
FileLogHandler fileLogHandler = new FileLogHandler(Utils.GetLogFilePath());
Log.LogHandler = fileLogHandler;
Log.Trace("Program.Main(): Logging initialized");
CompositionRoot.Initialize(new DependencyModule());
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(CompositionRoot.Resolve<ApplicationShellView>());
}
}
DependencyModule.cs
public class DependencyModule : NinjectModule
{
public override void Load()
{
Bind<IApplicationShellView>().To<ApplicationShellView>();
Bind<IDocumentController>().To<SpreadsheetController>();
Bind<ISpreadsheetView>().To<SpreadsheetView>();
}
}
CompositionRoot.cs
public class CompositionRoot
{
private static IKernel ninjectKernel;
public static void Initialize(INinjectModule module)
{
ninjectKernel = new StandardKernel(module);
}
public static T Resolve<T>()
{
return ninjectKernel.Get<T>();
}
public static IEnumerable<T> ResolveAll<T>()
{
return ninjectKernel.GetAll<T>();
}
}
ApplicationShellView.cs (आवेदन का मुख्य रूप)
public partial class ApplicationShellView : C1RibbonForm, IApplicationShellView
{
private ApplicationShellController controller;
public ApplicationShellView()
{
this.controller = new ApplicationShellController(this);
InitializeComponent();
InitializeView();
}
public void InitializeView()
{
dockPanel.Extender.FloatWindowFactory = new CustomFloatWindowFactory();
dockPanel.Theme = vS2012LightTheme;
}
private void ribbonButtonTest_Click(object sender, EventArgs e)
{
controller.OpenNewSpreadsheet();
}
public DockPanel DockPanel
{
get { return dockPanel; }
}
}
कहाँ:
public interface IApplicationShellView
{
void InitializeView();
DockPanel DockPanel { get; }
}
ApplicationShellController.cs
public class ApplicationShellController
{
private IApplicationShellView shellView;
[Inject]
public ApplicationShellController(IApplicationShellView view)
{
this.shellView = view;
}
public void OpenNewSpreadsheet(DockState dockState = DockState.Document)
{
SpreadsheetController controller = (SpreadsheetController)GetDocumentController("new.xlsx");
SpreadsheetView view = (SpreadsheetView)controller.New("new.xlsx");
view.Show(shellView.DockPanel, dockState);
}
private IDocumentController GetDocumentController(string path)
{
return return CompositionRoot.ResolveAll<IDocumentController>()
.SingleOrDefault(provider => provider.Handles(path));
}
public IApplicationShellView ShellView { get { return shellView; } }
}
SpreadsheetContro ller.cs
public class SpreadsheetController : IDocumentController
{
private ISpreadsheetView view;
public SpreadsheetController(ISpreadsheetView view)
{
this.view = view;
this.view.SetController(this);
}
public bool Handles(string path)
{
string extension = Path.GetExtension(path);
if (!String.IsNullOrEmpty(extension))
{
if (FileTypes.Any(ft => ft.FileExtension.CompareNoCase(extension)))
return true;
}
return false;
}
public void SetViewActive(bool isActive)
{
((SpreadsheetView)view).ShowIcon = isActive;
}
public IDocumentView New(string fileName)
{
// Opens a new file correctly.
}
public IDocumentView Open(string path)
{
// Opens an Excel file correctly.
}
public IEnumerable<DocumentFileType> FileTypes
{
get
{
return new List<DocumentFileType>()
{
new DocumentFileType("CSV", ".csv"),
new DocumentFileType("Excel", ".xls"),
new DocumentFileType("Excel10", ".xlsx")
};
}
}
}
कहाँ कार्यान्वित इंटरफेस है:
public interface IDocumentController
{
bool Handles(string path);
void SetViewActive(bool isActive);
IDocumentView New(string fileName);
IDocumentView Open(string path);
IEnumerable<DocumentFileType> FileTypes { get; }
}
अब दृश्य इस नियंत्रक के साथ ascociated है:
public partial class SpreadsheetView : DockContent, ISpreadsheetView
{
private IDocumentController controller;
public SpreadsheetView()
{
InitializeComponent();
}
private void SpreadsheetView_Activated(object sender, EventArgs e)
{
controller.SetViewActive(true);
}
private void SpreadsheetView_Deactivate(object sender, EventArgs e)
{
controller.SetViewActive(false);
}
public void SetController(IDocumentController controller)
{
this.controller = controller;
Log.Trace("SpreadsheetView.SetController(): Controller set successfully");
}
public string DisplayName
{
get { return Text; }
set { Text = value; }
}
public WorkbookView WorkbookView
{
get { return workbookView; }
set { workbookView = value; }
}
public bool StatusBarVisible
{
get { return statusStrip.Visible; }
set { statusStrip.Visible = value; }
}
public string StatusMessage
{
get { return statusLabelMessage.Text; }
set { statusLabelMessage.Text = value; }
}
}
दृश्य इंटरफेस हैं:
public interface ISpreadsheetView : IDocumentView
{
WorkbookView WorkbookView { get; set; }
}
और:
public interface IDocumentView
{
void SetController(IDocumentController controller);
string DisplayName { get; set; }
bool StatusBarVisible { get; set; }
}
मैं डि और Ninject के लिए नया हूँ तो मैं दो प्रश्न हैं:
- मैं अपने आप को
SpreadsheetController
मेंthis.view.SetController(this);
का उपयोग कर रोका जा सकता है कैसे, यहाँ यह लगता है जैसे मैं आईओसी का उपयोग करना चाहिए कंटेनर, लेकिन शुद्ध सीटीआर-इंजेक्शन का उपयोग सर्कुलर संदर्भ औरStackOverflowException
की ओर जाता है। क्या यह शुद्ध डीआई का उपयोग करके किया जा सकता है?
क्योंकि मेरे पास WPF (या एएसपी के साथ बाध्यकारी ढांचा नहीं है।एनईटी दृश्य और नियंत्रक को पूरी तरह से जोड़ने की क्षमता), मुझे दृश्य और नियंत्रक को एक दूसरे को स्पष्ट रूप से बेनकाब करना होगा। यह सही "महसूस" नहीं करता है और मुझे लगता है कि यह निनजेक आईओसी कंटेनर के साथ संभव होना चाहिए, लेकिन मेरे पास यह स्थापित करने का अनुभव नहीं है कि यह कैसे किया जा सकता है (यदि यह कर सकता है)।
- क्या मेरा निंजा/डी का उपयोग यहां सही है। जिस तरह से मैं अपने
CompositionRoot
का उपयोग कर रहा हूं और विधिGetDocumentController(string path)
सेवा लोकेटर एंटी-पैटर्न की तरह लगता है, मैं यह अधिकार कैसे बना सकता हूं?
इस समय यह कोड ठीक काम करता है, लेकिन मैं इसे सही प्राप्त करना चाहता हूं। आपके समय के लिए अत्यधिक धन्यवाद।
मैंने देखा कि आपने पहले कहा था कि आप हमें एमवीवीएम और डब्ल्यूपीएफ पसंद करेंगे। खैर मैं WinForms के साथ WVVM का उपयोग करके थोड़ी देर के लिए रहा हूं और इसे एमवीसी या एमवीपी की तुलना में अधिक कुशल माना जाता है। WinForms बाइंडिंग WPF में उतनी उन्नत नहीं हैं, लेकिन मुझे लगता है कि ज्यादातर मामलों में काम काफी अच्छी तरह से पर्याप्त है। पूरी बात के साथ मेरी सहायता करने के लिए मैं WinForms के लिए DevExpress MVVM का उपयोग कर रहा हूं: https://documentation.devexpress.com/#WindowsForms/CustomDocument113955 –