এমভিভিএম সহ ডাব্লুপিএফ সংলাপগুলির জন্য ভাল বা খারাপ অনুশীলন?


148

আমার ডাব্লুপিএফ অ্যাপ্লিকেশনটির জন্য সংলাপগুলি সম্পাদনা এবং সম্পাদনা করতে ইদানীং আমার সমস্যা হয়েছিল।

আমি আমার কোডে যা করতে চাই তা হ'ল কিছু। (আমি বেশিরভাগ এমভিভিএম এর সাথে ভিউ মডেল প্রথম পদ্ধতির ব্যবহার করি)

একটি ডায়লগ উইন্ডো কল করে ViewModel:

var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM);
// Do anything with the dialog result

এটা কিভাবে কাজ করে?

প্রথমত, আমি একটি সংলাপ পরিষেবা তৈরি করেছি:

public interface IUIWindowDialogService
{
    bool? ShowDialog(string title, object datacontext);
}

public class WpfUIWindowDialogService : IUIWindowDialogService
{
    public bool? ShowDialog(string title, object datacontext)
    {
        var win = new WindowDialog();
        win.Title = title;
        win.DataContext = datacontext;

        return win.ShowDialog();
    }
}

WindowDialogএকটি বিশেষ তবে সাধারণ উইন্ডো। আমার বিষয়বস্তু ধরে রাখতে আমার এটি দরকার:

<Window x:Class="WindowDialog"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    Title="WindowDialog" 
    WindowStyle="SingleBorderWindow" 
    WindowStartupLocation="CenterOwner" SizeToContent="WidthAndHeight">
    <ContentPresenter x:Name="DialogPresenter" Content="{Binding .}">

    </ContentPresenter>
</Window>

ডাব্লুপিএফ-এ সংলাপগুলির সাথে সমস্যা dialogresult = trueকেবল কোডেই অর্জন করা যায়। এ কারণেই আমি dialogviewmodelএটি কার্যকর করার জন্য একটি ইন্টারফেস তৈরি করেছি।

public class RequestCloseDialogEventArgs : EventArgs
{
    public bool DialogResult { get; set; }
    public RequestCloseDialogEventArgs(bool dialogresult)
    {
        this.DialogResult = dialogresult;
    }
}

public interface IDialogResultVMHelper
{
    event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
}

যখনই আমার ভিউমোডেল মনে করে যে এটির জন্য সময় এসেছে dialogresult = trueতখন এই ইভেন্টটি উত্থাপন করুন।

public partial class DialogWindow : Window
{
    // Note: If the window is closed, it has no DialogResult
    private bool _isClosed = false;

    public DialogWindow()
    {
        InitializeComponent();
        this.DialogPresenter.DataContextChanged += DialogPresenterDataContextChanged;
        this.Closed += DialogWindowClosed;
    }

    void DialogWindowClosed(object sender, EventArgs e)
    {
        this._isClosed = true;
    }

    private void DialogPresenterDataContextChanged(object sender,
                              DependencyPropertyChangedEventArgs e)
    {
        var d = e.NewValue as IDialogResultVMHelper;

        if (d == null)
            return;

        d.RequestCloseDialog += new EventHandler<RequestCloseDialogEventArgs>
                                    (DialogResultTrueEvent).MakeWeak(
                                        eh => d.RequestCloseDialog -= eh;);
    }

    private void DialogResultTrueEvent(object sender, 
                              RequestCloseDialogEventArgs eventargs)
    {
        // Important: Do not set DialogResult for a closed window
        // GC clears windows anyways and with MakeWeak it
        // closes out with IDialogResultVMHelper
        if(_isClosed) return;

        this.DialogResult = eventargs.DialogResult;
    }
 }

এখন কমপক্ষে আমাকে DataTemplateআমার রিসোর্স ফাইলে একটি তৈরি করতে হবে ( app.xamlবা কিছু):

<DataTemplate DataType="{x:Type DialogViewModel:EditOrNewAuswahlItemVM}" >
        <DialogView:EditOrNewAuswahlItem/>
</DataTemplate>

