কোনও ইভেন্ট সি-তে চালিত না হওয়া পর্যন্ত কোড প্রবাহকে কীভাবে ব্লক করবেন to


11

এখানে আমরা একটি Grid সঙ্গে একটি আছে Button। যখন ব্যবহারকারী বোতামটি ক্লিক করেন, একটি ইউটিলিটি ক্লাসে একটি পদ্ধতি কার্যকর করা হয় যা অ্যাপ্লিকেশনটিকে গ্রিডে ক্লিক পেতে বাধ্য করে। কোড প্রবাহ অবশ্যই এখানে থামবে এবং ব্যবহারকারীর উপর ক্লিক না করা অবধি চলতে থাকবে না Grid

আমি এখানে আগে অনুরূপ প্রশ্ন ছিল:

ব্যবহারকারী সি # ডাব্লুপিএফ ক্লিক না হওয়া পর্যন্ত অপেক্ষা করুন

এই প্রশ্নে, আমি async ব্যবহার করে একটি উত্তর পেয়েছি / যা অপেক্ষা করে তা প্রত্যাশা করে, তবে যেহেতু আমি এটি একটি API এর অংশ হিসাবে ব্যবহার করতে যাচ্ছি, তাই আমি async / প্রতীক্ষা করতে চাই না, যেহেতু গ্রাহকরা তখন তাদের পদ্ধতিগুলি চিহ্নিত করতে হবে অ্যাসিঙ্ক যা আমি চাই না।

কীভাবে লিখি Utility.PickPoint(Grid grid)এই লক্ষ্য অর্জনের জন্য পদ্ধতি ?

আমি এটি দেখেছি যা সাহায্য করতে পারে তবে সৎ হতে এখানে প্রয়োগ করার জন্য এটি পুরোপুরি বুঝতে পারেনি:

কোনও ইভেন্ট সম্পূর্ণ না হওয়া পর্যন্ত অবরুদ্ধ

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

<Window x:Class="WpfApp1.MainWindow"
        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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="3*"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <Grid x:Name="View" Background="Green"/>
        <Button Grid.Row="1" Content="Pick" Click="ButtonBase_OnClick"/>
    </Grid>
</Window>

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

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        // do not continue the code flow until the user has clicked on the grid. 
        // so when we debug, the code flow will literally stop here.
        var point = Utility.PickPoint(View);


        MessageBox.Show(point.ToString());
    }
}

public static class Utility
{
    public static Point PickPoint(Grid grid)
    {

    }
}

স্পষ্ট উপায় হ'ল Aync/Awaitকীভাবে অপারেশন এ করছেন এবং সেই অপারেশন স্টেটটি সংরক্ষণ করবেন এখন আপনি চান যে ব্যবহারকারীর গ্রিড ক্লিক করা উচিত .. সুতরাং যদি ব্যবহারকারী ক্লিক করে গ্রিড আপনি যদি রাষ্ট্রটি পরীক্ষা করে থাকেন তবে আপনার অপারেশনটি যা করতে চান তা করুন ??
রাও হামাস হুসেন হুসেন

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

AutoResetEventআপনি কি চান না?
রাও হামাস হুসেন হোসেন

@ রাওহামাসহুসাইন আমার মনে হয় তবে এটি কীভাবে এখানে ব্যবহার করতে হয় তা সত্যই জানি না।
ওয়াহিদ

এটি আপনার মতো ইচ্ছাকৃতভাবে ওয়েট স্টেট বাস্তবায়ন করছে like এটি কি সত্যিই প্রয়োজন? আপনি কি কেবল var point = Utility.PickPoint(Grid grid);গ্রিড ক্লিক পদ্ধতিতে এটি রাখতে পারবেন না ? কিছু অপারেশন এবং প্রতিক্রিয়া ফিরে?
রাও হামাস হুসেন হোসেন

উত্তর:


9

