ভিউমোডেলটি ফর্মটি কীভাবে বন্ধ করা উচিত?


247

আমি ডাব্লুপিএফ এবং এমভিভিএম সমস্যা শেখার চেষ্টা করছি, তবে একটি ছটফট করেছি। এই প্রশ্নটি অনুরূপ তবে এইটির মতো একরকম নয় (এমভিভিএম-এর সাথে ডাব্লুপিএফ-এ হ্যান্ডলিং-ডায়লগ) ...

আমার এমভিভিএম প্যাটার্নটি ব্যবহার করে একটি "লগইন" ফর্ম লেখা আছে।

এই ফর্মটিতে একটি ভিউমোডেল রয়েছে যা ব্যবহারকারীর নাম এবং পাসওয়ার্ড ধারণ করে, যা সাধারণ ডেটা বাইন্ডিং ব্যবহার করে এক্সএএমএল-এ দৃশ্যের সাথে আবদ্ধ। এটিতে একটি "লগইন" কমান্ড রয়েছে যা ফর্মের "লগইন" বোতামের সাথে আবদ্ধ, সাধারণ ডাটাবেইন্ডিং ব্যবহার করে আগান।

যখন "লগইন" কমান্ডটি চালিত হয়, এটি ভিউমোডেলে একটি ফাংশনকে আহ্বান করে যা বন্ধ হয়ে যায় এবং লগ ইন করার জন্য নেটওয়ার্কের মাধ্যমে ডেটা প্রেরণ করে this যখন এই ফাংশনটি সম্পূর্ণ হয়, তখন 2 টি ক্রিয়া হয়:

  1. লগইনটি অবৈধ ছিল - আমরা কেবল একটি বার্তাবক্স দেখাই এবং সব ঠিক আছে

  2. লগইনটি বৈধ ছিল, আমাদের লগইন ফর্মটি বন্ধ করতে হবে এবং এটির হিসাবে এটি সত্য হওয়া উচিত DialogResult...

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


হালনাগাদ

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

এটি বরং নির্বোধ বলে মনে হয় যে গৃহীত উত্তরটি -5 ভোটে! আমি যখন "শুদ্ধ" হওয়ার সময় সমস্যার সমাধান করে যে ভাল অনুভূতি সম্পর্কে ভালভাবে অবগত আছি তখন অবশ্যই আমি একা নই যে 200 লাইনের ইভেন্ট, কমান্ড এবং আচরণের একটি লাইন পদ্ধতি এড়াতে কেবল এটিই মনে করে "নিদর্শন" এবং "বিশুদ্ধতা" এর নামটি কিছুটা হাস্যকর ....


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

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

2
আপনি ডায়লগ ফলাফলের জন্য নীচের লিঙ্কটি চেক করতে পারেন asimsajjad.blogspot.com/2010/10/… , যা ডায়ালগটির পুনঃসূচনা ফিরে আসবে এবং ভিউমোডেল থেকে দৃশ্যটি বন্ধ করবে
অসীম সাজ্জাদ

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

2
@ ওরিওনওডওয়ার্ডস আমি মনে করি আপনি এখানে প্যাটার্নটি ভাঙতে ঠিক বলেছেন। ডিজাইনের প্যাটার্নের একটি প্রধান উদ্দেশ্য হ'ল উন্নয়নের চক্রকে ত্বরান্বিত করা, রক্ষণাবেক্ষণযোগ্যতা বাড়ানো এবং একই নিয়ম অনুসরণ করে পুরো দলকে তৈরি করে আপনার কোডটি সরল করা। বাহ্যিক গ্রন্থাগারের উপর নির্ভরতা যুক্ত করে এবং কোনও কাজ সম্পাদনের জন্য কয়েকশ কোড লাইন প্রয়োগ করে এটি অর্জন করা যায় না, পুরোপুরি উপেক্ষা করে যে আরও সহজ সমাধান রয়েছে, কেবলমাত্র প্যাটার্নের "বিশুদ্ধতা" ত্যাগ করার জন্য একগুঁয়েমী হওয়া। শুধু ডকুমেন্ট কৃতকর্মের your've করতে নিশ্চিত এবং চুম্বন আপনার কোড ( EEP আমি টি গুলি Hort এবং গুলি imple)।
এম 463

উত্তর:


324

একটি সহজ সংযুক্ত সম্পত্তি লিখতে আমি থেজুয়ানের উত্তরে অনুপ্রাণিত হয়েছি । স্টাইল নেই, ট্রিগার নেই; পরিবর্তে, আপনি কেবল এটি করতে পারেন:

<Window ...
        xmlns:xc="clr-namespace:ExCastle.Wpf"
        xc:DialogCloser.DialogResult="{Binding DialogResult}">

এটি প্রায় এতটাই পরিষ্কার যে ডাব্লুপিএফ টিম এটি সঠিকভাবে অর্জন করেছে এবং ডায়ালগআরসাল্টকে প্রথম স্থানে নির্ভরশীল সম্পত্তি হিসাবে তৈরি করেছে। bool? DialogResultআপনার ভিউমোডেলটিতে কেবল একটি সম্পত্তি রেখে আইএনটিফাইপ্রোটার্টি চেঞ্জড প্রয়োগ করুন এবং ভয়েল, আপনার ভিউমোডেল একটি সম্পত্তি সেট করেই উইন্ডোটি বন্ধ করতে পারে (এবং এর ডায়ালগের ফলাফল সেট করতে পারে) set এমভিভিএম যেমনটি হওয়া উচিত।

ডায়ালগক্লোজারের কোড এখানে:

using System.Windows;