সর্বোপরি, আমি এখন আমার ভিউ মডেলগুলি থেকে ডায়লগ কল করতে পারি:

 var result = this.uiDialogService.ShowDialog("Dialogwindow Title", dialogwindowVM);

এখন আমার প্রশ্ন, আপনি কি এই সমাধান নিয়ে কোনও সমস্যা দেখছেন?

সম্পাদনা করুন: সম্পূর্ণতার জন্য। ভিউমোডেলটি প্রয়োগ করা উচিত IDialogResultVMHelperএবং তারপরে এটি এটিকে OkCommandবা এর মতো কিছুতে বাড়িয়ে তুলতে পারে :

public class MyViewmodel : IDialogResultVMHelper
{
    private readonly Lazy<DelegateCommand> _okCommand;

    public MyViewmodel()
    {
         this._okCommand = new Lazy<DelegateCommand>(() => 
             new DelegateCommand(() => 
                 InvokeRequestCloseDialog(
                     new RequestCloseDialogEventArgs(true)), () => 
                         YourConditionsGoesHere = true));
    }

    public ICommand OkCommand
    { 
        get { return this._okCommand.Value; } 
    }

    public event EventHandler<RequestCloseDialogEventArgs> RequestCloseDialog;
    private void InvokeRequestCloseDialog(RequestCloseDialogEventArgs e)
    {
        var handler = RequestCloseDialog;
        if (handler != null) 
            handler(this, e);
    }
 }

সম্পাদনা 2: আমি আমার ইভেন্টহ্যান্ডলারটিকে নিবন্ধভুক্ত করার জন্য কোডটি এখান থেকে ব্যবহার করেছি:
http://diditwith.net/2007/03/23/SolvingTheProblemWithEventsWeakEventHandlers.aspx
(ওয়েবসাইট আর নেই, ওয়েবআর্কাইভ মিরর )

public delegate void UnregisterCallback<TE>(EventHandler<TE> eventHandler) 
    where TE : EventArgs;

public interface IWeakEventHandler<TE> 
    where TE : EventArgs
{
    EventHandler<TE> Handler { get; }
}

public class WeakEventHandler<T, TE> : IWeakEventHandler<TE> 
    where T : class 
    where TE : EventArgs
{
    private delegate void OpenEventHandler(T @this, object sender, TE e);

    private readonly WeakReference mTargetRef;
    private readonly OpenEventHandler mOpenHandler;
    private readonly EventHandler<TE> mHandler;
    private UnregisterCallback<TE> mUnregister;

    public WeakEventHandler(EventHandler<TE> eventHandler,
                                UnregisterCallback<TE> unregister)
    {
        mTargetRef = new WeakReference(eventHandler.Target);

        mOpenHandler = (OpenEventHandler)Delegate.CreateDelegate(
                           typeof(OpenEventHandler),null, eventHandler.Method);

        mHandler = Invoke;
        mUnregister = unregister;
    }

    public void Invoke(object sender, TE e)
    {
        T target = (T)mTargetRef.Target;

        if (target != null)
            mOpenHandler.Invoke(target, sender, e);
        else if (mUnregister != null)
        {
            mUnregister(mHandler);
            mUnregister = null;
        }
    }

    public EventHandler<TE> Handler
    {
        get { return mHandler; }
    }

    public static implicit operator EventHandler<TE>(WeakEventHandler<T, TE> weh)
    {
        return weh.mHandler;
    }
}

public static class EventHandlerUtils
{
    public static EventHandler<TE> MakeWeak<TE>(this EventHandler<TE> eventHandler, 
                                                    UnregisterCallback<TE> unregister)
        where TE : EventArgs
    {
        if (eventHandler == null)
            throw new ArgumentNullException("eventHandler");

        if (eventHandler.Method.IsStatic || eventHandler.Target == null)
            throw new ArgumentException("Only instance methods are supported.",
                                            "eventHandler");

        var wehType = typeof(WeakEventHandler<,>).MakeGenericType(
                          eventHandler.Method.DeclaringType, typeof(TE));

        var wehConstructor = wehType.GetConstructor(new Type[] 
                             { 
                                 typeof(EventHandler<TE>), typeof(UnregisterCallback<TE>) 
                             });

        IWeakEventHandler<TE> weh = (IWeakEventHandler<TE>)wehConstructor.Invoke(
                                        new object[] { eventHandler, unregister });

        return weh.Handler;
    }
}