"কোনও অনুষ্ঠান চালিত না হওয়া পর্যন্ত কোড প্রবাহকে কীভাবে ব্লক করবেন?"

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

আপনার কাছে সাধারণত দুটি (আধুনিক) বিকল্প রয়েছে: একটি অ্যাসিনক্রোনাস এপিআই বা ইভেন্ট-চালিত এপিআই প্রয়োগ করুন। যেহেতু আপনি আপনার এপিআই অ্যাসিঙ্ক্রোনাস বাস্তবায়ন করতে চান না, তাই আপনার ইভেন্ট-চালিত এপিআই ছেড়ে চলে যায়।

ইভেন্ট-চালিত এপিআই-এর মূল চাবিকাঠিটি হ'ল, কলারকে সিঙ্ক্রোনালি কোনও ফলাফলের জন্য অপেক্ষা করতে বা ফলাফলের জন্য পোলের জন্য চাপ দেওয়ার পরিবর্তে, আপনি ফলাফলটি প্রস্তুত হয়ে গেলে বা অপারেশন শেষ হয়ে গেলে আপনি কলারকে চালিয়ে যেতে এবং তাকে একটি বিজ্ঞপ্তি প্রেরণ করতে দেন। এদিকে, কলার অন্যান্য ক্রিয়াকলাপ চালিয়ে যেতে পারে।

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

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

আপনার প্রবাহ বা লক্ষ্যটিকে অবশ্যই ক্রিয়াকলাপের সিক্যুয়েন্স করতে কমপক্ষে দুটি ধাপে বিভক্ত করা হয়েছে:

  1. অপারেশন 1 চালান, যখন ব্যবহারকারী বোতামটি ক্লিক করে
  2. অপারেশন 2 চালান (চালিয়ে যান / সম্পূর্ণ অপারেশন 1), যখন ব্যবহারকারী ক্লিক করে Grid

কমপক্ষে দুটি বাধা সহ:

  1. Alচ্ছিক: ক্রমটি অবশ্যই এপিআই ক্লায়েন্টকে পুনরাবৃত্তি করার অনুমতি দেওয়ার আগে শেষ করতে হবে। অপারেশন 2 সম্পূর্ণ হওয়ার পরে একটি ক্রম সম্পূর্ণ হয়।
  2. অপারেশন 1 সর্বদা অপারেশন 2 এর আগে কার্যকর করা হয় 2 অপারেশন 1 ক্রম শুরু করে।
  3. এপিআই ক্লায়েন্টকে অপারেশন 2 চালানোর অনুমতি দেওয়ার আগে অপারেশন 1 অবশ্যই শেষ করতে হবে

এপিআই-র ক্লায়েন্টের জন্য অ-অবরুদ্ধ মিথস্ক্রিয়াটিকে মঞ্জুরি দেওয়ার জন্য এটি দুটি বিজ্ঞপ্তি (ইভেন্ট) এ প্রয়োজন:

  1. অপারেশন 1 সমাপ্ত (বা মিথস্ক্রিয়া প্রয়োজনীয়)
  2. অপারেশন 2 (বা লক্ষ্য) সম্পন্ন হয়েছে

আপনার এপিআইকে দু'টি পাবলিক পদ্ধতি এবং দুটি পাবলিক ইভেন্ট প্রকাশ করে এই আচরণ এবং প্রতিবন্ধকতাগুলি প্রয়োগ করতে দেওয়া উচিত।

যেহেতু এই বাস্তবায়নটি কেবলমাত্র API- এ একটি একক (অ-সমবর্তী) কলকে মঞ্জুরি দেয় এটি IsBusyএকটি চলমান ক্রমটি নির্দেশ করার জন্য কোনও সম্পত্তি প্রকাশ করার পরামর্শ দেয় recommended এটি নতুন ক্রম শুরু করার আগে বর্তমান অবস্থানে পোলিংয়ের অনুমতি দেয় যদিও পরবর্তী কলগুলি সম্পাদনের জন্য সম্পূর্ণ ইভেন্টটির জন্য অপেক্ষা করার পরামর্শ দেওয়া হয়।