namespace ExCastle.Wpf
{
    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty =
            DependencyProperty.RegisterAttached(
                "DialogResult",
                typeof(bool?),
                typeof(DialogCloser),
                new PropertyMetadata(DialogResultChanged));

        private static void DialogResultChanged(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null)
                window.DialogResult = e.NewValue as bool?;
        }
        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }
}

আমি আমার ব্লগে এটি পোস্ট করেছি ।


3
এই উত্তরটি আমি সবচেয়ে পছন্দ করি! ভাল কাজ লেখার যে সংযুক্ত সম্পত্তি।
জর্জে ভার্গাস

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

13
@ হাইটেক ম্যাজিক, মনে হচ্ছে বাগটি প্রথম স্থানে সিঙ্গলটন ভিউমোডেল ব্যবহার করছে। (গ্রিন) গম্ভীরভাবে, কেন পৃথিবীতে আপনি একটি সিঙ্গলটন ভিউমোডেল চান? বৈশ্বিক পরিবর্তনশীলগুলিতে পরিবর্তনীয় স্থিতি রাখা একটি খারাপ ধারণা। একটি দুঃস্বপ্ন পরীক্ষা করে তোলে এবং আপনি প্রথম স্থানে এমভিভিএম ব্যবহার করার কারণগুলির মধ্যে একটি কারণ পরীক্ষা হয়।
জো হোয়াইট

3
এমভিভিএমের বিন্দুটি আপনার যুক্তিটিকে কোনও নির্দিষ্ট ইউআইয়ের সাথে দৃ couple়ভাবে জুড়ে দেবে না? এই ক্ষেত্রে, বুল? উইনফর্মের মতো অন্য কোনও ইউআই দ্বারা অবশ্যই ব্যবহারযোগ্য নয় এবং ডায়ালগক্লোজারটি ডাব্লুপিএফ-এর জন্য নির্দিষ্ট। সুতরাং এটি একটি সমাধান হিসাবে ভাল ফিট করে? এছাড়াও, কেন একটি বাঁধনের মাধ্যমে একটি উইন্ডো বন্ধ করতে 2x-10x কোড লিখুন?
ডেভিড অ্যান্ডারসন

2
@ ডেভিড অ্যান্ডারসন, আমি কোনও অবস্থাতেই উইনফোর্মে এমভিভিএম চেষ্টা করব না; এর ডেটাবাইন্ডিং সমর্থনটি খুব দুর্বল, এবং এমভিভিএম একটি সুচিন্তিত চিন্তাভাবনা বাঁধাই সিস্টেমের উপর নির্ভর করে। এবং এটি 2x-10x কোডের কাছাকাছি কোথাও নেই। আপনি সেই কোডটি একবার লিখবেন , প্রতিটি উইন্ডোর জন্য একবার নয়। তারপরে এটি আপনার এক-লাইন বাঁধাই প্লাস একটি বিজ্ঞপ্তিযুক্ত সম্পত্তি, যা আপনি ইতিমধ্যে আপনার দৃষ্টিকোণে সমস্ত কিছুর জন্য ইতিমধ্যে ব্যবহার করছেন একই পদ্ধতি ব্যবহার করে (উদাহরণস্বরূপ, কেবলমাত্র বন্ধ করার জন্য আপনাকে অতিরিক্ত ভিউ ইন্টারফেসটি ইনজেক্ট করার দরকার নেই) জানলা). আপনি অন্যান্য ট্রেড অফ তৈরি করতে স্বাগত জানালেন তবে এটি আমার কাছে সাধারণভাবে ভাল বলে মনে হয়।
জো হোয়াইট

64

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

প্রতিটি ভিউমোডেল ক্লাসের উত্তরাধিকার সূত্রে WorkspaceViewModelএই জাতীয় RequestCloseইভেন্ট এবং CloseCommandসম্পত্তি থাকা উচিত ICommandCloseCommandসম্পত্তিটির ডিফল্ট বাস্তবায়ন RequestCloseঘটনাকে উত্থাপন করবে ।

উইন্ডোটি বন্ধ পেতে OnLoaded, আপনার উইন্ডোটির পদ্ধতিটি ওভাররাইড করা উচিত:

void CustomerWindow_Loaded(object sender, RoutedEventArgs e)
{
    CustomerViewModel customer = CustomerViewModel.GetYourCustomer();
    DataContext = customer;
    customer.RequestClose += () => { Close(); };
}

বা OnStartupআপনার অ্যাপ্লিকেশন পদ্ধতি:

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

        MainWindow window = new MainWindow();
        var viewModel = new MainWindowViewModel();
        viewModel.RequestClose += window.Close;
        window.DataContext = viewModel;

        window.Show();
    }

আমি অনুমান করি যে RequestCloseইভেন্ট এবং CloseCommandসম্পত্তি প্রয়োগ বাস্তবায়ন WorkspaceViewModelবেশ পরিষ্কার, তবে আমি তাদেরকে ধারাবাহিক হতে দেখাব:

public abstract class WorkspaceViewModel : ViewModelBase
// There's nothing interesting in ViewModelBase as it only implements the INotifyPropertyChanged interface
{
    RelayCommand _closeCommand;
    public ICommand CloseCommand
    {
        get
        {
            if (_closeCommand == null)
            {
                _closeCommand = new RelayCommand(
                   param => Close(),
                   param => CanClose()
                   );
            }
            return _closeCommand;
        }
    }

    public event Action RequestClose;

    public virtual void Close()
    {
        if ( RequestClose != null )
        {
            RequestClose();
        }
    }

    public virtual bool CanClose()
    {
        return true;
    }
}

এবং এর উত্স কোড RelayCommand:

public class RelayCommand : ICommand
{
    #region Constructors

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        if (execute == null)
            throw new ArgumentNullException("execute");