1
আপনি সম্ভবত আপনার উইন্ডো ডায়ালগ এক্সএএমএল- তে এক্সএমএনএস: x = " স্কিমাস.মিকাইসফেস.কম / উইনফেক্স / ২০০6/ xaml " রেফারেন্স মিস করছেন।
অ্যাডিয়েল ইয়াকাকভ

প্রকৃতপক্ষে নেমস্পেসটি হল xmlns: x = "[http: //] স্কিমেস.মাইক্রোসফট /উইনফেক্স/2006/xaml" বন্ধনী ছাড়াই
রেগেগুইটার


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

2
হাই @ ব্লাইন্ডমেইস, এই ধারণাটি নিয়ে কেবল আমার মাথা গুটিয়ে দেওয়ার চেষ্টা করছি, আমি মনে করি না এমন কোনও অনলাইন উদাহরণ প্রকল্প আছে যা আমি গ্রহণ করতে পারি? আমি বিভ্রান্ত হয়েছি এমন অনেকগুলি বিষয় রয়েছে।
হাঙ্ক

উত্তর:


48

এটি একটি ভাল পদ্ধতির এবং আমি অতীতে একই জাতীয় ব্যবহার করেছি। এটার জন্য যাও!

একটি ছোটখাটো জিনিস যা আমি অবশ্যই করতে চাই তা হ'ল ডায়লগেরসাল্টে যখন আপনাকে "মিথ্যা" সেট করতে হবে তখন ইভেন্টটির একটি বুলিয়ান গ্রহণ করা।

event EventHandler<RequestCloseEventArgs> RequestCloseDialog;

এবং ইভেন্টআর্গ ক্লাস:

public class RequestCloseEventArgs : EventArgs
{
    public RequestCloseEventArgs(bool dialogResult)
    {
        this.DialogResult = dialogResult;
    }

    public bool DialogResult { get; private set; }
}

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

15

আমি এখন বেশ কয়েক মাস ধরে প্রায় অভিন্ন পদ্ধতি ব্যবহার করে আসছি এবং এতে আমি খুব খুশি হয়েছি (যেমন আমি এখনও এটি পুরোপুরি নতুন করে লেখার তাগিদ অনুভব করতে পারি নি ...)

আমার বাস্তবায়নে আমি IDialogViewModelএমন একটি ব্যবহার করি যা শিরোনাম, স্ট্যান্ডাড বোতামগুলি প্রদর্শন করার জন্য (সমস্ত কথোপকথনের সাথে সামঞ্জস্যপূর্ণ অবয়ব রাখতে), একটি RequestCloseইভেন্ট এবং উইন্ডো আকার নিয়ন্ত্রণ করতে সক্ষম হতে আরও কয়েকটি জিনিস এবং আচরণ


THX, শিরোনামটি সত্যই আমার আইডিয়ালগভিউ মডেলটিতে থাকা উচিত। আকার, স্ট্যান্ডার্ড বোতামের মতো অন্যান্য বৈশিষ্ট্যগুলি আমি ছাড়ব, কারণ এই সমস্তটি অন্তত ডেটাপ্যাম্পেট থেকে আসে।
ব্লাইন্ডমিস

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

@ থমাস লেভসেক আপনার ভিউমোডেলে থাকা বোতামগুলি, সেগুলি কি আসলে ইউআই বোতামের অবজেক্ট বা বস্তুর প্রতিনিধিত্বকারী বোতামগুলি?
থমাস

3
@ থমাস, বোতাম উপস্থাপনকারী বস্তু ভিউমোডেলে আপনার কখনই UI অবজেক্টগুলি উল্লেখ করা উচিত নয়।
টমাস লেভেস্ক

2