প্রয়োগ / রিফ্যাক্টর ইউটিলিটি এপিআই

Utility.cs

class Utility
{
  public event EventHandler InitializePickPointCompleted;
  public event EventHandler<PickPointCompletedEventArgs> PickPointCompleted;
  public bool IsBusy { get; set; }
  private bool IsPickPointInitialized { get; set; }

  // The prefix 'Begin' signals the caller or client of the API, 
  // that he also has to end the sequence explicitly
  public void BeginPickPoint(param)
  {
    // Implement constraint 1
    if (this.IsBusy)
    {
      // Alternatively just return or use Try-do pattern
      throw new InvalidOperationException("BeginPickPoint is already executing. Call EndPickPoint before starting another sequence.");
    }

    // Set the flag that a current sequence is in progress
    this.IsBusy = true;

    // Execute operation until caller interaction is required.
    // Execute in background thread to allow API caller to proceed with execution.
    Task.Run(() => StartOperationNonBlocking(param));
  }

  public void EndPickPoint(param)
  {
    // Implement constraint 2 and 3
    if (!this.IsPickPointInitialized)
    {
      // Alternatively just return or use Try-do pattern
      throw new InvalidOperationException("BeginPickPoint must have completed execution before calling EndPickPoint.");
    }

    // Execute operation until caller interaction is required.
    // Execute in background thread to allow API caller to proceed with execution.
    Task.Run(() => CompleteOperationNonBlocking(param));
  }

  private void StartOperationNonBlocking(param)
  {
    ... // Do something

    // Flag the completion of the first step of the sequence (to guarantee constraint 2)
    this.IsPickPointInitialized = true;

    // Request caller interaction to kick off EndPickPoint() execution
    OnInitializePickPointCompleted();
  }

  private void CompleteOperationNonBlocking(param)
  {
    // Execute goal and get the result of the completed task
    Point result = ExecuteGoal();

    // Reset API sequence (allow next client invocation)
    this.IsBusy = false;
    this.IsPickPointInitialized = false;

    // Notify caller that execution has completed and the result is available
    OnPickPointCompleted(result);
  }

  private void OnInitializePickPointCompleted()
  {
    // Set the result of the task
    this.InitializePickPointCompleted?.Invoke(this, EventArgs.Empty);
  }

  private void OnPickPointCompleted(Point result)
  {
    // Set the result of the task
    this.PickPointCompleted?.Invoke(this, new PickPointCompletedEventArgs(result));
  }
}

PickPointCompletedEventArgs.cs

class PickPointCompletedEventArgs : AsyncCompletedEventArgs 
{
  public Point Result { get; }

  public PickPointCompletedEventArgs(Point result)
  {
    this.Result = result;
  }
}

এপিআই ব্যবহার করুন

MainWindow.xaml.cs

partial class MainWindow : Window
{
  private Utility Api { get; set; }

  public MainWindow()
  {
    InitializeComponent();

    this.Api = new Utility();
  }

  private void StartPickPoint_OnButtonClick(object sender, RoutedEventArgs e)
  {
    this.Api.InitializePickPointCompleted += RequestUserInput_OnInitializePickPointCompleted;

    // Invoke API and continue to do something until the first step has completed.
    // This is possible because the API will execute the operation on a background thread.
    this.Api.BeginPickPoint();
  }

  private void RequestUserInput_OnInitializePickPointCompleted(object sender, EventArgs e)
  {
    // Cleanup
    this.Api.InitializePickPointCompleted -= RequestUserInput_OnInitializePickPointCompleted;

    // Communicate to the UI user that you are waiting for him to click on the screen
    // e.g. by showing a Popup, dimming the screen or showing a dialog.
    // Once the input is received the input event handler will invoke the API to complete the goal   
    MessageBox.Show("Please click the screen");  
  }