        _execute = execute;
        _canExecute = canExecute;
    }
    #endregion // Constructors

    #region ICommand Members

    [DebuggerStepThrough]
    public bool CanExecute(object parameter)
    {
        return _canExecute == null ? true : _canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    #endregion // ICommand Members

    #region Fields

    readonly Action<object> _execute;
    readonly Predicate<object> _canExecute;

    #endregion // Fields
}

PS এই উত্সগুলির জন্য আমার সাথে খারাপ ব্যবহার করবেন না! আমি যদি গতকাল তাদের কাছে থাকতাম যা আমাকে কয়েক ঘন্টা বাঁচাতে পারত ...

পিপিএস কোন মন্তব্য বা পরামর্শ স্বাগত।


2
উম্মে, আপনি customer.RequestCloseআপনার এক্সএএমএল ফাইলের পিছনের কোডটির ইভেন্ট হ্যান্ডলারের দিকে ঝুঁকেছেন এটি কি এমভিভিএম প্যাটার্ন লঙ্ঘন করে না? আপনি Clickযেভাবেই হোক পেছনের কোডটি ছুঁয়েছেন এবং একটি করেছেন দেখে আপনি প্রথম স্থানে আপনার ঘনিষ্ঠ বোতামের ইভেন্ট হ্যান্ডলারের সাথে আবদ্ধ থাকতে পারেন this.Close()! রাইট?
GONELE

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

18

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

http://adammills.wordpress.com/2009/07/01/window-close-from-xaml/


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

4
এখন এটি এক-লাইন সংযুক্ত আচরণের সাথে করণীয়। আমার উত্তর দেখুন: স্ট্যাকওভারফ্লো
জো হোয়াইট

15

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

এটি বলেছিল, .. আমি মনে করি আপনার মামলাটি কিছুটা রিফ্যাক্টরিংয়ের সাথে ভাল ফিট হতে পারে।

বেশিরভাগ ক্ষেত্রেই আমি এসেছি, ডাব্লুপিএফ আপনাকে একাধিক Windowএস ছাড়াই সক্ষম করে । হতে পারে আপনি ব্যবহার করার চেষ্টা করুন পারে Frames এবং Pageসহ Windows পরিবর্তে গুলি DialogResultগুলি।

আপনার ক্ষেত্রে আমার পরামর্শটির LoginFormViewModelহ্যান্ডেলটি হবে LoginCommandএবং যদি লগইনটি অবৈধ থাকে তবে LoginFormViewModelউপযুক্ত সম্পত্তিতে ( falseবা কিছু এনাম মানের মতো UserAuthenticationStates.FailedAuthentication) একটি সম্পত্তি সেট করুন । আপনি সফল লগইন ( trueবা অন্য কোনও এনাম মান) এর জন্য একই কাজ করবেন । তারপরে আপনি এমন কোনও ব্যবহার করবেন DataTriggerযা বিভিন্ন ব্যবহারকারীর প্রমাণীকরণের রাজ্যে সাড়া দেয় এবং এর বৈশিষ্ট্য Setterপরিবর্তন করতে একটি সাধারণ ব্যবহার করতে পারে । SourceFrame

আপনার লগইন উইন্ডোটি ফিরে আসার পরে DialogResultআমি মনে করি আপনি কোথায় বিভ্রান্ত হচ্ছেন; এটি DialogResultসত্যিই আপনার ভিউমোডেলের একটি সম্পত্তি। আমার, ডাব্লুপিএফের সাথে স্বীকৃতভাবে সীমিত অভিজ্ঞতা, যখন কোনও কিছু ঠিক মনে হয় না কারণ সাধারণত আমি উইনফোর্মে কীভাবে কাজটি করতাম সেভাবে বিবেচনা করছি।

আশা করি এইটি কাজ করবে.


10

ধরে নেওয়া আপনার লগইন ডায়লগটি প্রথম উইন্ডোটি তৈরি হয়, এটি আপনার লগইনভিউমোডেল শ্রেণীর মধ্যে চেষ্টা করুন:

    void OnLoginResponse(bool loginSucceded)
    {
        if (loginSucceded)
        {
            Window1 window = new Window1() { DataContext = new MainWindowViewModel() };
            window.Show();

            App.Current.MainWindow.Close();
            App.Current.MainWindow = window;
        }
        else
        {
            LoginError = true;
        }
    }

পুরুষেরা এটি সহজ এবং দুর্দান্ত কাজ করে। বর্তমানে আমি এই পদ্ধতির ব্যবহার করছি।
এরে এফে

এটি কেবল মেইন উইন্ডোতে কাজ করে। সুতরাং এটি অন্য কোনও উইন্ডোর জন্য ব্যবহার করবেন না।
ওলেকসেই

7

এটি একটি সহজ এবং পরিষ্কার সমাধান - আপনি ভিউমোডেলে একটি ইভেন্ট যুক্ত করেন এবং উইন্ডোটিকে সেই ইভেন্টটি চালিত হওয়ার পরে নিজেকে বন্ধ করার নির্দেশ দিন।

আরও তথ্যের জন্য আমার ব্লগ পোস্টটি দেখুন, ভিউমোডেল থেকে উইন্ডোটি বন্ধ করুন

XAML:

<Window
  x:Name="this"
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"  
  xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions">
  <i:Interaction.Triggers>
    <i:EventTrigger SourceObject="{Binding}" EventName="Closed">
      <ei:CallMethodAction
        TargetObject="{Binding ElementName=this}"
        MethodName="Close"/>
    </i:EventTrigger>
  </i:Interaction.Triggers>
<Window>

ViewModel:

private ICommand _SaveAndCloseCommand;
public ICommand SaveAndCloseCommand
{
  get
  {
    return _SaveAndCloseCommand ??
      (_SaveAndCloseCommand = new DelegateCommand(SaveAndClose));
  }
}
private void SaveAndClose()
{
  Save();
  Close();
}

public event EventHandler Closed;
private void Close()
{
  if (Closed != null) Closed(this, EventArgs.Empty);
}

দ্রষ্টব্য: উদাহরণটি প্রিজমের DelegateCommand( প্রিজম দেখুন: কমান্ডিং ) ICommandব্যবহার করে তবে যে কোনও বাস্তবায়ন সে ক্ষেত্রে ব্যবহার করা যেতে পারে।

আপনি এই অফিসিয়াল প্যাকেজ থেকে আচরণ ব্যবহার করতে পারেন ।


2
+1 তবে আপনাকে উত্তরে নিজেই আরও বিশদ সরবরাহ করতে হবে, উদাহরণস্বরূপ যে এই সমাধানটির জন্য এক্সপ্রেশন ব্লেন্ড ইন্টারেক্টিভিটি অ্যাসেম্বলির রেফারেন্স প্রয়োজন।
surfen

6

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


2
আমি সাধারণত এটিও করি। তবুও এটি যে সমস্ত নতুন রূপযুক্ত ডাব্লুপিএফ-কমান্ডিং স্টাফ বিবেচনা করে কিছুটা নোংরা বলে মনে হচ্ছে।
Botz3000

4

আমি প্রথমে যা করেছি তা এখানে রয়েছে, যা কাজ করে, তবে এটি দীর্ঘ-বায়ুযুক্ত এবং কুরুচিপূর্ণ বলে মনে হয় (গ্লোবাল স্ট্যাটিক কোনও কিছুই কখনই ভাল হয় না)

1: App.xaml.cs

public partial class App : Application
{
    // create a new global custom WPF Command
    public static readonly RoutedUICommand LoggedIn = new RoutedUICommand();
}

2: লগইনফর্ম.এক্সএএমএল

// bind the global command to a local eventhandler
<CommandBinding Command="client:App.LoggedIn" Executed="OnLoggedIn" />

3: লগইনফর্ম.এক্স্যামল সি

// implement the local eventhandler in codebehind
private void OnLoggedIn( object sender, ExecutedRoutedEventArgs e )
{
    DialogResult = true;
    Close();
}

4: লগইনফর্মভিউমোডেল সি

// fire the global command from the viewmodel
private void OnRemoteServerReturnedSuccess()
{
    App.LoggedIn.Execute(this, null);
}

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


3

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

আমার ক্ষেত্রে, ভিউমোডেল যা উইন্ডোটি প্রদর্শিত হতে তাত্ক্ষণিক করে তোলে (যাকে একে ভিউমোডেলমেন বলে ডাকতে পারে) লগইনফর্মভিউমোডেল (উদাহরণস্বরূপ উপরের পরিস্থিতিটি ব্যবহার করে) সম্পর্কেও জানে।

সুতরাং আমি যা করেছি তা লগইনফর্মভিউমোডেলে এমন একটি সম্পত্তি তৈরি করা ছিল যা আইকোমন্ড টাইপের ছিল (আসুন একে ক্লোজউইন্ডোকম্যান্ড বলতে ডাকি)। তারপরে, আমি উইন্ডোতে .Dialog () কল করার আগে, আমি উইন্ডোতে লগইনফর্মভিউমোডেলের ক্লোজ উইন্ডো কম্যান্ড সম্পত্তি সেট করেছিলাম I উইন্ডোটি বন্ধ করে () পদ্ধতিটি ইনস্ট্যান্ট করেছিলাম। তারপরে লগইনফর্মভিউমোডেলের অভ্যন্তরে উইন্ডোটি বন্ধ করার জন্য আমাকে ক্লোজড উইন্ডোকম্যান্ড.এক্সেকিউট () কল করতে হবে।

আমি মনে করি এটি একদম সামান্য কাজ / হ্যাক, তবে এটি সত্যিই এমভিভিএম প্যাটার্নটি ভঙ্গ না করে ভালভাবে কাজ করে।

আপনি যতটা পছন্দ এই প্রক্রিয়াটি সমালোচনা করতে দ্বিধা বোধ করবেন না, আমি এটি নিতে পারি! :)


আমি নিশ্চিত নই যে আমি এটি পুরোপুরি কুঁচকেছি, তবে এর অর্থ এই নয় যে আপনার লগইন উইন্ডোর আগে আপনার মেইন উইন্ডো ইনস্ট্যান্ট করা উচিত? এটি সম্ভব হয় যদি আমি এড়াতে চাই
অরিওন এডওয়ার্ডস

3

এটি সম্ভবত খুব দেরী হয়েছে, তবে আমি একই সমস্যাটি পেয়েছি এবং আমি একটি সমাধান খুঁজে পেয়েছি যা আমার পক্ষে কাজ করে।

ডায়লগ ছাড়াই কীভাবে অ্যাপ তৈরি করতে হয় তা আমি বুঝতে পারি না (সম্ভবত এটি কেবল মাইন্ড ব্লক)। সুতরাং আমি এমভিভিএমের সাথে একটি সংঘর্ষে এসে সংলাপটি দেখছিলাম। সুতরাং আমি এই কোডপ্রজেক্ট নিবন্ধটি জুড়ে এসেছি:

http://www.codeproject.com/KB/WPF/XAMLDialog.aspx

