ডাব্লুপিএফ / এমভিভিএম অ্যাপ্লিকেশনে নির্ভরতা ইনজেকশন কীভাবে পরিচালনা করবেন


107

আমি একটি নতুন ডেস্কটপ অ্যাপ্লিকেশন শুরু করছি এবং আমি এটি এমভিভিএম এবং ডাব্লুপিএফ ব্যবহার করে তৈরি করতে চাই।

আমিও টিডিডি ব্যবহারের পরিকল্পনা করছি।

সমস্যাটি হ'ল আমি জানি না যে আমার প্রোডাকশন কোডে আমার নির্ভরতা ইনজেকশনের জন্য কীভাবে আইওসি পাত্রে ব্যবহার করা উচিত।

ধরুন আমার কাছে ফলোয়িং ক্লাস এবং ইন্টারফেস রয়েছে:

public interface IStorage
{
    bool SaveFile(string content);
}

public class Storage : IStorage
{
    public bool SaveFile(string content){
        // Saves the file using StreamWriter
    }
}

এবং তারপরে আমার আরও একটি ক্লাস রয়েছে যার IStorageনির্ভরতা হিসাবে রয়েছে , মনে করুন যে এই শ্রেণিটি ভিউমোডেল বা ব্যবসায়িক শ্রেণি ...

public class SomeViewModel
{
    private IStorage _storage;

    public SomeViewModel(IStorage storage){
        _storage = storage;
    }
}

এর সাহায্যে আমি সহজেই ইউনিট পরীক্ষাগুলি লিখতে পারি তা নিশ্চিত করার জন্য যে তারা ঠিকঠাকভাবে কাজ করছে, মোক এবং ইত্যাদি ব্যবহার করছে that

সমস্যাটি যখন এটি আসল অ্যাপ্লিকেশনটিতে ব্যবহার করতে আসে। আমি জানি যে আমার অবশ্যই একটি আইওসি পাত্রে থাকতে হবে যা IStorageইন্টারফেসের জন্য একটি ডিফল্ট বাস্তবায়নকে সংযুক্ত করে , তবে আমি কীভাবে এটি করব?

উদাহরণস্বরূপ, আমার যদি নিম্নলিখিত xaml থাকে তবে এটি কেমন হবে:

<Window 
    ... xmlns definitions ...
>
   <Window.DataContext>
        <local:SomeViewModel />
   </Window.DataContext>
</Window>

আমি কীভাবে ডাব্লুপিএফকে সেই ক্ষেত্রে নির্ভরতা ইনজেক্ট করতে সঠিকভাবে বলতে পারি?

এছাড়াও, ধরুন SomeViewModelআমার সি # কোড থেকে আমার একটি উদাহরণ প্রয়োজন , আমি এটি কীভাবে করব?

আমি মনে করি এটিতে আমি পুরোপুরি হারিয়ে গেছি, এটিকে পরিচালনা করার সর্বোত্তম উপায় কীভাবে তার কোনও উদাহরণ বা দিকনির্দেশনা আমি উপলব্ধি করব।

আমি স্ট্রাকচারম্যাপের সাথে পরিচিত, তবে আমি কোনও বিশেষজ্ঞ নই। এছাড়াও, যদি বাক্সের চেয়ে ভাল / সহজ / বাইরে ফ্রেমওয়ার্ক থাকে তবে দয়া করে আমাকে জানান।


4
প্রাক নেট। 3.0 এর পূর্বরূপে আপনি কিছু মাইক্রোসফ্ট নুগেট প্যাকেজগুলির সাহায্যে এটি করতে পারেন।
বেলি মিলার

উত্তর:


91

আমি নিনজেক্ট ব্যবহার করছি এবং খুঁজে পেয়েছি যে এটির সাথে কাজ করে আনন্দিত। সবকিছু কোডে সেট আপ করা হয়েছে, বাক্য গঠনটি বেশ সহজবোধ্য এবং এটিতে একটি ভাল ডকুমেন্টেশন রয়েছে (এবং এসও তে প্রচুর উত্তর)।

সুতরাং মূলত এটি এর মত যায়:

ভিউ মডেল তৈরি করুন, এবং IStorageকনস্ট্রাক্টর প্যারামিটার হিসাবে ইন্টারফেসটি নিন :

class UserControlViewModel
{
    public UserControlViewModel(IStorage storage)
    {

    }
}

ViewModelLocatorভিউ মডেলের জন্য একটি গেট প্রপার্টি সহ একটি তৈরি করুন , যা নিনজেক্ট থেকে ভিউ মডেলটি লোড করে:

class ViewModelLocator
{
    public UserControlViewModel UserControlViewModel
    {
        get { return IocKernel.Get<UserControlViewModel>();} // Loading UserControlViewModel will automatically load the binding for IStorage
    }
}

করুন ViewModelLocatorApp.xaml মধ্যে একটি অ্যাপ্লিকেশন ব্যাপক সম্পদ:

<Application ...>
    <Application.Resources>
        <local:ViewModelLocator x:Key="ViewModelLocator"/>
    </Application.Resources>
</Application>

বাঁধুন DataContextএর UserControlViewModelLocator সংশ্লিষ্ট সম্পত্তিতে।

<UserControl ...
             DataContext="{Binding UserControlViewModel, Source={StaticResource ViewModelLocator}}">
    <Grid>
    </Grid>
</UserControl>

নিনজেক্টমোডিয়ুল উত্তরাধিকারসূত্রে একটি বর্গ তৈরি করুন, যা প্রয়োজনীয় বাইন্ডিংগুলি ( IStorageএবং ভিউ মডেল) সেটআপ করবে :

class IocConfiguration : NinjectModule
{
    public override void Load()
    {
        Bind<IStorage>().To<Storage>().InSingletonScope(); // Reuse same storage every time

        Bind<UserControlViewModel>().ToSelf().InTransientScope(); // Create new instance every time
    }
}