  private void FinishPickPoint_OnGridMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  {
    this.Api.PickPointCompleted += ShowPoint_OnPickPointCompleted;

    // Invoke API to complete the goal
    // and continue to do something until the last step has completed
    this.Api.EndPickPoint();
  }

  private void ShowPoint_OnPickPointCompleted(object sender, PickPointCompletedEventArgs e)
  {
    // Cleanup
    this.Api.PickPointCompleted -= ShowPoint_OnPickPointCompleted;

    // Get the result from the PickPointCompletedEventArgs instance
    Point point = e.Result;

    // Handle the result
    MessageBox.Show(point.ToString());
  }
}

MainWindow.xaml

<Window>
  <Grid MouseLeftButtonUp="FinishPickPoint_OnGridMouseLeftButtonUp">
    <Button Click="StartPickPoint_OnButtonClick" />
  </Grid>
</Window>

মন্তব্য

একটি পটভূমি থ্রেডে উত্থাপিত ইভেন্টগুলি একই থ্রেডে তাদের হ্যান্ডলারগুলি কার্যকর করবে। একটি অ্যাক্সেস DispatcherObjectএকটি হ্যান্ডলার, যা একটি পটভূমি থ্রেডে কার্যকর থেকে একটি UI 'তে উপাদান মত, প্রয়োজন সমালোচনামূলক অপারেশনে enqueued করা Dispatcherব্যবহার হয় Dispatcher.Invokeবা Dispatcher.InvokeAsyncএড়াতে ক্রস থ্রেড ব্যতিক্রম। ডিসপ্যাচার অ্যাফিনিটি বা থ্রেড অ্যাফিনিটি নামে পরিচিত এই ঘটনাটি সম্পর্কে আরও
জানার DispatcherObjectজন্য মন্তব্যগুলি পড়ুন ।
এপিআই এর সুবিধাজনক ব্যবহারের জন্য আমি কলারের ক্যাপচার এবং ব্যবহার করে SynchronizationContextবা AsyncOperation(বা AsyncOperationManager) ব্যবহার করে কলারের মূল প্রসঙ্গে সমস্ত ঘটনা মার্শাল করার পরামর্শ দিই ।

উপরোক্ত উদাহরণটি সহজেই বাতিলকরণ (প্রস্তাবিত) প্রদানের মাধ্যমে উদাহরণস্বরূপ কোনও Cancel()পদ্ধতি উদঘাটন করে PickPointCancel()এবং অগ্রগতি প্রতিবেদন (সাধারণত ব্যবহার করা Progress<T>) সরবরাহ করে বাড়ানো যেতে পারে ।


কিছু চিন্তা - আপনার মন্তব্যের জবাব দিন

আপনি কনসোল অ্যাপ্লিকেশনগুলির উদাহরণ দিয়ে আমাকে একটি "আরও ভাল" ব্লকিং সমাধানের জন্য আমার কাছে পৌঁছেছিলেন বলে আমি আপনাকে বোঝাতে পেরেছি, আপনার ধারণা বা দৃষ্টিভঙ্গি সম্পূর্ণ ভুল is

"এতে এই দুটি লাইনের কোড সহ একটি কনসোল অ্যাপ্লিকেশন বিবেচনা করুন।

var str = Console.ReadLine(); 
Console.WriteLine(str);

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

একটি কনসোল অ্যাপ্লিকেশন সম্পূর্ণ আলাদা কিছু। থ্রেডিং ধারণাটি কিছুটা আলাদা। কনসোল অ্যাপ্লিকেশনগুলির একটি জিইউআই নেই। কেবল ইনপুট / আউটপুট / ত্রুটি স্ট্রিম। আপনি একটি কনসোল অ্যাপ্লিকেশনটির আর্কিটেকচারকে একটি সমৃদ্ধ জিইউআই অ্যাপ্লিকেশনটির সাথে তুলনা করতে পারবেন না। এটি কাজ করবে না। আপনার অবশ্যই এটি বুঝতে এবং গ্রহণ করতে হবে।