কোন ইউজারকন্ট্রল যা মূলত উইন্ডোটিকে অন্য উইন্ডোটির ভিজ্যুয়াল ট্রিের মধ্যে থাকতে দেয় (xaml এ অনুমোদিত নয়)। এটি ইস্ওহিং নামে একটি বুলিয়ান নির্ভরতা প্রপোর্টিও প্রকাশ করে।

আপনি সাধারণত একটি রিসোর্সড অভিধানে একটি স্টাইল সেট করতে পারেন যা মূলত যখনই নিয়ন্ত্রণের সামগ্রীর সম্পত্তি! = ট্রিগারগুলির মাধ্যমে শূন্য হয় তখন ডায়লগটি প্রদর্শন করে:

<Style TargetType="{x:Type d:Dialog}">
    <Style.Triggers>
        <Trigger Property="HasContent"  Value="True">
            <Setter Property="Showing" Value="True" />
        </Trigger>
    </Style.Triggers>
</Style>

আপনি যেখানে ডায়ালগটি প্রদর্শন করতে চান সেই দৃশ্যে এটি হ'ল:

<d:Dialog Content="{Binding Path=DialogViewModel}"/>

এবং আপনার ভিউমোডেলে আপনাকে যা করতে হবে তা হল সম্পত্তিটিকে একটি মান হিসাবে সেট করতে হবে (দ্রষ্টব্য: কিছু ঘটেছে তা দেখার জন্য ভিউমোডেল শ্রেণি অবশ্যই INotifyPropertyChanged সমর্থন করবে)।

তাই ভালো:

DialogViewModel = new DisplayViewModel();

ভিউমোডেলটি ভিউয়ের সাথে মেলানোর জন্য আপনার রিসোর্সড ডিকোরিয়ান্সটিতে এমন কিছু থাকা উচিত:

<DataTemplate DataType="{x:Type vm:DisplayViewModel}">
    <vw:DisplayView/>
</DataTemplate>

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

        var vm = new DisplayViewModel();
        vm.RequestClose += new RequestCloseHandler(DisplayViewModel_RequestClose);
        DialogViewModel = vm;

তারপরে আপনি ডায়ালগের ফলাফলটি কলব্যাকের মাধ্যমে পরিচালনা করতে পারবেন।

এটি কিছুটা জটিল বলে মনে হতে পারে তবে ভিত্তিটি তৈরি হয়ে গেলে এটি বেশ সোজা। আবার এটি আমার বাস্তবায়ন, আমি নিশ্চিত অন্যরাও রয়েছেন :)

আশা করি এটি সাহায্য করবে, এটি আমাকে বাঁচিয়েছে।


3

ঠিক আছে, সুতরাং এই প্রশ্নটি প্রায় 6 বছরের পুরানো এবং আমি এখনও এটি সঠিক উত্তর হিসাবে আমি কী মনে করি তা এখানে খুঁজে পাই না, সুতরাং আমাকে আমার "2 সেন্ট" ভাগ করার অনুমতি দিন ...

আমার কাছে এটি করার 2 টি উপায় রয়েছে, প্রথমটি হ'ল সহজটি ... দ্বিতীয়টি ডানদিকে, তাই আপনি যদি সঠিকটির সন্ধান করে থাকেন তবে কেবল # 1 এড়িয়ে যান এবং # 2 এ যান :

1. দ্রুত এবং সহজ (তবে সম্পূর্ণ নয়)

যদি আমার কেবল একটি ছোট প্রকল্প থাকে তবে আমি কখনও কখনও ভিউমোডেলে ক্লোজ উইন্ডো অ্যাকশন তৈরি করি:

        public Action CloseWindow { get; set; } // In MyViewModel.cs

এবং যে কেউ ভিউকে ক্রেট করে, বা এর কোডের পিছনে আমি কেবলমাত্র পদ্ধতিটি সেট করেছি সেই ক্রিয়াটি কল করবে:

(মনে রাখবেন এমভিভিএমটি ভিউ এবং ভিউমোডেলের পৃথকীকরণ সম্পর্কে রয়েছে ... ভিউ কোডটি বেহিনস এখনও দেখা হচ্ছে এবং যতক্ষণ না যথাযথ পৃথকীকরণ রয়েছে ততক্ষণ আপনি নিদর্শন লঙ্ঘন করছেন না)

যদি কিছু ভিউমোডেল একটি নতুন উইন্ডো তৈরি করে:

private void CreateNewView()
{
    MyView window = new MyView();
    window.DataContext = new MyViewModel
                             {
                                 CloseWindow = window.Close,
                             }; 
    window.ShowDialog();
}

বা যদি আপনি এটি আপনার প্রধান উইন্ডোতে চান তবে এটি কেবল আপনার দর্শকের নীচে রাখুন:

public MyView()
{
    InitializeComponent();           
    this.DataContext = new MainViewModel
                           {
                                CloseWindow = this.Close
                           };
}

আপনি যখন উইন্ডোটি বন্ধ করতে চান, কেবল আপনার ভিউমোডেলে অ্যাকশনটি কল করুন।


2. সঠিক উপায়

এখন এটি করার যথাযথ উপায় হ'ল প্রিজম (আইএমএইচও) ব্যবহার করা এবং এটির সমস্ত কিছুই এখানে পাওয়া যাবে

আপনি একটি ইন্টারঅ্যাকশন অনুরোধ করতে পারেন , আপনার নতুন উইন্ডোতে আপনার যা প্রয়োজন ডেটা তৈরি করুন, এটি লাঞ্চ করুন, এটি বন্ধ করুন এবং এমনকি ডেটা ফিরে পাবেন । এই সমস্ত encapsulated এবং এমভিভিএম অনুমোদিত। এমনকি উইন্ডোটি কীভাবে বন্ধ করা হয়েছিল তার একটি স্থিতি পাবেন , যেমন ব্যবহারকারী Canceledবা Accepted(ঠিক আছে বোতাম) উইন্ডোটি এবং আপনার প্রয়োজন হলে ডেটা ফিরে । এটি কিছুটা জটিল এবং উত্তর # 1, তবে এটি আরও অনেক সম্পূর্ণ এবং মাইক্রোসফ্ট দ্বারা প্রস্তাবিত প্যাটার্ন।