প্রয়োজনীয় নিনজেক্ট মডিউলগুলি (আপাতত উপরে একটি) সাথে অ্যাপ্লিকেশন প্রারম্ভকালে আইওসি কার্নেলটি শুরু করুন:

public partial class App : Application
{       
    protected override void OnStartup(StartupEventArgs e)
    {
        IocKernel.Initialize(new IocConfiguration());

        base.OnStartup(e);
    }
}

IocKernelআইওসি কার্নেলের অ্যাপ্লিকেশন প্রশস্ত উদাহরণ ধরে রাখতে আমি একটি স্ট্যাটিক ক্লাস ব্যবহার করেছি , সুতরাং যখন প্রয়োজন হয় তখন আমি সহজেই এটি অ্যাক্সেস করতে পারি:

public static class IocKernel
{
    private static StandardKernel _kernel;

    public static T Get<T>()
    {
        return _kernel.Get<T>();
    }

    public static void Initialize(params INinjectModule[] modules)
    {
        if (_kernel == null)
        {
            _kernel = new StandardKernel(modules);
        }
    }
}

এই সমাধানটি একটি স্ট্যাটিক ServiceLocator(দ্য IocKernel) ব্যবহার করে, যা সাধারণত একটি বিরোধী-নিদর্শন হিসাবে বিবেচিত হয়, কারণ এটি শ্রেণীর নির্ভরতা লুকিয়ে রাখে। তবে ইউআই ক্লাসগুলির জন্য কিছু ধরণের ম্যানুয়াল পরিষেবা সন্ধান করা এড়ানো খুব কঠিন, কারণ তাদের অবশ্যই প্যারামিটারলেস কনস্ট্রাক্টর থাকতে হবে এবং আপনি যে কোনও উপায়ে ইনস্ট্যান্টেশন নিয়ন্ত্রণ করতে পারবেন না, তাই আপনি ভিএম ইনজেক্ট করতে পারবেন না। কমপক্ষে এই উপায়ে আপনাকে ভিএমকে বিচ্ছিন্নতার সাথে পরীক্ষা করতে দেয়, যেখানে সমস্ত ব্যবসায়ের যুক্তি রয়েছে।

কারও যদি আরও ভাল উপায় থাকে তবে দয়া করে শেয়ার করুন।

সম্পাদনা: ভাগ্যবান লাইকি, নিনেক্ট ইনস্ট্যানিয়েট ইউআই ক্লাসগুলি দিয়ে স্ট্যাটিক সার্ভিস লোকেটার থেকে মুক্তি পাওয়ার জন্য একটি উত্তর সরবরাহ করেছিল। উত্তরের বিশদটি এখানে দেখা যাবে


14
আমি নির্ভরতা ইনজেকশনে নতুন, তবুও এর অন্তরে আপনার সমাধানটি সার্ভিস লোকেটারকে অ্যান্টি-প্যাটার্নটি নিনজেক্টের সাথে একত্রিত করছে যেহেতু আপনি স্থির ভিউমোডেল লোকেটার ব্যবহার করছেন। এক্সামিল ফাইলটিতে একটি তর্ক করতে পারে ইনজেকশনটি করা হয়েছিল, এটির পরীক্ষার সম্ভাবনা কম। আমার আরও ভাল সমাধান নেই এবং সম্ভবত আপনার ব্যবহার করব - তবুও আমি মনে করি এটি উত্তরেও উল্লেখ করা সহায়ক হবে।
ব্যবহারকারী3141326

4
ম্যান আপনার সমাধান, শুধু মহান সেখানে নিম্নলিখিত লাইন সাথে আছেন কেবলমাত্র একটি "সমস্যা": DataContext="{Binding [...]}"। এর ফলে ভিএস-ডিজাইনার ভিউমোডেলের কনস্ট্রাক্টরে সমস্ত প্রোগ্রাম-কোড কার্যকর করতে পারে। আমার ক্ষেত্রে উইন্ডো কার্যকর করা হয়েছে এবং VS এর সাথে কোনওরকম মিথস্ক্রিয়াটিকে অবরুদ্ধ করে mod ডিজাইন-টাইমে "রিয়েল" ভিউমোডেলগুলি সনাক্ত না করার জন্য সম্ভবত কোনও ব্যক্তির ভিউমোডেল লোকেশনটি সংশোধন করা উচিত। - আরেকটি সমাধান হ'ল "প্রকল্প কোডটি অক্ষম করুন", যা মৌমাছি দেখানো থেকে সমস্ত কিছু রোধ করবে। হতে পারে আপনি ইতিমধ্যে এটির একটি ঝরঝরে সমাধান খুঁজে পেয়েছেন। এক্ষেত্রে আমি আপনাকে এটি প্রদর্শন করতে দয়া করে করব।
ভাগ্যবানলিকে

4
@ লাকিলিকি আপনি ডি ব্যবহার করার চেষ্টা করতে পারেন: ডেটা কনটেক্সট = "{ডি: ডিজাইনআইনস্ট্যান্স ভিএম: ইউজারকন্ট্রোলভিউমোডেল, আইসডিজাইনটাইমক্রিটেবল = ট্রু}" তবে আমি নিশ্চিত নই যে এটি কোনও পার্থক্য করেছে। তবে কেন / কীভাবে ভিএম কনস্ট্রাক্টর একটি মডেল উইন্ডো চালু করছেন? আর কী রকম উইন্ডো?
সোনারগার্ড