এছাড়াও চেহারা দ্বারা প্রতারিত করবেন না । জানো ভিতরে কী হচ্ছে Console.ReadLine? এটি কীভাবে বাস্তবায়ন হয় ? এটি কি মূল থ্রেডটি ব্লক করছে এবং সমান্তরালে এটি ইনপুটটি পড়ে? নাকি এটা ঠিক ভোটদান?
এর মূল বাস্তবায়ন এখানে Console.ReadLine:

public virtual String ReadLine() 
{
  StringBuilder sb = new StringBuilder();
  while (true) 
  {
    int ch = Read();
    if (ch == -1) 
      break;
    if (ch == '\r' || ch == '\n') 
    {
      if (ch == '\r' && Peek() == '\n') 
        Read();
      return sb.ToString();
    }
    sb.Append((char)ch);
  }
  if (sb.Length > 0) 
    return sb.ToString();
  return null;
}

আপনি দেখতে পাচ্ছেন এটি একটি সাধারণ সিঙ্ক্রোনাস অপারেশন। এটি "অসীম" লুপে ব্যবহারকারীর ইনপুট জন্য পোল করে। কোনও ম্যাজিক ব্লক এবং অবিরত নেই।

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

অপেক্ষমান = থ্রেড ব্লকিং = প্রতিক্রিয়াহীনতা = খারাপ ইউএক্স = বিরক্ত ব্যবহারকারী / গ্রাহকরা = অফিসে সমস্যা।

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

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

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

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

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

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

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

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

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

"আমি অটোডেস্ক রিভিটে সঠিক আচরণটি দেখেছি।"

আচরণটি (আপনি যা অনুভব করেন বা পর্যবেক্ষণ করেন) এই অভিজ্ঞতা কীভাবে প্রয়োগ করা হয় তার থেকে অনেক আলাদা। দুটি ভিন্ন জিনিস। আপনার অটোডেস্ক সম্ভবত অ্যাসিনক্রোনাস লাইব্রেরি বা ভাষার বৈশিষ্ট্য বা অন্য কোনও থ্রেডিং প্রক্রিয়া ব্যবহার করছে। এবং এটি প্রাসঙ্গিক সম্পর্কিতও। আপনার মনে যে পদ্ধতিটি কোনও পটভূমির থ্রেডে চালিত হয় তখন বিকাশকারী এই থ্রেডটি ব্লক করতে পছন্দ করতে পারেন। এটি করার জন্য তার কাছে খুব ভাল কারণ রয়েছে বা তিনি একটি খারাপ নকশা পছন্দ করেছেন choice আপনি সম্পূর্ণ ভুল পথে আছেন;) ব্লক করা ভাল নয় is
(অটোডেস্ক সোর্স কোড ওপেন সোর্স? বা কীভাবে এটি বাস্তবায়ন হয় আপনি কীভাবে জানেন?)

আমি আপনাকে অসন্তুষ্ট করতে চাই না, দয়া করে আমাকে বিশ্বাস করুন। তবে দয়া করে আপনার এপিআই অ্যাসিক্রোনাস বাস্তবায়নের জন্য পুনর্বিবেচনা করুন। এটি কেবল আপনার মাথায় রয়েছে যে বিকাশকারীরা async / অপেক্ষা করতে পছন্দ করেন না। আপনি অবশ্যই ভুল মানসিকতা পেয়েছেন। এবং সেই কনসোল অ্যাপ্লিকেশন আর্গুমেন্টটি সম্পর্কে ভুলে যান - এটি বোকামি;)

