ভিউমোডেল থেকে উইন্ডোটি বন্ধ করুন


97

আমি window controlকোনও ব্যবহারকারীকে WPFআমি তৈরি করছি এমন একটি অ্যাপ্লিকেশনটিতে লগইন করতে অনুমতি দিয়ে একটি লগইন তৈরি করছি।

এ পর্যন্ত, আমি একটি পদ্ধতি যা চেক ব্যবহারকারীর জন্য সঠিক পরিচয়পত্র মধ্যে প্রবেশ করেছে কিনা তৈরি করেছেন usernameএবং passwordএকটি textboxলগইন স্ক্রীনে, উপর bindingদুই properties

আমি এ জাতীয় boolপদ্ধতি তৈরি করে এটি অর্জন করেছি;

public bool CheckLogin()
{
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome " + user.Username + ", you have successfully logged in.");

        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
}

public ICommand ShowLoginCommand
{
    get
    {
        if (this.showLoginCommand == null)
        {
            this.showLoginCommand = new RelayCommand(this.LoginExecute, null);
        }
        return this.showLoginCommand;
    }
}

private void LoginExecute()
{
    this.CheckLogin();
} 

আমার কাছে এমন একটি রয়েছে commandযা আমি bindআমার বোতামের xamlমতো করে রাখি ;

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" />

আমি যখন ব্যবহারকারীর নাম এবং পাসওয়ার্ড লিখি এটি অনুমোদিত কোড কার্যকর করে, এটি সঠিক হোক বা ভুল। ব্যবহারকারীর নাম এবং পাসওয়ার্ড উভয়ই সঠিক হলে আমি কীভাবে ভিউমোডেল থেকে এই উইন্ডোটি বন্ধ করব?

আমি এর আগে একটি ব্যবহার করার চেষ্টা করেছি dialog modalকিন্তু এটি কার্যকর হয়নি। তদুপরি, আমার app.xaml এর মধ্যে আমি নীচের মতো কিছু করেছি, যা লগইন পৃষ্ঠাটি প্রথমে লোড করে, তারপরে একবার সত্য হয়ে যায়, আসল অ্যাপ্লিকেশনটি লোড করে।

private void ApplicationStart(object sender, StartupEventArgs e)
{
    Current.ShutdownMode = ShutdownMode.OnExplicitShutdown;

    var dialog = new UserView();

    if (dialog.ShowDialog() == true)
    {
        var mainWindow = new MainWindow();
        Current.ShutdownMode = ShutdownMode.OnMainWindowClose;
        Current.MainWindow = mainWindow;
        mainWindow.Show();
    }
    else
    {
        MessageBox.Show("Unable to load application.", "Error", MessageBoxButton.OK);
        Current.Shutdown(-1);
    }
}

প্রশ্ন: আমি Window controlভিউমোডেল থেকে লগইনটি কীভাবে বন্ধ করতে পারি ?

আগাম ধন্যবাদ.


উত্তর:


154

আপনি উইন্ডোটি ব্যবহার করে আপনার ভিউমোডেলটিতে পাস করতে পারেন CommandParameter। নীচে আমার উদাহরণ দেখুন।

আমি একটি CloseWindowপদ্ধতি প্রয়োগ করেছি যা একটি উইন্ডোজকে প্যারামিটার হিসাবে গ্রহণ করে এবং এটি বন্ধ করে দেয়। উইন্ডোটি ভিউমোডেলের মাধ্যমে দিয়ে গেছে CommandParameter। নোট করুন যে আপনার x:Nameউইন্ডোটির জন্য একটি সংজ্ঞা দেওয়া দরকার যা কাছাকাছি হওয়া উচিত। আমার এক্সএএমএল উইন্ডোতে আমি এই পদ্ধতিটি কল Commandকরে ভিউমোডেল ব্যবহার করে উইন্ডোটিকে প্যারামিটার হিসাবে নিজেই পাস করি CommandParameter

Command="{Binding CloseWindowCommand, Mode=OneWay}" 
CommandParameter="{Binding ElementName=TestWindow}"

ভিউমোডেল

public RelayCommand<Window> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
}

private void CloseWindow(Window window)
{
    if (window != null)
    {
       window.Close();
    }
}

দেখুন