4
@ সাসান আসলে আমি জানি না কেন এবং কীভাবে, তবে আমি যখন সলিউশন এক্সপ্লোরার থেকে একটি উইন্ডো ডিজাইনার খুলি, যখন নতুন ট্যাবটি খোলা হচ্ছে, উইন্ডোটি ডিজাইনার দ্বারা প্রদর্শিত হবে এবং একই উইন্ডোটি প্রদর্শিত হবে যেন ডিবাগিং মডেল, ভিএস "মাইক্রোসফ্ট ভিজ্যুয়াল স্টুডিও এক্সএএমএল ডিজাইনার" এর বাইরে একটি নতুন প্রক্রিয়াতে হোস্ট করা। যদি প্রক্রিয়াটি বন্ধ হয়ে যায় তবে ভিএস-ডিজাইনার পূর্ববর্তী উল্লিখিত ব্যতিক্রমের সাথেও ব্যর্থ হন। আমি আপনার কাজের চেষ্টা করতে যাচ্ছি। আমি নতুন তথ্য শনাক্ত করার সাথে সাথে আমি আপনাকে অবহিত করব :)
লাকীলাইকী

4
@ সোনারগার্ড আমি সার্ভিস লোকেটার অ্যান্টি-প্যাটার্ন এড়িয়ে আপনার উত্তরে একটি উন্নতি পোস্ট করেছি। এটি পরীক্ষা করে নির্দ্বিধায়।
ভাগ্যবানলাইকি

55

আপনার প্রশ্নে আপনি DataContextএক্সএএমএল-তে ভিউয়ের সম্পত্তির মান নির্ধারণ করেছেন । এটির জন্য আপনার ভিউ-মডেলের ডিফল্ট নির্মাতা থাকতে হবে। তবে, যেমন আপনি উল্লেখ করেছেন, এটি নির্ভরতা ইনজেকশনের সাথে ভাল কাজ করে না যেখানে আপনি কনস্ট্রাক্টরের উপর নির্ভরতা ইনজেকশন করতে চান।

সুতরাং আপনি DataContextXAML এ সম্পত্তি সেট করতে পারবেন না । পরিবর্তে আপনার কাছে অন্যান্য বিকল্প রয়েছে।

যদি আপনি অ্যাপ্লিকেশনটি কোনও সাধারণ শ্রেণিবদ্ধ ভিউ-মডেলের উপর ভিত্তি করে থাকেন তবে অ্যাপ্লিকেশন শুরু হওয়ার পরে আপনি পুরো ভিউ-মডেল শ্রেণিবিন্যাসটি তৈরি করতে পারেন (আপনাকে ফাইলটি StartupUriথেকে সম্পত্তি সরিয়ে ফেলতে App.xamlহবে):

public partial class App {

  protected override void OnStartup(StartupEventArgs e) {
    base.OnStartup(e);
    var container = CreateContainer();
    var viewModel = container.Resolve<RootViewModel>();
    var window = new MainWindow { DataContext = viewModel };
    window.Show();
  }

}

এটি মূল-ভিত্তিক ভিউ-মডেলগুলির একটি অবজেক্ট গ্রাফের চারপাশে ভিত্তি করে তৈরি করা হয়েছে RootViewModelতবে আপনি কিছু ভিউ-মডেল ফ্যাক্টরিগুলিকে অভিভাবক-ভিউ-মডেলগুলিতে ইনজেক্ট করতে পারেন যাতে তাদেরকে নতুন চাইল্ড ভিউ-মডেল তৈরি করতে দেয় যাতে অবজেক্টের গ্রাফটি ঠিক করতে হবে না। এটি আশাবাদী আপনার প্রশ্নেরও উত্তর দেয় মনে করুন যে SomeViewModelআমার csকোড থেকে আমার একটি উদাহরণ প্রয়োজন , আমি এটি কীভাবে করব?

class ParentViewModel {

  public ParentViewModel(ChildViewModelFactory childViewModelFactory) {
    _childViewModelFactory = childViewModelFactory;
  }

  public void AddChild() {
    Children.Add(_childViewModelFactory.Create());
  }

  ObservableCollection<ChildViewModel> Children { get; private set; }

 }

class ChildViewModelFactory {

  public ChildViewModelFactory(/* ChildViewModel dependencies */) {
    // Store dependencies.
  }

  public ChildViewModel Create() {
    return new ChildViewModel(/* Use stored dependencies */);
  }

}

যদি আপনার অ্যাপ্লিকেশনটি প্রকৃতির ক্ষেত্রে আরও গতিশীল হয় এবং সম্ভবত নেভিগেশনের চারপাশে ভিত্তি করে আপনাকে নেভিগেশন সম্পাদন করে এমন কোডটি প্রবেশ করতে হবে। প্রতিবার নতুন ভিউতে নেভিগেট করার সময় আপনাকে ভিউ-মডেল তৈরি করতে হবে (ডিআই কন্টেইনার থেকে), নিজেই DataContextভিউ এবং ভিউ-মডেলটিতে দৃশ্যের সেট সেট করে । আপনি এই ভিউটি প্রথমে করতে পারেন যেখানে আপনি একটি ভিউর ভিত্তিতে একটি ভিউ-মডেল বেছে নেন বা আপনি প্রথমে ভিউ-মডেলটি করতে পারেনযেখানে ভিউ-মডেল কোন ভিউটি ব্যবহার করবেন তা নির্ধারণ করে। একটি এমভিভিএম ফ্রেমওয়ার্ক আপনার ডিআই কনটেইনারকে ভিউ-মডেলগুলি তৈরি করার জন্য কোনও উপায় সহ এই মূল কার্যকারিতা সরবরাহ করে তবে আপনি নিজে এটি প্রয়োগ করতেও পারেন। আমি এখানে কিছুটা অস্পষ্ট কারণ আপনার প্রয়োজনের উপর নির্ভর করে এই কার্যকারিতাটি বেশ জটিল হয়ে উঠতে পারে। এটি আপনি একটি এমভিভিএম কাঠামো থেকে প্রাপ্ত মূল ফাংশনগুলির মধ্যে একটি তবে একটি সাধারণ অ্যাপ্লিকেশনটিতে আপনার নিজের ঘূর্ণায়মান আপনাকে এমভিভিএম ফ্রেমওয়ার্কগুলি হুডের নীচে কী সরবরাহ করে তা আপনাকে একটি ভাল বোঝার সুযোগ দেবে।