UI সম্পর্কিত এআইপিআই async ব্যবহার করা / যখনই সম্ভব অপেক্ষা করা আবশ্যক । অন্যথায়, আপনি আপনার API এর ক্লায়েন্টকে নন-ব্লকিং কোড লেখার জন্য সমস্ত কাজ ছেড়ে যান আপনি আমাকে আপনার এপিআইতে প্রতিটি কল একটি পটভূমির থ্রেডে আবদ্ধ করতে বাধ্য করবেন। বা কম আরামদায়ক ইভেন্ট হ্যান্ডলিং ব্যবহার করতে। আমাকে বিশ্বাস করুন - প্রতিটি বিকাশকারী asyncইভেন্ট হ্যান্ডলিংয়ের চেয়ে বরং তার সদস্যদের সাথে সজ্জিত করে । প্রতিবার আপনি ইভেন্টগুলি ব্যবহার করার সময় আপনি একটি সম্ভাব্য মেমরি ফাঁসের ঝুঁকি নিতে পারেন - এটি কিছু পরিস্থিতিতে নির্ভর করে, তবে ঝুঁকিটি বাস্তব এবং বিরল না হয়ে প্রোগ্রামিং করার সময় ঘটে।

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

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

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

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


হাই, অন্য দৃষ্টিকোণ থেকে প্রশ্ন পৌঁছানোর জন্য আপনাকে ধন্যবাদ। প্রশ্নের বিবরণে যদি প্রশ্নটি কিছুটা অস্পষ্ট হত তবে দুঃখিত। এতে এই দুটি লাইনের কোড সহ একটি কনসোল অ্যাপ্লিকেশন বিবেচনা করুন। var str = Console.ReadLine(); Console.WriteLine(str);আপনি যখন ডিবাগ মোডে অ্যাপ্লিকেশনটি কার্যকর করেন তখন কী হয়। এটি কোডের প্রথম লাইনে থামবে এবং আপনাকে কনসোল ইউআইতে একটি মান লিখতে বাধ্য করবে এবং তারপরে আপনি কিছু প্রবেশ করার পরে এন্টার টিপুন, এটি পরবর্তী লাইনটি কার্যকর করবে এবং আপনি যা লিখেছেন তা মুদ্রণ করবে। আমি ঠিক একই আচরণ সম্পর্কে কিন্তু WPF অ্যাপ্লিকেশনটিতে ভাবছিলাম application
ওয়াহিদ

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

আমি অটোডেস্ক রিভিটে সঠিক আচরণটি দেখেছি।
ওয়াহিদ

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

আপনার আপডেট করা উত্তরের জন্য আপনাকে ধন্যবাদ। অবশ্যই আমি বিরক্ত হই না। বিপরীতে, আপনি যে সময় এবং প্রচেষ্টার প্রতিদান দিয়েছেন তার জন্য আমি সত্যই কৃতজ্ঞ।
ওয়াহিদ

5

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

প্রথম এবং সর্বাগ্রে, সম্পত্তি Backgroundএবং IsHitTestVisibleবৈশিষ্ট্যগুলি সেট করে আপনার গ্রিডটিকে হিট-টেস্টেবল করে তুলুন , অন্যথায় এটি মাউস ক্লিকগুলিও ক্যাপচার করবে না।

<grid MouseLeftButtonUp="Grid_MouseLeftButtonUp" IsHitTestVisible="True" Background="Transparent">

এরপরে একটি বিল মান তৈরি করুন যা "গ্রিডক্লিক" ইভেন্টটি হওয়া উচিত কিনা তা সঞ্চয় করতে পারে। গ্রিডটি ক্লিক করা হলে, ক্লিকটির অপেক্ষায় থাকলে গ্রিড ক্লিক ইভেন্ট থেকে সেই মানটি এবং সম্পাদনা সম্পাদনা পরীক্ষা করে দেখুন।

উদাহরণ:

bool awaitingClick = false;


private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
   awaitingClick=true;
}

private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{     
     //Stop here if the program shouldn't do anything when grid is clicked
     if (!awaitingClick) { return; } 

     //Run event
     var point = Utility.PickPoint(View);
     MessageBox.Show(point.ToString());

     awaitingClick=false;//Reset
}

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

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