<Window x:Class="ClientLibTestTool.ErrorView"
        x:Name="TestWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:localization="clr-namespace:ClientLibTestTool.ViewLanguages"
        DataContext="{Binding Main, Source={StaticResource Locator}}"
        Title="{x:Static localization:localization.HeaderErrorView}"
        Height="600" Width="800"
        ResizeMode="NoResize"
        WindowStartupLocation="CenterScreen">
    <Grid> 
        <Button Content="{x:Static localization:localization.ButtonClose}" 
                Height="30" 
                Width="100" 
                Margin="0,0,10,10" 
                IsCancel="True" 
                VerticalAlignment="Bottom" 
                HorizontalAlignment="Right" 
                Command="{Binding CloseWindowCommand, Mode=OneWay}" 
                CommandParameter="{Binding ElementName=TestWindow}"/>
    </Grid>
</Window>

মনে রাখবেন যে আমি এমভিভিএম হালকা কাঠামো ব্যবহার করছি তবে অধ্যক্ষটি প্রতিটি ডাব্লুপিএফ অ্যাপ্লিকেশনটিতে প্রযোজ্য।

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

এমভিভিএম কনফর্ম সমাধান (প্রাক্তন EDIT2)

ব্যবহারকারী ক্রোনো মন্তব্য বিভাগে একটি বৈধ পয়েন্ট উল্লেখ করেছেন:

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

একটি ঘনিষ্ঠ পদ্ধতিযুক্ত ইন্টারফেস প্রবর্তন করে আপনি এটি ঠিক করতে পারেন।

ইন্টারফেস:

public interface ICloseable
{
    void Close();
}

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

ভিউমোডেল

public RelayCommand<ICloseable> CloseWindowCommand { get; private set; }

public MainViewModel()
{
    this.CloseWindowCommand = new RelayCommand<IClosable>(this.CloseWindow);
}

private void CloseWindow(ICloseable window)
{
    if (window != null)
    {
        window.Close();
    }
}

ICloseableআপনার দৃষ্টিভঙ্গিতে আপনাকে ইন্টারফেসটি রেফারেন্স এবং প্রয়োগ করতে হবে

দেখুন (পিছনে কোড)

public partial class MainWindow : Window, ICloseable
{
    public MainWindow()
    {
        InitializeComponent();
    }
}

মূল প্রশ্নের উত্তর: (প্রাক্তন EDIT1)

আপনার লগইন বোতাম (যোগ করা কমান্ডপ্যারামিটার):

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding ShowLoginCommand}" CommandParameter="{Binding ElementName=LoginWindow}"/>

তোমার গোপন সংকেত:

 public RelayCommand<Window> CloseWindowCommand { get; private set; } // the <Window> is important for your solution!

 public MainViewModel() 
 {
     //initialize the CloseWindowCommand. Again, mind the <Window>
     //you don't have to do this in your constructor but it is good practice, thought
     this.CloseWindowCommand = new RelayCommand<Window>(this.CloseWindow);
 }

 public bool CheckLogin(Window loginWindow) //Added loginWindow Parameter
 {
    var user = context.Users.Where(i => i.Username == this.Username).SingleOrDefault();

    if (user == null)
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
    else if (this.Username == user.Username || this.Password.ToString() == user.Password)
    {
        MessageBox.Show("Welcome "+ user.Username + ", you have successfully logged in.");
        this.CloseWindow(loginWindow); //Added call to CloseWindow Method
        return true;
    }
    else
    {
        MessageBox.Show("Unable to Login, incorrect credentials.");
        return false;
    }
 }

 //Added CloseWindow Method
 private void CloseWindow(Window window)
 {
     if (window != null)
     {
         window.Close();
     }
 }

4
@ জোয়েল আপডেটের জন্য ধন্যবাদ। একটি শেষ প্রশ্ন, উইন্ডোটির প্যারামিটার গ্রহণের পদ্ধতিটির কারণে, এবং আমি যখন আমার কমান্ডের মধ্যে সেই পদ্ধতিটি কল করি তখন এটি একটি পরামিতি প্রত্যাশা করে, আমি কি একটি স্থানীয় উইন্ডো প্যারামিটার তৈরি করব যা পদ্ধতির জন্য ডাকা হয়, যেমন; private void LoginExecute(){this.CheckLogin();}<- চেকলগিনকে পরামিতি নেওয়া দরকার।
WPFNoob

দুঃখিত আমি বুঝতে পারি না, আপনি কি নিজের প্রশ্নটি কিছুটা স্পষ্ট করে বলতে পারছেন?
জোয়েল