আপনি যদি কথোপকথন উইন্ডো সম্পর্কে কথা বলছেন এবং কেবল পপ-আপ বার্তা বাক্সগুলির বিষয়ে নয়, দয়া করে নীচে আমার পদ্ধতির বিষয়টি বিবেচনা করুন। মূল বিষয়গুলি হ'ল:

  1. আমি Module Controllerপ্রত্যেকটির কন্সট্রাক্টরের কাছে একটি রেফারেন্স দিয়েছি ViewModel(আপনি ইঞ্জেকশনটি ব্যবহার করতে পারেন)।
  2. এতে Module Controllerডায়লগ উইন্ডো তৈরির জন্য সর্বজনীন / অভ্যন্তরীণ পদ্ধতি রয়েছে (কোনও ফলাফল না দিয়ে কেবল তৈরি করা)। তাই ViewModelআমি লিখতে একটি কথোপকথন উইন্ডো খুলতে :controller.OpenDialogEntity(bla, bla...)
  3. প্রতিটি সংলাপ উইন্ডো দুর্বল ইভেন্টগুলির মাধ্যমে তার ফলাফল সম্পর্কে (যেমন ঠিক আছে , সংরক্ষণ করুন , বাতিল করুন ইত্যাদি) অবহিত করে । আপনি যদি PRISM ব্যবহার করেন তবে এই ইভেন্টএগ্রিগ্রেটার ব্যবহার করে বিজ্ঞপ্তি প্রকাশ করা আরও সহজ ।
  4. সংলাপের ফলাফলগুলি পরিচালনা করতে, আমি বিজ্ঞপ্তিগুলির সাবস্ক্রিপশনটি ব্যবহার করছি ( PRISM এর ক্ষেত্রে আবার দুর্বল ইভেন্টস এবং ইভেন্টএগ্রিগেটর )। এই জাতীয় বিজ্ঞপ্তির উপর নির্ভরতা হ্রাস করতে, স্ট্যান্ডার্ড বিজ্ঞপ্তিগুলির সাথে স্বাধীন ক্লাস ব্যবহার করুন।

পেশাদাররা:

  • কম কোড। ইন্টারফেস ব্যবহারে আমার আপত্তি নেই, তবে আমি এমন অনেকগুলি প্রকল্প দেখেছি যেখানে ইন্টারফেস এবং অ্যাবস্ট্রাকশন স্তরগুলি ব্যবহারের অত্যধিকতা সাহায্যের চেয়ে আরও বেশি সমস্যার সৃষ্টি করে।
  • Module Controllerশক্তিশালী রেফারেন্সগুলি এড়ানোর সহজ উপায় হ'ল খোলা কথোপকথন উইন্ডোজ এবং এখনও পরীক্ষার জন্য মক-আপগুলি ব্যবহার করার অনুমতি দেয়।
  • দুর্বল ইভেন্টগুলির মাধ্যমে বিজ্ঞপ্তি সম্ভাব্য মেমরি ফাঁসের সংখ্যা হ্রাস করে।

কনস:

  • হ্যান্ডলারের অন্যদের থেকে প্রয়োজনীয় বিজ্ঞপ্তি আলাদা করা সহজ নয়। দুটি সমাধান:
    • একটি কথোপকথন উইন্ডো খোলার জন্য একটি অনন্য টোকেন প্রেরণ করুন এবং সাবস্ক্রিপশনে সেই টোকেনটি দেখুন
    • জেনেরিক নোটিফিকেশন ক্লাস ব্যবহার করুন <T>যেখানে Tসত্তার সংখ্যা রয়েছে (বা সরলতার জন্য এটি ভিউমোডেলের ধরণ হতে পারে)।
  • কোনও প্রকল্পের নোটিফিকেশন প্রতিরোধের জন্য বিজ্ঞপ্তি ক্লাস ব্যবহার করার বিষয়ে একটি চুক্তি হওয়া উচিত।
  • প্রচুর পরিমাণে বড় প্রকল্পগুলির Module Controllerজন্য উইন্ডো তৈরির পদ্ধতিতে অভিভূত হতে পারে। এই ক্ষেত্রে এটি বিভিন্ন মডিউল মধ্যে বিভক্ত করা ভাল।

পিএস আমি এই পদ্ধতিটি এখন দীর্ঘকাল ধরে ব্যবহার করছি এবং মন্তব্যে এর যোগ্যতা রক্ষা করতে এবং প্রয়োজনে কিছু উদাহরণ সরবরাহ করার জন্য প্রস্তুত।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.