DataContextএক্সএএমএএমএল-এ ঘোষণা করতে সক্ষম না হয়ে আপনি কিছু ডিজাইন-সময় সমর্থন হারাবেন। যদি আপনার ভিউ-মডেলটিতে কিছু ডেটা থাকে তবে এটি ডিজাইনের সময় উপস্থিত হবে যা খুব দরকারী। ভাগ্যক্রমে, আপনি ডাব্লুপিএফ -এ ডিজাইন-সময় বৈশিষ্ট্যও ব্যবহার করতে পারেন । এটি করার একটি উপায় হ'ল <Window>উপাদান বা <UserControl>এক্সএএমএলএলে নিম্নলিখিত বৈশিষ্ট্যগুলি যুক্ত করা :

xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=local:MyViewModel, IsDesignTimeCreatable=True}"

ভিউ-মডেল ধরণের দুটি কনস্ট্রাক্টর থাকতে হবে, ডিজাইন-সময় ডেটার জন্য ডিফল্ট এবং নির্ভরতা ইঞ্জেকশনের জন্য আরেকটি:

class MyViewModel : INotifyPropertyChanged {

  public MyViewModel() {
    // Create some design-time data.
  }

  public MyViewModel(/* Dependencies */) {
    // Store dependencies.
  }

}

এটি করে আপনি নির্ভরতা ইনজেকশন ব্যবহার করতে পারেন এবং ভাল ডিজাইন-সময় সমর্থন ধরে রাখতে পারেন।


15
এটি ঠিক আমি যা খুঁজছিলাম is "আমাকে [ ইয়াদে-ই ] কাঠামোটি কেবল ব্যবহার করুন" বলে এমন উত্তরগুলি আমি কতবার পড়ি তা হতাশ করে । এগুলি সব ভাল এবং ভাল, তবে আমি প্রথমে নিজেকে কীভাবে রোল করব ঠিক তা জানতে চাই এবং তারপরে আমি জানতে পারি যে আসলে কী ধরণের কাঠামো আমার পক্ষে কার্যকর হতে পারে। এটিকে স্পষ্ট করে বানান করার জন্য ধন্যবাদ।
কিমিওট

31

আমি এখানে যা পোস্ট করছি তা সন্ডারগার্ডের উত্তরের একটি উন্নতি, কারণ আমি যা বলতে যাচ্ছি তা কোনও মন্তব্যের সাথে খাপ খায় না :)

প্রকৃতপক্ষে আমি একটি ঝরঝরে সমাধান প্রবর্তন করছি, যা সার্ভিসলোকেটার এবং StandardKernel-Instance এর জন্য একটি মোড়কের প্রয়োজনকে এড়িয়ে চলে , যাকে সন্ডারগার্ডের সলিউশন বলা হয় IocContainer। কেন? উল্লিখিত হিসাবে, এগুলি নিদর্শন বিরোধী।

মেকিং StandardKernelসর্বত্র উপলব্ধ

নিনেক্টের ম্যাজিকের মূলটি হ'ল StandardKernel-ইথেন্স যা -Modod ব্যবহার করা প্রয়োজন .Get<T>()

বিকল্পভাবে সন্ডারগার্ডের জন্য IocContainerআপনি -ক্লাসের StandardKernelঅভ্যন্তরটি তৈরি করতে পারেন App

আপনার App.xaml থেকে কেবল স্টার্টআপিকে সরান

<Application x:Class="Namespace.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
             ... 
</Application>

এটি App.xaml.cs এর ভিতরে অ্যাপের কোডবিহাইন্ড

public partial class App
{
    private IKernel _iocKernel;

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        _iocKernel = new StandardKernel();
        _iocKernel.Load(new YourModule());

        Current.MainWindow = _iocKernel.Get<MainWindow>();
        Current.MainWindow.Show();
    }
}

এখন থেকে, নিনজেক্ট জীবিত এবং লড়াইয়ের জন্য প্রস্তুত :)

আপনার ইনজেকশন DataContext

নিনজেক্ট জীবিত থাকাকালীন, আপনি সমস্ত ধরণের ইনজেকশনগুলি ব্যবহার করতে পারেন, যেমন প্রপার্টি সেটার ইঞ্জেকশন বা সর্বাধিক সাধারণ একটি কনস্ট্রাক্টর ইঞ্জেকশন

এভাবেই আপনি আপনার মধ্যে আপনার ViewModel উদ্বুদ্ধ হয় WindowএরDataContext

public partial class MainWindow : Window
{
    public MainWindow(MainWindowViewModel vm)
    {
        DataContext = vm;
        InitializeComponent();
    }
}

আপনি IViewModelযদি সঠিক বাঁধাই করেন তবে অবশ্যই আপনি একটি ইনজেকশনও করতে পারেন , তবে এটি এই উত্তরের অংশ নয়।

সরাসরি কার্নেল অ্যাক্সেস করা হচ্ছে

আপনার যদি সরাসরি কার্নেলে .Get<T>()মেথডগুলি কল করতে চান (যেমন - মেথড ), আপনি কার্নেলটিকে নিজেই ইনজেক্ট করতে দিতে পারেন।

    private void DoStuffWithKernel(IKernel kernel)
    {
        kernel.Get<Something>();
        kernel.Whatever();
    }

কার্নেলের কোনও স্থানীয় উদাহরণ প্রয়োজন হলে আপনি এটি সম্পত্তি হিসাবে ইনজেকশন করতে পারেন।

    [Inject]
    public IKernel Kernel { private get; set; }

যদিও এটি বেশ কার্যকর হতে পারে তবে আমি আপনাকে এটি করার পরামর্শ দিচ্ছি না। কেবলমাত্র লক্ষ করুন যে এইভাবে অবজেক্টগুলি ইনজেকশন করা হয়েছে, এটি কনস্ট্রাক্টরের অভ্যন্তরে উপলব্ধ হবে না, কারণ এটি পরে ইনজেকশন দেওয়া হয়েছে।