14
আপনি যদি আপনার উইন্ডোগুলির নামকরণ পছন্দ না করেন তবে আপনি এই জাতীয় প্যারামিটারটিও আবদ্ধ করতে পারেন:CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
জ্যাকো ডিলিম্যান

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

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

35

যখন আমি এটি করার দরকার হয় তখন আমি সাধারণত ভিউ মডেলটিতে একটি ইভেন্ট রাখি এবং তারপরে Window.Close()যখন ভিউ মডেলটিকে উইন্ডোতে আবদ্ধ করি তখন এটি পর্যন্ত আপ হয়

public class LoginViewModel
{
    public event EventHandler OnRequestClose;

    private void Login()
    {
        // Login logic here
        OnRequestClose(this, new EventArgs());
    }
}

এবং লগইন উইন্ডো তৈরি করার সময়

var vm = new LoginViewModel();
var loginWindow = new LoginWindow
{
    DataContext = vm
};
vm.OnRequestClose += (s, e) => loginWindow.Close();

loginWindow.ShowDialog(); 

11
বেনামে প্রতিনিধিটি দ্রুত লেখা হয়, তবে লক্ষণীয় যে ইভেন্টটি নিবন্ধভুক্ত করা যাবে না (যা কোনও সমস্যা হতে পারে বা নাও হতে পারে)। সাধারণত একটি পূর্ণ ইভেন্ট ইভেন্ট হ্যান্ডলার দিয়ে ভাল off
ম্যাথিউ গাইন্ডন

4
আমি এটি সবচেয়ে পছন্দ করি। উইন্ডোটি প্রদর্শন করার সময় বিশেষ প্রক্রিয়াজাতকরণ এড়াতে খুব শক্ত (যেমন Loaded, ContentRenderedমূল উইন্ডো, ডায়ালগ পরিষেবাগুলি ইত্যাদির জন্য), ভিউমোডেল ইভেন্টের মাধ্যমে এতে কিছুটা যুক্ত করা আমার পক্ষে বেশ পরিষ্কার। 3 লাইনের কোডের কোনও পুনরায় ব্যবহারযোগ্যতা সমাধানের দরকার নেই। PS: খাঁটি এমভিভিএম যাইহোক নার্দের জন্য।
সিনাটার

ছেলে এই আমাকে সাহায্য করেছে।
দিমিত্রি

4
এটি গৃহীত উত্তরের চেয়ে অনেক ভাল, কারণ এটি এমভিভিএম প্যাটার্নটি ভঙ্গ করে না।
ভূত

35

এমভিভিএম থাকা অবস্থায়, আমি মনে করি মিশ্রিত এসডিকে (সিস্টেম. উইন্ডোস.ইন্টেরাকটিভিটি) বা প্রিজমের কাছ থেকে একটি কাস্টম ইন্টারঅ্যাকশন অনুরোধটি এই ধরণের পরিস্থিতির জন্য সত্যই কার্যকর হতে পারে।

যদি আচরণের পথে যেতে হয় তবে সাধারণ ধারণাটি এখানে:

public class CloseWindowBehavior : Behavior<Window>
{
    public bool CloseTrigger
    {
        get { return (bool)GetValue(CloseTriggerProperty); }
        set { SetValue(CloseTriggerProperty, value); }
    }

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

    private static void OnCloseTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = d as CloseWindowBehavior;

        if (behavior != null)
        {
            behavior.OnCloseTriggerChanged();
        }
    }

    private void OnCloseTriggerChanged()
    {
        // when closetrigger is true, close the window
        if (this.CloseTrigger)
        {
            this.AssociatedObject.Close();
        }
    }
}

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

<Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:local="clr-namespace:TestApp"
        Title="MainWindow" Height="350" Width="525">
    <i:Interaction.Behaviors>
        <local:CloseWindowBehavior CloseTrigger="{Binding CloseTrigger}" />
    </i:Interaction.Behaviors>

    <Grid>

    </Grid>
</Window>

অবশেষে, আপনার ডেটা কনটেক্সট / ভিউমোডেলের এমন একটি সম্পত্তি থাকবে যা আপনি উইন্ডোটি এভাবে বন্ধ করতে চাইলে সেট করেছিলেন:

public class MainWindowViewModel : INotifyPropertyChanged
{
    private bool closeTrigger;