এটি সম্ভব না হলে এখনও নিশ্চিত নই। এটি async / প্রতীক্ষার মাধ্যমে অবশ্যই সম্ভব যা কোনও মাল্টি-থ্রেড সমাধান নয়। তবে আমার যা প্রয়োজন তা হ'ল এসাইক / অপেক্ষার সমাধানের বিকল্প।
ওয়াহিদ

1
অবশ্যই, তবে আপনি উল্লেখ করেছেন যে আপনি async / অপেক্ষা করতে পারবেন না। দেখে মনে হচ্ছে আপনার কোনও প্রেরণকারী এবং একটি থ্রেড যা মূল থ্রেড (যা ইউআইতে কার্যকর হয়) থেকে পৃথক করা প্রয়োজন of আমি আশা করি আমার নিজের মতো আগ্রহী হলেও আপনি অন্য কোনও উপায় খুঁজে পাবেন
ট্রোনাল্ড

2

আমি কয়েকটি জিনিস চেষ্টা করেছিলাম তবে আমি তা ছাড়া তৈরি করতে পারছি না async/await। কারণ আমরা যদি এটি ব্যবহার না করি তবে এটির কারণ হয় DeadLockবা ইউআই অবরুদ্ধ থাকে এবং তারপরে আমরা Grid_Clickইনপুট নিতে সক্ষম হয়েছি ।

private async void ToolBtn_OnClick(object sender, RoutedEventArgs e)
{
    var senderBtn = sender as Button;
    senderBtn.IsEnabled = false;

    var response = await Utility.PickPoint(myGrid);
    MessageBox.Show(response.ToString());
    senderBtn.IsEnabled = true;
}  

public static class Utility
{
    private static TaskCompletionSource<bool> tcs;
    private static Point _point = new Point();

    public static async Task<Point> PickPoint(Grid grid)
    {
        tcs = new TaskCompletionSource<bool>();
        _point = new Point();

        grid.MouseLeftButtonUp += GridOnMouseLeftButtonUp;


        await tcs.Task;

        grid.MouseLeftButtonUp -= GridOnMouseLeftButtonUp;
        return _point;
    }


    private static void GridOnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {

        // do something here ....
        _point = new Point { X = 23, Y = 34 };
        // do something here ....

        tcs.SetResult(true); // as soon its set it will go back

    }
}

থ্যাঙ্কস, আমার অন্যান্য প্রশ্নের জন্য এটি একই উত্তর পেয়েছে যা অ্যাসিঙ্ক / অপেক্ষারত ব্যবহার করে।
ওয়াহিদ

হ্যাঁ ! আমি এখন এটি লক্ষ্য করেছি তবে আমি অনুমান করি এটিই একমাত্র উপায় যা আমি কাজ করেছিলাম
রাও হামস হুসেন হুসেন

2

আপনি এটি ব্যবহার করে অ্যাসিঙ্ক্রোনিকভাবে ব্লক করতে পারেন SemaphoreSlim:

public partial class MainWindow : Window, IDisposable
{
    private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(0, 1);

    public MainWindow()
    {
        InitializeComponent();
    }

    private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        var point = Utility.PickPoint(View);

        // do not continue the code flow until the user has clicked on the grid. 
        // so when we debug, the code flow will literally stop here.
        await _semaphoreSlim.WaitAsync();

        MessageBox.Show(point.ToString());
    }

    private void View_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        //click on grid detected....
        _semaphoreSlim.Release();
    }

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        Dispose();
    }

    public void Dispose() => _semaphoreSlim.Dispose();
}

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


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