আমি যে লিঙ্কটি দিয়েছি তাতে সমস্ত কোড স্নিপেট এবং উদাহরণ রয়েছে, সুতরাং আমি এখানে কোনও কোড রাখার বিরক্ত করব না, কেবল প্রিজম কুইক স্টার্ট ডাউনলোডের নিবন্ধটি পড়ুন এবং এটি চালান, এটি কেবল আরও কিছুটা ভার্বোসকে আন্ডারট্যাড করা সত্যিই সহজ to এটি কাজ করুন, তবে সুবিধাগুলি কেবল একটি উইন্ডো বন্ধ করার চেয়ে বড় than


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

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

3
public partial class MyWindow: Window
{
    public ApplicationSelection()
    {
      InitializeComponent();

      MyViewModel viewModel = new MyViewModel();

      DataContext = viewModel;

      viewModel.RequestClose += () => { Close(); };

    }
}

public class MyViewModel
{

  //...Your code...

  public event Action RequestClose;

  public virtual void Close()
  {
    if (RequestClose != null)
    {
      RequestClose();
    }
  }

  public void SomeFunction()
  {
     //...Do something...
     Close();
  }
}

2

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


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

2

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

var windows = Application.Current.Windows;
for (var i=0;i< windows.Count;i++ )
    if (windows[i].DataContext == this)
        windows[i].Close();

এটি নিখুঁত নয় এবং এটি পরীক্ষা করা কঠিন হতে পারে (কারণ এটি একটি স্ট্যাটিককে উপহাস / আঘাত করা কঠিন) তবে এটি অন্যান্য সমাধানগুলির চেয়ে ক্লিনার (আইএমএইচও) is

এরিক


আমি আপনার সরল উত্তরটি দেখে খুব খুশি হয়েছি! কিন্তু এটি কাজ করে না! আমার ভিজ্যুয়াল বেসিকটি খুলতে এবং বন্ধ করতে হবে। আপনি কি ভিবিতে (উইন্ডোজ [i]। ডেটা কনটেক্সট == এটি) এর সমতুল্যতা জানেন?
এহসান

আমি শেষ পর্যন্ত পেয়েছি! :) ধন্যবাদ। উইন্ডোজ যদি (i) .ডাটা কনটেক্সট আমি হয়
এহসান

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

1

আমি জো হোয়াইটের সমাধানটি বাস্তবায়িত করেছি, তবে মাঝে মাঝে সমস্যাগুলির মধ্যে চলে এসেছি " উইন্ডোটি তৈরি হওয়ার পরে এবং ডায়লগ " ত্রুটি হিসাবে প্রদর্শিত হওয়ার পরেই ডায়ালগআরসাল্ট সেট করা যেতে পারে

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

আমার সমাধানটি ছিল উইন্ডোটির ইসলয়েড সম্পত্তিটি পরীক্ষা করতে ডায়ালগের ফলাফল পরিবর্তন করা :

private static void DialogResultChanged(
    DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    var window = d as Window;
    if (window != null && window.IsLoaded)
        window.DialogResult = e.NewValue as bool?;
}

এই পরিবর্তনটি করার পরে বন্ধ ডায়লগগুলির সাথে কোনও সংযুক্তি উপেক্ষা করা হয়।


ধন্যবাদ জনাব. আমার একই সমস্যা ছিল
ডিজে বার্ব

1

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

<UserControl ...
    xmlns:xw="clr-namespace:Wpf"
    xw:DialogCloser.DialogResult="{Binding DialogResult}">

এবং ডায়ালগক্লোজারটি যদি উইন্ডোতে নিজেই সংযুক্ত না থাকে তবে ব্যবহারকারী নিয়ন্ত্রণের উইন্ডোটি খুঁজে পাবেন।

namespace Wpf
{
  public static class DialogCloser
  {
    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached(
            "DialogResult",
            typeof(bool?),
            typeof(DialogCloser),
            new PropertyMetadata(DialogResultChanged));

    private static void DialogResultChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
      var window = d.GetWindow();
      if (window != null)
        window.DialogResult = e.NewValue as bool?;
    }

    public static void SetDialogResult(DependencyObject target, bool? value)
    {
      target.SetValue(DialogResultProperty, value);
    }
  }

  public static class Extensions
  {
    public static Window GetWindow(this DependencyObject sender_)
    {
      Window window = sender_ as Window;        
      return window ?? Window.GetWindow( sender_ );
    }
  }
}

1

আচরণটি এখানে সবচেয়ে সুবিধাজনক উপায়।

  • একদিকে থেকে, এটি প্রদত্ত ভিউমডেলের সাথে আবদ্ধ হতে পারে (এটি "ফর্মটি বন্ধ করুন!")

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

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


0

কেন শুধু কমান্ড প্যারামিটার হিসাবে উইন্ডোটি পাস করবেন না?

সি #:

 private void Cancel( Window window )
  {
     window.Close();
  }

  private ICommand _cancelCommand;
  public ICommand CancelCommand
  {
     get
     {
        return _cancelCommand ?? ( _cancelCommand = new Command.RelayCommand<Window>(
                                                      ( window ) => Cancel( window ),
                                                      ( window ) => ( true ) ) );
     }
  }