    /// <summary>
    /// Gets or Sets if the main window should be closed
    /// </summary>
    public bool CloseTrigger
    {
        get { return this.closeTrigger; }
        set
        {
            this.closeTrigger = value;
            RaisePropertyChanged(nameof(CloseTrigger));
        }
    }

    public MainWindowViewModel()
    {
        // just setting for example, close the window
        CloseTrigger = true;
    }

    protected void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

(আপনার উইন্ডোটি সেট করুন D ডেটা কনটেক্সট = নতুন মেইন উইন্ডোভিউ মডেল ())


উত্তরের জন্য ধন্যবাদ @ স্টিভ, আপনি ক্লোজ্ট ট্রিগারকে একটি booleanমানের সাথে বাঁধাই সম্পর্কে উল্লেখ করেছিলেন । যখন আপনি এটি বলেছিলেন, আপনি কি DataTriggerএটি অর্জনের জন্য আমার তৈরির অর্থ দিয়েছিলেন?
WPFNoob

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

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

কোনও ক্রিয়া সম্পাদনের জন্য সম্পত্তিকে সত্যে নির্ধারণ করা দুর্গন্ধযুক্ত আইএমও।
জোশ নো

22

এটি দেরী হতে পারে, কিন্তু এখানে আমার উত্তর

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

4
কেন এটি আসল উত্তর নয়?
ব্যবহারকারী 2529011

4
@ user2529011 কিছু অন্তত অভিযোগ যে viewmodel Application.Current.Windows সম্পর্কে কিছু জানেন করা উচিত নয়
gusmally মনিকা সমর্থন

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

13

বেশ কয়েকটি এখানে আমি বেশ কয়েকটি প্রকল্পে ব্যবহার করেছি। এটি হ্যাকের মতো দেখাচ্ছে তবে এটি ঠিকঠাক কাজ করে।

public class AttachedProperties : DependencyObject //adds a bindable DialogResult to window
{
    public static readonly DependencyProperty DialogResultProperty = 
        DependencyProperty.RegisterAttached("DialogResult", typeof(bool?), typeof(AttachedProperties), 
        new PropertyMetaData(default(bool?), OnDialogResultChanged));

    public bool? DialogResult
    {
        get { return (bool?)GetValue(DialogResultProperty); }
        set { SetValue(DialogResultProperty, value); }
    }

    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var window = d as Window;
        if (window == null)
            return;

        window.DialogResult = (bool?)e.NewValue;
    }
}

এখন আপনি DialogResultকোনও ভিএম-তে বাঁধাই করতে পারেন এবং কোনও সম্পত্তির মূল্য সেট করতে পারেন । Windowবন্ধ হয়ে যাবে, যখন মান সেট করা হয়।

<!-- Assuming that the VM is bound to the DataContext and the bound VM has a property DialogResult -->
<Window someNs:AttachedProperties.DialogResult={Binding DialogResult} />

এটি আমাদের উত্পাদন পরিবেশে কী চলছে তার বিমূর্ততা

<Window x:Class="AC.Frontend.Controls.DialogControl.Dialog"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:DialogControl="clr-namespace:AC.Frontend.Controls.DialogControl" 
        xmlns:hlp="clr-namespace:AC.Frontend.Helper"
        MinHeight="150" MinWidth="300" ResizeMode="NoResize" SizeToContent="WidthAndHeight"
        WindowStartupLocation="CenterScreen" Title="{Binding Title}"
        hlp:AttachedProperties.DialogResult="{Binding DialogResult}" WindowStyle="ToolWindow" ShowInTaskbar="True"
        Language="{Binding UiCulture, Source={StaticResource Strings}}">
        <!-- A lot more stuff here -->
</Window>

যেমন আপনি দেখতে পাচ্ছেন, আমি xmlns:hlp="clr-namespace:AC.Frontend.Helper"প্রথমে নেমস্পেস এবং তার পরে বাইন্ডিং ঘোষণা করছি hlp:AttachedProperties.DialogResult="{Binding DialogResult}"

AttachedPropertyসৌন্দর্য এটি পছন্দ। আমি গতকাল যা পোস্ট করেছি তা নয়, তবে আইএমএইচও এর কোনও প্রভাব থাকতে হবে না।

public class AttachedProperties
{
    #region DialogResult

    public static readonly DependencyProperty DialogResultProperty =
        DependencyProperty.RegisterAttached("DialogResult", typeof (bool?), typeof (AttachedProperties), new PropertyMetadata(default(bool?), OnDialogResultChanged));