এই লিঙ্ক অনুসারে আপনার IKernel(ডিআই কনটেইনার) ইনজেক্ট করার পরিবর্তে কারখানা-এক্সটেনশনটি ব্যবহার করা উচিত ।

একটি সফ্টওয়্যার সিস্টেমে একটি ডিআই কনটেইনার নিয়োগের জন্য প্রস্তাবিত পদ্ধতিটি হ'ল অ্যাপ্লিকেশনটির কম্পোজিশন রুটটি একক জায়গা যেখানে কনটেইনারটি সরাসরি স্পর্শ করা হয়।

নিনজেক্ট.এক্সটেনশনস.ফ্যাক্টরি কীভাবে ব্যবহার করতে হয় তাও এখানে লাল হতে পারে ।


চমৎকার পন্থা। নিিনজেক্টকে এই পর্যায়ে কখনও অন্বেষণ করা হয়নি, তবে আমি দেখতে পাচ্ছি যে আমি মিস করছি :)
সোনারগার্ড

যদি কেউ Ninject.Extensions.Factoryএটিতে কীভাবে ব্যবহার করতে আগ্রহী তবে তা এখানে মন্তব্যগুলিতে লিখুন এবং আমি আরও কিছু তথ্য যুক্ত করব।
লাকিলিকি

4
@ লাকিলিকি: এক্সএএমএল এর মাধ্যমে উইন্ডো ডেটাকন্টেক্সটে আমি কীভাবে একটি ভিউমোডেল যুক্ত করতে সক্ষম হবো যার কোনও প্যারামিটারলেস কনস্ট্রাক্টর নেই? সার্ভিসলোকেটারের সাথে স্যান্ডারগার্ড থেকে সমাধানের সাথে এই পরিস্থিতি সম্ভব হবে।
টমাস জিউলেন

সুতরাং দয়া করে আমাকে বলুন যে সংযুক্ত বৈশিষ্ট্যে আমার প্রয়োজনীয় পরিষেবাগুলি কীভাবে পুনরুদ্ধার করবেন? এগুলি সর্বদা স্থির থাকে, উভয়ই সমর্থন DependencyPropertyক্ষেত্র এবং এর গেট এবং সেট পদ্ধতি।
বসন্তের 76

@ বসন্ত 7676 একটি ইন্টারেস্টিং প্রশ্ন। আমি জানি, আমি একটু দেরি করেছি, তবে আপনি কী শেষ করেছেন? বেশিরভাগ অংশ হিসাবে, আমি কখনও আমার সংযুক্ত-বৈশিষ্ট্যগুলির মধ্যে ডিআই ব্যবহার করি না। সম্ভবত আপনি যেখানে সার্ভিসকোলেটর এড়াতে পারবেন না তা ঠিক আছে?
ভাগ্যিসুলভ

13

আমি একটি "প্রথম দেখুন" পদ্ধতির জন্য যাই, যেখানে আমি ভিউ-মডেলটি ভিউর কনস্ট্রাক্টরের কাছে (এর কোড-পিছনে) পাস করি, যা ডেটা প্রসঙ্গে নির্ধারিত হয়, যেমন

public class SomeView
{
    public SomeView(SomeViewModel viewModel)
    {
        InitializeComponent();

        DataContext = viewModel;
    }
}

এটি আপনার এক্সএএমএল-ভিত্তিক পদ্ধতির পরিবর্তে।