@ ওয়াহিদ: Console.Readline ব্লক , অর্থাৎ কোনও লাইন না পড়া পর্যন্ত এটি ফিরে আসে না। আপনার PickPointপদ্ধতি না। এটি সঙ্গে সঙ্গে ফিরে আসে। এটি সম্ভাব্যভাবে অবরুদ্ধ হতে পারে তবে এর পরে আমি আমার উত্তরে যেমন লিখেছি আপনি এই সময়ের মধ্যে ইউআই ইনপুট পরিচালনা করতে সক্ষম হবেন না। অন্য কথায়, একই আচরণ পেতে আপনাকে পদ্ধতির অভ্যন্তরে ক্লিকটি পরিচালনা করতে হবে।
এমএম 8

কনসোল.রিলাইন () ব্লক করে তবে একই সাথে কীপ্রেস ইভেন্টগুলি অনুমোদিত। আমরা কি এখানে ঠিক একই আচরণ করতে পারি না? পিকপয়েন্ট () দ্বারা ব্লক করা এবং কেবল মাউসএভেন্টসকে অনুমতি দেওয়া হচ্ছে? কনসোলে কেন এটি সম্ভব তা আমি বুঝতে পারি না তবে কোনও ইউআই ভিত্তিক অ্যাপ্লিকেশনটিতে নয়।
ওয়াহিদ

তারপরে আপনাকে PickPointমাউসের ইভেন্টগুলি পরিচালনা করে এমন একটি পৃথক প্রেরক সেটআপ করতে হবে । আপনি কোথায় যাচ্ছেন তা দেখতে আমি ব্যর্থ?
মিমি 8

1
@ ওয়াহাইন্ড: কোডটি অ্যাসিঙ্ক করুন এবং তারপরে ব্যবহারকারীকে সেই পদ্ধতির অপেক্ষায় থাকতে দিন? এটি ইউআইআই বিকাশকারী হিসাবে আমি আশা করব এমন এপিআই। কোনও ইউআই অ্যাপ্লিকেশনটিতে একটি ব্লকিং পদ্ধতিতে কল করা কোনও অর্থবোধ করে না।
মিমি 8

2

প্রযুক্তিগতভাবে এটি AutoResetEventছাড়া এবং ছাড়াও সম্ভব async/await, তবে একটি উল্লেখযোগ্য ব্যর্থতা রয়েছে:

public static Point PickPoint(Grid grid)
{
    var pointPicked = new AutoResetEvent(false);
    grid.MouseLeftButtonUp += (s, e) => 
    {
        // do whatever after the grid is clicked

        // signal the end of waiting
        pointPicked.Set();
    };

    // code flow will stop here and wait until the grid is clicked
    pointPicked.WaitOne();
    // return something...
}

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

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

private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
    // here I used ThreadPool, but you may use other means to run on another thread
    ThreadPool.QueueUserWorkItem(new WaitCallback(Capture));
}

private void Capture(object state)
{
    // do not continue the code flow until the user has clicked on the grid. 
    // so when we debug, the code flow will literally stop here.
    var point = Utility.PickPoint(View);


    MessageBox.Show(point.ToString());
}

এটি আপনার এপিআই এর গ্রাহকদের নিজের থ্রেড পরিচালনা করতে ব্যতীত আরও ঝামেলা সৃষ্টি করতে পারে। এজন্যই async/awaitআবিষ্কার করা হয়েছিল।


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

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

0

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

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

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

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


0

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

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

    private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
    {
        Utility.PickPoint(View, (x) => MessageBox.Show(x.ToString()));
    }
}

public static class Utility
{
    private static Action<Point> work;

    public static void PickPoint(Grid grid, Action<Point> work)
    {
        if (Utility.work == null)
        {
            grid.PreviewMouseLeftButtonUp += Grid_PreviewMouseLeftButtonUp;
            Utility.work = work;
        }
    }

    private static void Grid_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        var grid = (Grid)sender;
        work.Invoke(e.GetPosition(grid));
        grid.PreviewMouseLeftButtonUp -= Grid_PreviewMouseLeftButtonUp;
        Utility.work = null;
    }
}   

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

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