XAML:

<Window x:Class="WPFRunApp.MainWindow"
        x:Name="_runWindow"
...
   <Button Content="Cancel"
           Command="{Binding Path=CancelCommand}"
           CommandParameter="{Binding ElementName=_runWindow}" />

আমি মনে করি না যে ভিএমএলটিকে উইন্ডো প্রকারের মধ্যে সীমাবদ্ধ রাখা ভাল ধারণা।
শিমি ওয়েটজ্যান্ডলার

2
আমি মনে করি না Windowভিএমকে এমন ধরণের সীমাবদ্ধ করা ভাল ধারণা যা কিছুটা "খাঁটি" এমভিভিএম নয়। এই উত্তরটি দেখুন , যেখানে ভিএম কোনও Windowবস্তুর মধ্যে সীমাবদ্ধ নয় ।
শিমি ওয়েটজ্যান্ডলার

এইভাবে নির্ভরতাটি একটি বোতামে রাখা হচ্ছে যা অবশ্যই সর্বদা পরিস্থিতি হতে পারে না। এছাড়াও ভিউমোডেলে ইউআই টাইপ পাস করা একটি খারাপ অভ্যাস।
কিলো রেন

0

আর একটি সমাধান হ'ল ডায়লোগ্রিজল্টের মতো ভিউ মডেলে আইএনটিফাইপ্রোপার্টিচেন্জ দিয়ে সম্পত্তি তৈরি করা এবং তারপরে কোডের পিছনে এটি লিখুন:

public class SomeWindow: ChildWindow
{
    private SomeViewModel _someViewModel;

    public SomeWindow()
    {
        InitializeComponent();

        this.Loaded += SomeWindow_Loaded;
        this.Closed += SomeWindow_Closed;
    }

    void SomeWindow_Loaded(object sender, RoutedEventArgs e)
    {
        _someViewModel = this.DataContext as SomeViewModel;
        _someViewModel.PropertyChanged += _someViewModel_PropertyChanged;
    }

    void SomeWindow_Closed(object sender, System.EventArgs e)
    {
        _someViewModel.PropertyChanged -= _someViewModel_PropertyChanged;
        this.Loaded -= SomeWindow_Loaded;
        this.Closed -= SomeWindow_Closed;
    }

    void _someViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName == SomeViewModel.DialogResultPropertyName)
        {
            this.DialogResult = _someViewModel.DialogResult;
        }
    }
}

সবচেয়ে গুরুত্বপূর্ণ খণ্ডটি হ'ল _someViewModel_PropertyChangedDialogResultPropertyNameকিছু পাবলিক কনস্টিং স্ট্রিং হতে পারে SomeViewModel

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


0

আমি এই পথে যেতে হবে:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;    
using GalaSoft.MvvmLight.Messaging; 

// View

public partial class TestCloseWindow : Window
{
    public TestCloseWindow() {
        InitializeComponent();
        Messenger.Default.Register<CloseWindowMsg>(this, (msg) => Close());
    }
}

// View Model

public class MainViewModel: ViewModelBase
{
    ICommand _closeChildWindowCommand;

    public ICommand CloseChildWindowCommand {
        get {
            return _closeChildWindowCommand?? (_closeChildWindowCommand = new RelayCommand(() => {
                Messenger.Default.Send(new CloseWindowMsg());
        }));
        }
    }
}

public class CloseWindowMsg
{
}

0

আমি সমস্ত উত্তরগুলি পড়েছি তবে অবশ্যই বলতে হবে, তাদের বেশিরভাগই যথেষ্ট ভাল বা আরও খারাপ নয়।

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

এখানে সর্বাধিক গুরুত্বপূর্ণ অংশ রয়েছে:

//we will call this interface in our viewmodels
public interface IDialogService
{
    bool? ShowDialog(object dialogViewModel, string caption);
}

//we need to display logindialog from mainwindow
public class MainWindowViewModel : ViewModelBase
{
    public string Message {get; set;}
    public void ShowLoginCommandExecute()
    {
        var loginViewModel = new LoginViewModel();
        var dialogResult = this.DialogService.ShowDialog(loginViewModel, "Please, log in");

        //after dialog is closed, do someting
        if (dialogResult == true && loginViewModel.IsLoginSuccessful)
        {
            this.Message = string.Format("Hello, {0}!", loginViewModel.Username);
        }
    }
}


public class DialogService : IDialogService
{
    public bool? ShowDialog(object dialogViewModel, string caption)
    {
        var contentView = ViewLocator.GetView(dialogViewModel);
        var dlg = new DialogWindow
        {
            Title = caption
        };
        dlg.PART_ContentControl.Content = contentView;

        return dlg.ShowDialog();
    }
}

এটি কি সহজ নয়? ইভেন্টটিগ্রিগেটর বা অন্যান্য অনুরূপ সমাধানের চেয়ে আরও স্ট্রেটফর্ডওয়ার্ড, আরও পঠনযোগ্য এবং শেষ কিন্তু ডিবাগ করা সহজ নয়?

যেমন আপনি দেখতে পাচ্ছেন, আমার দেখার মডেলগুলিতে আমি এখানে আমার পোস্টে বর্ণিত ভিডমোডেল প্রথম পদ্ধতির ব্যবহার করেছি: ডাব্লুপিএফ-এর ভিউমোডেল থেকে ভিউ কল করার জন্য সেরা অনুশীলন

অবশ্যই, বাস্তব বিশ্বে DialogService.ShowDialogডায়ালগটি কনফিগার করার জন্য অবশ্যই আরও বিকল্প থাকতে হবে, যেমন বোতাম এবং কমান্ডগুলি তাদের কার্যকর করা উচিত। এটি করার বিভিন্ন উপায় রয়েছে, তবে এর সুযোগটি নেই :)