আমি নেভিগেশন হ্যান্ডেল করতে প্রিজম ফ্রেমওয়ার্কটি ব্যবহার করি - যখন কোনও কোড একটি নির্দিষ্ট দর্শন ("এটিকে" নেভিগেট করে "প্রদর্শিত করার জন্য) অনুরোধ করে তখন প্রিজম সেই দৃশ্যটি সমাধান করবে (অভ্যন্তরীণভাবে অ্যাপ্লিকেশনটির ডিআই ফ্রেমওয়ার্ক ব্যবহার করে); ডিআই কাঠামোটি ঘুরে দেখা যায় যে কোনও নির্ভরতা (আমার উদাহরণের দর্শন মডেল) এর সমাধান করবে, তারপরে তার নির্ভরতাগুলি সমাধান করবে এবং আরও অনেক কিছু।

ডিআই ফ্রেমওয়ার্কের পছন্দটি অনেকটা অপ্রাসঙ্গিক কারণ এগুলি মূলত একই জিনিস করে, যেমন আপনি কংক্রিটের ধরণের সাথে একটি ইন্টারফেস (বা কোনও প্রকার) নিবন্ধন করেন যা আপনি যখন ফ্রেমওয়ার্কটি সেই ইন্টারফেসের উপর নির্ভরতা খুঁজে পান তখন তা ইনস্ট্যান্ট করতে চান। রেকর্ডের জন্য আমি ক্যাসেল উইন্ডসর ব্যবহার করি।

প্রিজম নেভিগেশন কিছুটা অভ্যস্ত হয়ে ওঠে তবে আপনি যখন আপনার চারপাশে মাথা পান তবে এটি বেশ ভাল is যেমন আপনি আপনার মূল উইন্ডোতে একটি প্রিজম "অঞ্চল" তৈরি করতে পারেন, তারপরে প্রিজম নেভিগেশন ব্যবহার করে আপনি এই অঞ্চলের মধ্যে একটি ভিউ থেকে অন্য দৃশ্যে স্যুইচ করবেন, যেমন ব্যবহারকারী মেনু আইটেম বা যা কিছু নির্বাচন করেন lects

বিকল্পভাবে এমভিভিএম লাইটের মতো এমভিভিএম ফ্রেমওয়ার্কগুলির একটিতে একবার দেখুন। আমি এগুলির কোনও অভিজ্ঞতা পাইনি তাই তারা কী ব্যবহার করতে চাইছে তা নিয়ে মন্তব্য করতে পারে না।


4
কীভাবে আপনি শিশু দর্শনে কনস্ট্রাক্টর যুক্তিগুলি পাস করেন? আমি এই পদ্ধতির চেষ্টা করেছি, তবে পিতামাতার দৃশ্যে ব্যতিক্রম পেয়ে আমাকে বলছে যে সন্তানের দৃশ্যে কোনও ডিফল্ট প্যারামিটার-কম
ডক্টর জোনস

11

এমভিভিএম লাইট ইনস্টল করুন।

ইনস্টলেশন অংশটি একটি ভিউ মডেল লোকেটার তৈরি করা। এটি এমন একটি শ্রেণী যা আপনার ভিউমোডেলগুলিকে বৈশিষ্ট্য হিসাবে প্রকাশ করে। এরপরে এই বৈশিষ্ট্যগুলির প্রাপ্তকারী আপনার আইওসি ইঞ্জিন থেকে দৃষ্টান্তগুলি ফিরে আসতে পারে। সৌভাগ্যক্রমে, এমভিভিএম আলোতে সিম্পলআইওসি ফ্রেমওয়ার্কটিও অন্তর্ভুক্ত থাকে তবে আপনি যদি পছন্দ করেন তবে অন্যকেও তারে রাখতে পারেন।

সাধারণ আইওসি দিয়ে আপনি কোনও প্রকারের বিরুদ্ধে একটি বাস্তবায়ন নিবন্ধন করুন ...

SimpleIOC.Default.Register<MyViewModel>(()=> new MyViewModel(new ServiceProvider()), true);

এই উদাহরণে, আপনার ভিউ মডেলটি তার নির্মাণকারীর হিসাবে কোনও পরিষেবা সরবরাহকারী অবজেক্ট তৈরি এবং পাস করে।

তারপরে আপনি এমন একটি সম্পত্তি তৈরি করুন যা আইওসি থেকে একটি উদাহরণ দেয়।

public MyViewModel
{
    get { return SimpleIOC.Default.GetInstance<MyViewModel>; }
}

চতুর অংশটি হল ভিউ মডেল লোকেটারটি তখন অ্যাপ্লিকেশন: এক্সএএমএল বা ডেটা উত্স হিসাবে সমতুল্য তৈরি করা হয়।

<local:ViewModelLocator x:key="Vml" />

ইনজেকশন পরিষেবা সহ আপনার ভিউ মডেলটি পেতে আপনি এখন এটির 'মাইভিউমোডেল' সম্পত্তিটিতে আবদ্ধ করতে পারেন।

আশা করি এইটি কাজ করবে. কোনও আইপ্যাডে মেমরি থেকে কোডেড কোনও কোডের ভুলের জন্য ক্ষমা চাই।


অ্যাপ্লিকেশনটির বুটস্ট্র্যাপের বাইরে GetInstanceবা আপনার থাকা উচিত নয় resolve। এটাই তো ডিআই এর পয়েন্ট!
সোলেইল - ম্যাথিউ প্রভোট

আমি সম্মত হই যে আপনি প্রারম্ভকালীন সময়ে সম্পত্তিটির মান নির্ধারণ করতে পারতেন, তবে অলস তাত্ক্ষণিক ব্যবহার ডিআইবির বিপক্ষে যে পরামর্শ দেওয়া ভুল is
কিডসশো

@ কিশাও আমি না।
সোলেইল - ম্যাথিউ প্রভোট

4

ক্যানোনিক ড্রাইআইক কেস

কোনও পুরানো পোস্টের উত্তর দেওয়া, তবে এটি করা DryIocএবং আমি যা মনে করি তা করা ডিআই এবং ইন্টারফেসের (কংক্রিটের ক্লাসগুলির ন্যূনতম ব্যবহার) এর ভাল ব্যবহার।

  1. ডাব্লুপিএফ অ্যাপ্লিকেশনটির প্রারম্ভিক বিন্দুটি App.xamlএবং সেখানে আমরা ব্যবহার করার অভ্যন্তরীণ দৃষ্টিভঙ্গিটি কী তা বলি; আমরা ডিফল্ট xaml এর পরিবর্তে কোড সহ এটি করি:
  2. অপসারণ StartupUri="MainWindow.xaml"App.xaml মধ্যে
  3. কোডবিহাইডে (App.xaml.cs) এটি যুক্ত করুন override OnStartup:

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);
        DryContainer.Resolve<MainWindow>().Show();
    }
    

এটাই স্টার্টআপ পয়েন্ট; এটিই একমাত্র জায়গা যেখানে resolveডাকা উচিত।

  1. কনফিগারেশন রুট (। নেট মধ্যে মার্ক সিমেনের বই নির্ভরতা ইনজেকশন অনুসারে; কংক্রিটের ক্লাসগুলি উল্লেখ করা উচিত এমন একমাত্র জায়গা) কনস্ট্রাক্টরে একই কোডবিহাইডে থাকবে:

    public Container DryContainer { get; private set; }
    
    public App()
    {
        DryContainer = new Container(rules => rules.WithoutThrowOnRegisteringDisposableTransient());
        DryContainer.Register<IDatabaseManager, DatabaseManager>();
        DryContainer.Register<IJConfigReader, JConfigReader>();
        DryContainer.Register<IMainWindowViewModel, MainWindowViewModel>(
            Made.Of(() => new MainWindowViewModel(Arg.Of<IDatabaseManager>(), Arg.Of<IJConfigReader>())));
        DryContainer.Register<MainWindow>();
    }
    

মন্তব্য এবং আরও কিছু বিশদ

  • আমি দৃশ্যের সাথে কংক্রিট শ্রেণি ব্যবহার করেছি MainWindow;
  • ভিউমোডেলের জন্য কোন কনট্রাক্টরটি ব্যবহার করতে হবে (আমাদের এটি DryIoc সহ করতে হবে) নির্দিষ্ট করতে হয়েছিল, কারণ এক্সএএমএল ডিজাইনারের জন্য ডিফল্ট কনস্ট্রাক্টরটির উপস্থিতি থাকা প্রয়োজন এবং ইঞ্জেকশন সহ কনস্ট্রাক্টরই অ্যাপ্লিকেশনটির জন্য ব্যবহৃত প্রকৃত।