    private static void OnDialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var wnd = d as Window;
        if (wnd == null)
            return;

        wnd.DialogResult = (bool?) e.NewValue;
    }

    public static bool? GetDialogResult(DependencyObject dp)
    {
        if (dp == null) throw new ArgumentNullException("dp");

        return (bool?)dp.GetValue(DialogResultProperty);
    }

    public static void SetDialogResult(DependencyObject dp, object value)
    {
        if (dp == null) throw new ArgumentNullException("dp");

        dp.SetValue(DialogResultProperty, value);
    }

    #endregion
}

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

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

যে পরিষ্কার করার জন্য ধন্যবাদ। দেখা গেল যে আমি ভুল নামস্থানটি ডাকছিলাম: এস। datatriggerকাজটি করার জন্য আমাকে কি কেবল একটি তৈরি করে এটিকে বোতামে বরাদ্দ করতে হবে? আবার দু: খিত প্রশ্নের জন্য দুঃখিত।
WPFNoob

ধন্যবাদ - ভাল, আমি আমার সম্পর্কে অনেক বেশি প্রশ্ন জিজ্ঞাসা করেছি যা নির্বোধ এবং বোকা মনে হতে পারে এবং মানুষের সময় নষ্ট করে! তবে আমার প্রশ্নে ফিরে যাচ্ছি। আপনি উল্লিখিত সমস্ত কিছুর পরে, আমি কীভাবে উইন্ডোটি বন্ধ করব? একটি সত্য ব্যবহার করুন DataTrigger¬ and setting value ?
WPFNoob

4
আচ্ছা সেই অংশ, আমি তোমার কাছে চলে যাচ্ছি। ; O) ভাবুন DataContextএর Dialog। আমি আশা করবে, VM- র সেট হিসাবে DataContextকমান্ড, যা সম্পত্তি সেট করে উপলব্ধ DialogResultবা যাই হোক না কেন আপনি বাধ্য থাকেন trueবা false, যাতে Dialogবন্ধ হয়ে যায়।
ডিএনএইচ

13

সহজ পথ

public interface IRequireViewIdentification
{
    Guid ViewID { get; }
}

ভিউমোডেলে প্রয়োগ করুন

public class MyViewVM : IRequireViewIdentification
{
    private Guid _viewId;

    public Guid ViewID
    {
        get { return _viewId; }
    }

    public MyViewVM()
    {
        _viewId = Guid.NewGuid();
    }
}

সাধারণ উইন্ডো ম্যানেজার সহায়ক

public static class WindowManager
{
    public static void CloseWindow(Guid id)
    {
        foreach (Window window in Application.Current.Windows)
        {
            var w_id = window.DataContext as IRequireViewIdentification;
            if (w_id != null && w_id.ViewID.Equals(id))
            {
                window.Close();
            }
        }
    }
}

এবং ভিউ মডেলটিতে এটি বন্ধ করুন

WindowManager.CloseWindow(ViewID);

খুব সুন্দর সমাধান।
ডনবয়েটনট