0

যদিও ভিউ মডেলের মাধ্যমে এটি কীভাবে করা যায় তার প্রশ্নের উত্তর দেয় না, তবে এটি কেবল এক্সএএমএল + মিশ্রিত এসডিকে ব্যবহার করে কীভাবে এটি করবেন তা দেখায়।

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

System.Windows.Interactivity.dll এবং Microsoft.Expression.Inteferences.dll

মাইক্রোসফ্ট.প্রকাশ

কিছু এক্সএএমএল:

<Window x:Class="Blah.Blah.MyWindow"
    ...
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
  ...>
 <StackPanel>
    <Button x:Name="OKButton" Content="OK">
       <i:Interaction.Triggers>
          <i:EventTrigger EventName="Click">
             <ei:ChangePropertyAction
                      TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                      PropertyName="DialogResult"
                      Value="True"
                      IsEnabled="{Binding SomeBoolOnTheVM}" />                                
          </i:EventTrigger>
    </Button>
    <Button x:Name="CancelButton" Content="Cancel">
       <i:Interaction.Triggers>
          <i:EventTrigger EventName="Click">
             <ei:ChangePropertyAction
                      TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                      PropertyName="DialogResult"
                      Value="False" />                                
          </i:EventTrigger>
    </Button>

    <Button x:Name="CloseButton" Content="Close">
       <i:Interaction.Triggers>
                <i:EventTrigger EventName="Click">
                    <!-- method being invoked should be void w/ no args -->
                    <ei:CallMethodAction
                        TargetObject="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                        MethodName="Close" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
    </Button>
 <StackPanel>
</Window>

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


0

এখানে সরল বাগ মুক্ত সমাধান (উত্স কোড সহ), এটি আমার পক্ষে কাজ করছে।

  1. এ থেকে আপনার ভিউমোডেলটি বের করুন INotifyPropertyChanged

  2. একটি লক্ষণীয় সম্পত্তি তৈরি করুন CloseDialog ViewModel মধ্যে

    public void Execute()
    {
        // Do your task here
    
        // if task successful, assign true to CloseDialog
        CloseDialog = true;
    }
    
    private bool _closeDialog;
    public bool CloseDialog
    {
        get { return _closeDialog; }
        set { _closeDialog = value; OnPropertyChanged(); }
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    private void OnPropertyChanged([CallerMemberName]string property = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }

    }

  3. এই সম্পত্তি পরিবর্তনের জন্য একটি হ্যান্ডলার সংযুক্ত করুন

        _loginDialogViewModel = new LoginDialogViewModel();
        loginPanel.DataContext = _loginDialogViewModel;
        _loginDialogViewModel.PropertyChanged += OnPropertyChanged;
  4. এখন আপনি প্রায় সম্পন্ন হয়েছে। ইভেন্ট হ্যান্ডলার মেকDialogResult = true

    protected void OnPropertyChanged(object sender, PropertyChangedEventArgs args)
    {
        if (args.PropertyName == "CloseDialog")
        {
            DialogResult = true;
        }
    }

0

Dependency Propertyআপনার View/ যে কোনও একটি তৈরি করুন UserControl(বা Windowআপনি বন্ধ করতে চান)। নীচের মত:

 public bool CloseTrigger
        {
            get { return (bool)GetValue(CloseTriggerProperty); }
            set { SetValue(CloseTriggerProperty, value); }
        }

        public static readonly DependencyProperty CloseTriggerProperty =
            DependencyProperty.Register("CloseTrigger", typeof(bool), typeof(ControlEventBase), new PropertyMetadata(new PropertyChangedCallback(OnCloseTriggerChanged)));

        private static void OnCloseTriggerChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
        {
            //write Window Exit Code
        }

এবং এটি আপনার ভিউমোডেলের সম্পত্তি থেকে বাঁধুন :

<Window x:Class="WpfStackOverflowTempProject.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"  Width="525"
        CloseTrigger="{Binding Path=CloseWindow,Mode=TwoWay}"

সম্পত্তি এতে VeiwModel:

private bool closeWindow;

    public bool CloseWindow
    {
        get { return closeWindow; }
        set 
        { 
            closeWindow = value;
            RaiseChane("CloseWindow");
        }
    }

এখন CloseWindowভিউমোডেলে মান পরিবর্তন করে ঘনিষ্ঠ অপারেশনটি ট্রিগার করুন । :)


-2

যেখানে আপনার উইন্ডোটি বন্ধ করতে হবে, কেবল এটি ভিউ মডেলটিতে রেখে দিন:

TA-দা

  foreach (Window window in Application.Current.Windows)
        {
            if (window.DataContext == this)
            {
                window.Close();
                return;
            }
        }

একটি ভিউমোডেলটিতে কোনওভাবেই কোনও ইউআইএলমেন্ট থাকা উচিত নয় , কারণ এটি বাগ তৈরি করতে পারে
ওয়াইম্যাক্সেক্স

যদি ডেটা কনটেক্সটটি উত্তরাধিকারসূত্রে একাধিক উইন্ডো হয়ে থাকে?
কিলো রেন

তবে, এটি পুরোপুরি এমভিভিএম নয়।
আলেকজান্দ্রু ডিকু

-10
Application.Current.MainWindow.Close() 

তাতেই চলবে!


3
-1 কেবলমাত্র সত্য যদি আপনি উইন্ডোটি বন্ধ করতে চান তবে মূল উইন্ডোটি ... লগইন কথোপকথনের জন্য খুব সম্ভবত সম্ভাবনা অনুমান ...
সার্ফেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.