ডিআই সহ ভিউমোডেল নির্মাতা:

public MainWindowViewModel(IDatabaseManager dbmgr, IJConfigReader jconfigReader)
{
    _dbMgr = dbmgr;
    _jconfigReader = jconfigReader;
}

ডিজাইনের জন্য ভিউমোডেল ডিফল্ট নির্মাতা:

public MainWindowViewModel()
{
}

দেখার কোডবিহাইড:

public partial class MainWindow
{
    public MainWindow(IMainWindowViewModel vm)
    {
        InitializeComponent();
        ViewModel = vm;
    }

    public IViewModel ViewModel
    {
        get { return (IViewModel)DataContext; }
        set { DataContext = value; }
    }
}

এবং ভিউমোডেলের সাথে ডিজাইনের উদাহরণ পেতে ভিউতে (মেইনওয়াইন্ডো.এক্সএএমএল) কী প্রয়োজন:

d:DataContext="{d:DesignInstance local:MainWindowViewModel, IsDesignTimeCreatable=True}"

উপসংহার

সুতরাং ভিউ এবং ভিউ মডেলদের ডিজাইনের উদাহরণগুলি সম্ভব রেখে আমরা একটি ড্রায়আইওকে ধারক এবং ডিআই সহ একটি ডাব্লুপিএফ অ্যাপ্লিকেশনটির একটি খুব পরিষ্কার এবং ন্যূনতম বাস্তবায়ন পেয়েছি।


2

পরিচালিত এক্সটেনসিবিলিটি ফ্রেমওয়ার্কটি ব্যবহার করুন ।