উইন ম্যানেজার আলিটল পরিবর্তন করে উইল পাবলিক স্ট্যাটিক শূন্যতা ক্লোজ উইন্ডো বন্ধ করার সময় ডায়লগসাল্ট সেট করতে (গাইড আইডি, বুল ডায়ালগেররসাল্ট) {ফরচ (অ্যাপ্লিকেশনে উইন্ডো উইন্ডো। ক্রন্ট. উইন্ডোজ) {var w_id = উইন্ডো।ডাটা কনটেক্সট আইআরকিয়ারভিউআইডেন্টিফিকেশন হিসাবে; if (w_id! = নাল && w_id.ViewID.Equals (id)) {উইন্ডো.ডায়ালগআরসাল্ট = কথোপকথন ফলাফল; উইন্ডো.ক্লোজ (); it} it এটিকে কল করুন: উইন্ডো ম্যানেজ.ক্লস উইন্ডো (_ ভিউআইডি, সত্য);
লেভেরো

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

4

এখানে ইভেন্টের পরিবর্তে এমভিভিএম লাইট মেসেঞ্জার ব্যবহারের একটি সাধারণ উদাহরণ। একটি বোতাম ক্লিক করা হলে ভিউ মডেল একটি ঘনিষ্ঠ বার্তা পাঠায়:

    public MainViewModel()
    {
        QuitCommand = new RelayCommand(ExecuteQuitCommand);
    }

    public RelayCommand QuitCommand { get; private set; }

    private void ExecuteQuitCommand() 
    {
        Messenger.Default.Send<CloseMessage>(new CloseMessage());
    }

তারপরে এটি উইন্ডোর পিছনের কোডে প্রাপ্ত হয়।

    public Main()
    {   
        InitializeComponent();
        Messenger.Default.Register<CloseMessage>(this, HandleCloseMessage);
    }

    private void HandleCloseMessage(CloseMessage closeMessage)
    {
        Close();
    }

আপনি কি দয়া করে পরামর্শ দিতে পারেন, যেখানে আমি ক্লোজমেসেজ বাস্তবায়ন পেতে পারি?
রোমান হে

ক্লোজমেসেজটি কেবল একটি খালি ক্লাস, প্রেরিত বার্তার প্রকারটি সনাক্ত করতে ব্যবহৃত হয়। (
এটিতে

4

কেমন হয় এই ?

ভিউমোডেল:

class ViewModel
{
    public Action CloseAction { get; set; }
    private void Stuff()
    {
       // Do Stuff
       CloseAction(); // closes the window
    }
}

আপনার ভিউমোডেলে উপরের উদাহরণের মতো উইন্ডোটি বন্ধ করতে ক্লোজঅ্যাকশন () ব্যবহার করুন।

দেখুন:

public View()
{
    InitializeComponent();
    ViewModel vm = new ViewModel (); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if (vm.CloseAction == null)
        vm.CloseAction = new Action(() => this.Close());
}

4

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

ব্লগ

ভিউমোডেলে:

...

public bool CanClose { get; set; }

private RelayCommand closeCommand;
public ICommand CloseCommand
{
    get
    {
        if(closeCommand == null)
        (
            closeCommand = new RelayCommand(param => Close(), param => CanClose);
        )
    }
}

public void Close()
{
    this.Close();
}

...

ভিউমোডেলে একটি অ্যাকশন সম্পত্তি যুক্ত করুন, তবে এটিকে ভিউ কোড-পিছনের ফাইল থেকে সংজ্ঞায়িত করুন। এটি আমাদেরকে ভিউমোডেলে এমন একটি রেফারেন্সকে গতিশীলরূপে সংজ্ঞায়িত করতে দেয় যা দর্শনকে নির্দেশ করে।

ভিউমোডেলে, আমরা সহজভাবে যুক্ত করব:

public Action CloseAction { get; set; }

এবং ভিউতে, আমরা এটিকে এরূপ হিসাবে সংজ্ঞায়িত করব:

public View()
{
    InitializeComponent() // this draws the View
    ViewModel vm = new ViewModel(); // this creates an instance of the ViewModel
    this.DataContext = vm; // this sets the newly created ViewModel as the DataContext for the View
    if ( vm.CloseAction == null )
        vm.CloseAction = new Action(() => this.Close());
}

লিঙ্কটি নষ্ট হয়েছে: /
মনোরমভাবে মনিকাকে সমর্থন করে

@ গুগলভাবে আপনি কি নিশ্চিত? আমি সাধারনত
সেরলোক

2

আপনি ভিউমোডেলে এর মতো নতুন ইভেন্ট হ্যান্ডলার তৈরি করতে পারেন।

public event EventHandler RequestClose;

    protected void OnRequestClose()
    {
        if (RequestClose != null)
            RequestClose(this, EventArgs.Empty);
    }

তারপরে প্রস্থানকমান্ডের জন্য রিলে কম্যান্ড নির্ধারণ করুন।

private RelayCommand _CloseCommand;
    public ICommand CloseCommand
    {
        get
        {
            if(this._CloseCommand==null)
                this._CloseCommand=new RelayCommand(CloseClick);
            return this._CloseCommand;
        }
    }

    private void CloseClick(object obj)
    {
        OnRequestClose();
    }

তারপরে এক্সএএমএল ফাইল সেট করুন

<Button Command="{Binding CloseCommand}" />

Xaml.cs ফাইলে ডেটা কনটেক্সট সেট করুন এবং আমরা তৈরি ইভেন্টটি সাবস্ক্রাইব করুন।

public partial class MainWindow : Window
{
    private ViewModel mainViewModel = null;
    public MainWindow()
    {
        InitializeComponent();
        mainViewModel = new ViewModel();
        this.DataContext = mainViewModel;
        mainViewModel.RequestClose += delegate(object sender, EventArgs args) { this.Close(); };
    }
}

আমি ইভেন্টটির পরিবর্তে একটি এমভিভিএম লাইট ম্যাসেঞ্জার ব্যবহার করেছি।
হামিশ গন

1

আমার লাভজনক উপায়টি ভিউমোডলে ইভেন্টটি ঘোষণা করুন এবং নীচের মতো মিশ্রণ ইনভোকমথোডঅ্যাকশনটি ব্যবহার করুন।

নমুনা ভিউমোডেল

public class MainWindowViewModel : BindableBase, ICloseable
{
    public DelegateCommand SomeCommand { get; private set; }
    #region ICloseable Implementation
    public event EventHandler CloseRequested;        

    public void RaiseCloseNotification()
    {
        var handler = CloseRequested;
        if (handler != null)
        {
            handler.Invoke(this, EventArgs.Empty);
        }
    }
    #endregion

    public MainWindowViewModel()
    {
        SomeCommand = new DelegateCommand(() =>
        {
            //when you decide to close window
            RaiseCloseNotification();
        });
    }
}

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

internal interface ICloseable
{
    event EventHandler CloseRequested;
}

আইসি্লোজেবলের ব্যবহার

var viewModel = new MainWindowViewModel();
        // As service is generic and don't know whether it can request close event
        var window = new Window() { Content = new MainView() };
        var closeable = viewModel as ICloseable;
        if (closeable != null)
        {
            closeable.CloseRequested += (s, e) => window.Close();
        }

এবং নীচে Xaml, আপনি এই এক্সএএমএলটি ব্যবহার করতে পারেন এমনকি যদি আপনি ইন্টারফেস বাস্তবায়ন না করেন তবে এটি ক্লোজারকুইস্টে বাড়াতে আপনার ভিউ মডেলটির প্রয়োজন হবে।

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPFRx"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" 
xmlns:ViewModels="clr-namespace:WPFRx.ViewModels" x:Name="window" x:Class="WPFRx.MainWindow"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525" 
d:DataContext="{d:DesignInstance {x:Type ViewModels:MainWindowViewModel}}">

<i:Interaction.Triggers>
    <i:EventTrigger SourceObject="{Binding Mode=OneWay}" EventName="CloseRequested" >
        <ei:CallMethodAction TargetObject="{Binding ElementName=window}" MethodName="Close"/>
    </i:EventTrigger>
</i:Interaction.Triggers>

<Grid>
    <Button Content="Some Content" Command="{Binding SomeCommand}" Width="100" Height="25"/>
</Grid>


1

আপনি Messengerএমভিভিএমএললাইট টুলকিট থেকে ব্যবহার করতে পারেন । আপনার ViewModelবার্তায় এই বার্তা প্রেরণ করুন:
Messenger.Default.Send(new NotificationMessage("Close"));
তারপরে আপনার উইন্ডোজ কোডের পিছনে, পরে InitializeComponent, এই বার্তার জন্য নিবন্ধন করুন:

Messenger.Default.Register<NotificationMessage>(this, m=>{
    if(m.Notification == "Close") 
    {
        this.Close();
    }
   });

আপনি এখানে এমভিভিএমএললাইট টুলকিট সম্পর্কে আরও জানতে পারেন: কোডেপ্লেক্সে এমভিভিএমএলএইচ টুলকিট

লক্ষ্য করুন যে এমভিভিএম-এ "কোনও নিয়ম অনুসারে কোনও কোড-ব্যাকড" নেই এবং আপনি ভিউ কোড-পিছনে বার্তাগুলির জন্য নিবন্ধকরণ করতে পারেন।


0

ইহা সহজ. আপনি লগইনের জন্য নিজস্ব ভিউমোডেল ক্লাস তৈরি করতে পারেন - লগইনভিউমোডেল। আপনি ভিউ var ডায়ালগ তৈরি করতে পারেন = নতুন ইউজারভিউ (); আপনার লগইনভিউমোডেলের ভিতরে। এবং আপনি কমান্ড লগইনকমকে বোতামে সেট আপ করতে পারেন।

<Button Name="btnLogin" IsDefault="True" Content="Login" Command="{Binding LoginCommand}" />

এবং

<Button Name="btnCancel" IsDefault="True" Content="Login" Command="{Binding CancelCommand}" />

ভিউমোডেল ক্লাস:

public class LoginViewModel
{
    Window dialog;
    public bool ShowLogin()
    {
       dialog = new UserView();
       dialog.DataContext = this; // set up ViewModel into View
       if (dialog.ShowDialog() == true)
       {
         return true;
       }

       return false;
    }

    ICommand _loginCommand
    public ICommand LoginCommand
    {
        get
        {
            if (_loginCommand == null)
                _loginCommand = new RelayCommand(param => this.Login());

            return _loginCommand;
        }
    }

    public void CloseLoginView()
    {
            if (dialog != null)
          dialog.Close();
    }   

    public void Login()
    {
        if(CheckLogin()==true)
        {
            CloseLoginView();         
        }
        else
        {
          // write error message
        }
    }

    public bool CheckLogin()
    {
      // ... check login code
      return true;
    }
}

4
হ্যাঁ, এটিও একটি কার্যকর সমাধান। তবে আপনি যদি এমভিভিএম এবং ভিএম এবং দৃষ্টিভঙ্গির ডিকপলিংয়ে লেগে থাকতে চান তবে আপনি এই প্যাটার্নটি ভঙ্গ করতে চলেছেন।
ডিএনএইচ

হাই @ মিসাক - আপনার সমাধানটি (অন্যান্য উত্তরগুলির মতো) বাস্তবায়নের চেষ্টা করে, এটি Object reference not set to an instance of an object.ক্লোজলোগিনভিউ পদ্ধতির জন্য একটি ছুড়ে ফেলে । কোন সমস্যা কীভাবে সমাধান করবেন?
ডাব্লুপিএফনুব

@WPFNoob - আমি আবার এই সমাধানটি ট্রে করছি solution উদাহরণ সঠিকভাবে কাজ করে। আপনি কি ইমেইলে সম্পূর্ণ ভিজ্যুয়াল স্টুডিও সমাধানটি প্রেরণ করতে চান?
মিসক

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

0

এটি এমন এক উপায় যা আমি খুব সহজভাবে এটি করেছি:

আপনার উইন্ডো.এক্স্যামল সি

//In your constructor
public YourWindow()
{
    InitializeComponent();
    DataContext = new YourWindowViewModel(this);
}

আপনার উইন্ডোভিউমোডেল। সি

private YourWindow window;//so we can kill the window

//In your constructor
public YourWindowViewModel(YourWindow window)
{
    this.window = window;
}

//to close the window
public void CloseWindow()
{
    window.Close();
}

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


8
এর জন্য আপনার ভিউমোডেলটি আপনার ভিউটি জানতে এবং রেফারেন্স করতে হবে।
অ্যান্ড্রুএস

@ এন্ড্রুস কেন খারাপ?
থিস্টেফেনস্ট্যান্টন

9
এমভিভিএম প্যাটার্নটি অনুসরণ করতে, ভিউমোডেলটি ভিউ সম্পর্কে জানতে হবে না।
মেটালমাইকস্টার

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

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

0

আপনি উইন্ডোটিকে একটি পরিষেবা হিসাবে বিবেচনা করতে পারেন (যেমন, ইউআই পরিষেবা) এবং একটি ইন্টারফেসের মাধ্যমে ভিউ মডেলটিতে নিজেকে পাস করতে পারেন :

public interface IMainWindowAccess
{
    void Close(bool result);
}

public class MainWindow : IMainWindowAccess
{
    // (...)
    public void Close(bool result)
    {
        DialogResult = result;
        Close();
    }
}

public class MainWindowViewModel
{
    private IMainWindowAccess access;

    public MainWindowViewModel(IMainWindowAccess access)
    {
        this.access = access;
    }

    public void DoClose()
    {
        access.Close(true);
    }
}

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

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


-1

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

Application.Current.Windows[0].Close();

6
আপনার যদি একাধিক উইন্ডো থাকে তবে এটি ভুল উইন্ডোটি বন্ধ করতে পারে।
সাশা

17
ওহ খোদা! আপনি এমভিভিএম জবাই করেছেন
হোসেইন শাহদুস্ট

-7

সিস্টেম.ইনোভায়রন.এক্সিট (0); ভিউ মডেল কাজ করবে।


6
না এটা অভয়। এটি অ্যাপ্লিকেশন থেকে প্রস্থান করবে এবং বর্তমান উইন্ডোটি বন্ধ করবে না।
তিলক

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

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