[Export(typeof(IViewModel)]
public class SomeViewModel : IViewModel
{
    private IStorage _storage;

    [ImportingConstructor]
    public SomeViewModel(IStorage storage){
        _storage = storage;
    }

    public bool ProperlyInitialized { get { return _storage != null; } }
}

[Export(typeof(IStorage)]
public class Storage : IStorage
{
    public bool SaveFile(string content){
        // Saves the file using StreamWriter
    }
}

//Somewhere in your application bootstrapping...
public GetViewModel() {
     //Search all assemblies in the same directory where our dll/exe is
     string currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
     var catalog = new DirectoryCatalog(currentPath);
     var container = new CompositionContainer(catalog);
     var viewModel = container.GetExport<IViewModel>();
     //Assert that MEF did as advertised
     Debug.Assert(viewModel is SomViewModel); 
     Debug.Assert(viewModel.ProperlyInitialized);
}

সাধারণভাবে, আপনি যা করবেন তা একটি স্থির শ্রেণি রয়েছে এবং আপনাকে গ্লোবাল ধারক (ক্যাশেড, ন্যাচ) সরবরাহ করতে কারখানা প্যাটার্ন ব্যবহার করে use

ভিউ মডেলগুলি কীভাবে ইনজেক্ট করা যায়, আপনি সেগুলিকে একইভাবে ইনজেক্ট করুন আপনি সমস্ত কিছু ইনজেক্ট করবেন। এক্সএএমএল ফাইলের কোড-পেছনে একটি আমদানি করা কনস্ট্রাক্টর তৈরি করুন (বা কোনও সম্পত্তি / ক্ষেত্রের উপর আমদানির বিবৃতি দিন) এবং দেখুন মডেলটি আমদানি করতে বলুন। তারপর বেঁধে আপনার Window's DataContextযে সম্পত্তিতে। আপনার প্রকৃত অবজেক্টগুলি যা আপনি প্রকৃতপক্ষে ধারকটি থেকে টানেন সেগুলি সাধারণত সাধারণত রচনাগুলি তৈরি Windowহয়। উইন্ডো ক্লাসে কেবল ইন্টারফেস যুক্ত করুন, এবং তাদের রফতানি করুন, তারপরে উপরের মত ক্যাটালগ থেকে ধরুন (App.xaml.cs এ ... এটি ডাব্লুপিএফ বুটস্ট্র্যাপ ফাইল)।


আপনি ডিআই-র একটি গুরুত্বপূর্ণ পয়েন্ট মিস করছেন যা কোনও উদাহরণ সৃষ্টি এড়ানোর জন্য new
সোলেইল - ম্যাথিউ প্রভোট

1

আমি ভিউমোডেলটি ব্যবহার করার পরামর্শ দেব - প্রথম পদ্ধতির https://github.com/Caliburn- মাইক্রো / ক্যালিবর্ন.মাইক্রো

দেখুন: https://caliburnmicro.codeplex.com/wikipage?title=Al%20About%2020 চুক্তিগুলি

Castle Windsorআইওসি পাত্রে হিসাবে ব্যবহার করুন ।

সমস্ত কনভেনশন সম্পর্কে

ক্যালিবার্নের অন্যতম প্রধান বৈশিষ্ট্য M মাইক্রো একাধিক সম্মেলনে অভিনয় করে বয়লার প্লেট কোডের প্রয়োজনীয়তা অপসারণ করার দক্ষতায় প্রকাশিত। কিছু লোক সম্মেলন পছন্দ করে এবং কিছু তাদের ঘৃণা করে। এজন্য মুখ্যমন্ত্রীর সম্মেলনগুলি সম্পূর্ণ কাস্টমাইজযোগ্য এবং এমনকি না চাইলে সম্পূর্ণভাবে বন্ধও করা যেতে পারে। আপনি যদি কনভেনশনগুলি ব্যবহার করতে যাচ্ছেন এবং যেহেতু সেগুলি ডিফল্টরূপে চালু রয়েছে, এই সম্মেলনগুলি কী এবং তারা কীভাবে কাজ করে তা জেনে রাখা ভাল। এটি এই নিবন্ধের বিষয়। রেজোলিউশন দেখুন (ViewModel- প্রথম)

বুনিয়াদি

সিএম ব্যবহার করার সময় আপনি যে প্রথম সম্মেলনের মুখোমুখি হতে পারেন তা দেখার সমাধানের সাথে সম্পর্কিত। এই কনভেনশনটি আপনার আবেদনের যেকোন ভিউমোডেল-প্রথম ক্ষেত্রকে প্রভাবিত করে। ভিউমোডেল-প্রথমটিতে, আমাদের বিদ্যমান ভিউমোডেল রয়েছে যা আমাদের পর্দায় রেন্ডার করতে হবে। এটি করার জন্য, সিএম একটি ব্যবহারকারীর নিয়ন্ত্রণ 1 এটির জন্য একটি সাধারণ নামকরণ প্যাটার্ন ব্যবহার করে যা ভিউমোডেল এবং ডিসপ্লেতে আবদ্ধ হয়। তো, সেই প্যাটার্নটি কী? আসুন শুধু ভিউলোকেটরটি দেখুন Lএর জন্য লকফোর্ডমোডেলটাইপ:

public static Func<Type, DependencyObject, object, UIElement> LocateForModelType = (modelType, displayLocation, context) =>{
    var viewTypeName = modelType.FullName.Replace("Model", string.Empty);
    if(context != null)
    {
        viewTypeName = viewTypeName.Remove(viewTypeName.Length - 4, 4);
        viewTypeName = viewTypeName + "." + context;
    }

    var viewType = (from assmebly in AssemblySource.Instance
                    from type in assmebly.GetExportedTypes()
                    where type.FullName == viewTypeName
                    select type).FirstOrDefault();

    return viewType == null
        ? new TextBlock { Text = string.Format("{0} not found.", viewTypeName) }
        : GetOrCreateViewType(viewType);
};

প্রথমে "প্রসঙ্গ" ভেরিয়েবলটিকে অগ্রাহ্য করা যাক। দৃষ্টিভঙ্গিটি রূপ নেওয়ার জন্য, আমরা ধরেই নিয়েছি যে আপনি আপনার ভিএমগুলির নামকরণে "ভিউমোডেল" পাঠ্যটি ব্যবহার করছেন, সুতরাং আমরা কেবল "মডেল" শব্দটি সরিয়ে যেখানেই খুঁজে পাই না কেন এটি "ভিউ" তে পরিবর্তন করেছি। এটি উভয় প্রকারের নাম এবং নামের স্থান পরিবর্তন করার প্রভাব ফেলে। সুতরাং ভিউমোডেলস.কাস্টমরভিউমোডেল ভিউস.কাস্টমারভিউতে পরিণত হবে। বা যদি আপনি বৈশিষ্ট্য অনুসারে আপনার অ্যাপ্লিকেশনটি সংগঠিত করছেন: গ্রাহকতা ব্যবস্থাপনা C কাস্টমারভিউমোডেল গ্রাহক ম্যানেজমেন্ট.কাস্টমারভিউতে পরিণত হয়। আশা করি, এটি বেশ সোজা এগিয়ে। আমাদের নামটি পরে, আমরা তখন সেই নামের সাথে সন্ধান করি। আপনি মুখ্যমন্ত্রীকে যে কোনও অ্যাসেম্বলির সন্ধান করেছেন সেটি এসেম্বলসোর্স এর মাধ্যমে অনুসন্ধানযোগ্য হিসাবে আবিষ্কার করুন n যদি আমরা প্রকারটি খুঁজে না পাই,

এখন, সেই "প্রসঙ্গ" মানটিতে ফিরে আসুন। মুখ্যমন্ত্রী একই ভিউমোডেলের উপরে একাধিক ভিউ সমর্থন করেন। যদি কোনও প্রসঙ্গ (সাধারণত একটি স্ট্রিং বা এনুম) সরবরাহ করা হয় তবে আমরা সেই মানটির উপর ভিত্তি করে নামের আরও রূপান্তর করি। এই রূপান্তরটি কার্যকরভাবে ধরে নিয়েছে যে "ভিউ" শব্দটি শেষ থেকে সরিয়ে এবং এর পরিবর্তে প্রসঙ্গটি সংযোজন করে বিভিন্ন দর্শনের জন্য আপনার একটি ফোল্ডার (নেমস্পেস) রয়েছে। সুতরাং, "মাস্টার" এর একটি প্রসঙ্গ দেওয়া আমাদের ভিউমোডেলস। কাস্টমারভিউমোডেলটি ভিউ.কাস্টমআরমাস্টার হয়ে যাবে।


4
আপনার সম্পূর্ণ পোস্ট মতামত।
জন পিটারস

0

আপনার app.xaml থেকে স্টার্টআপ ইউরি সরান।

App.xaml.cs

public partial class App
{
    protected override void OnStartup(StartupEventArgs e)
    {
        IoC.Configure(true);

        StartupUri = new Uri("Views/MainWindowView.xaml", UriKind.Relative);

        base.OnStartup(e);
    }
}

উদাহরণস্বরূপ আপনি এখন আপনার আইওসি ক্লাস ব্যবহার করতে পারেন।

মেইন উইন্ডোভিউ.অ্যাক্সমল সি

public partial class MainWindowView
{
    public MainWindowView()
    {
        var mainWindowViewModel = IoC.GetInstance<IMainWindowViewModel>();

        //Do other configuration            

        DataContext = mainWindowViewModel;

        InitializeComponent();
    }

}

4
আপনার বাইরের app.xaml.cs GetInstanceএর কোনও ধারক থাকা উচিত নয় resolve, আপনি ডিআই এর বিন্দু হারাচ্ছেন। এছাড়াও, ভিউ এর কোডবিহাইডে জ্যামাল ভিউ উল্লেখ করা একধরণের সংশ্লেষিত is খালি সি # তে ভিউ কল করুন এবং ধারক দিয়ে এটি করুন।
সোলেল - ম্যাথিউ প্রভোট
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.