ভিউমোডেলে ফিরে পঠনযোগ্য জিইউআই বৈশিষ্ট্যগুলি পুশ করছে


124

আমি একটি ভিউমোডেল লিখতে চাই যা সর্বদা ভিউ থেকে কিছু পঠনযোগ্য-নির্ভর নির্ভরতা সম্পর্কিত বর্তমান অবস্থা জানে।

বিশেষত, আমার জিইউআইতে একটি ফ্লোডোকামেন্টপেজভিউয়ার রয়েছে যা ফ্লোডোকামেন্ট থেকে একবারে একটি পৃষ্ঠা প্রদর্শন করে। ফ্লোডোকামেন্টপেজভিউয়ার দুটি-পঠনযোগ্য কেবল নির্ভরযোগ্য বৈশিষ্ট্যগুলি CanGoToPreLivePage এবং CanGoToNextPage নামে প্রকাশ করে। আমি চাই আমার ভিউমোডেলটি সর্বদা এই দুটি দেখার বৈশিষ্ট্যের মান জানতে পারে।

আমি অনুভব করেছি যে আমি ওয়ানওয়ে টোসোর্স ডেটাবাইন্ডিংয়ের মাধ্যমে এটি করতে পারি:

<FlowDocumentPageViewer
    CanGoToNextPage="{Binding NextPageAvailable, Mode=OneWayToSource}" ...>

যদি এটি অনুমোদিত হয় তবে এটি নিখুঁত হবে: যখনই ফ্লোডোকামেন্ট পেজভিউয়ের ক্যানগো টেক্সেক্সট সম্পত্তি পরিবর্তন হবে, নতুন মানটি ভিউমোডেলের নেক্সটপেজ উপলভ্য সম্পত্তিটিতে নিচে নামবে, যা আমি চাই ঠিক তাই।

দুর্ভাগ্যক্রমে, এটি সংকলন করে না: 'CanGoToPreLivePage' সম্পত্তিটি কেবল পঠনযোগ্য বলে মার্কআপ থেকে সেট করা যায় না বলে আমি একটি ত্রুটি পেয়েছি। দৃশ্যত কেবল পঠনযোগ্য বৈশিষ্ট্যগুলি কোনও ধরণের ডাটাবেইন্ডিং সমর্থন করে না, এমনকি সেই সম্পত্তি সম্পর্কিত শ্রদ্ধার সাথে কেবল পাঠযোগ্য ডেটাবাইন্ডিংও নয়।

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

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

আমি কীভাবে আমার ভিউমোডেলকে কেবলমাত্র পঠনযোগ্য বৈশিষ্ট্যগুলির পরিবর্তন সম্পর্কে অবহিত রাখতে পারি?

উত্তর:


151

হ্যাঁ, আমি অতীতে এটি ActualWidthএবং ActualHeightবৈশিষ্ট্যগুলি দিয়ে কাজ করেছি , উভয়ই কেবল পঠনযোগ্য। আমি একটি সংযুক্ত আচরণ তৈরি করেছি যা বৈশিষ্ট্যযুক্ত ObservedWidthএবং ObservedHeightসংযুক্ত রয়েছে। এটিতে এমন একটি Observeসম্পত্তিও রয়েছে যা প্রাথমিক হুক-আপ করতে ব্যবহৃত হয়। ব্যবহার এর মতো দেখাচ্ছে:

<UserControl ...
    SizeObserver.Observe="True"
    SizeObserver.ObservedWidth="{Binding Width, Mode=OneWayToSource}"
    SizeObserver.ObservedHeight="{Binding Height, Mode=OneWayToSource}"

সুতরাং দৃশ্য মডেল আছে Widthএবং Heightবৈশিষ্ট্য সঙ্গে সবসময় সমলয়ে রয়েছে যে ObservedWidthএবং ObservedHeightসংযুক্ত বৈশিষ্ট্য। Observeসম্পত্তি কেবল সংযুক্ত SizeChangedঘটনা FrameworkElement। হ্যান্ডেলটিতে এটি এর ObservedWidthএবং ObservedHeightবৈশিষ্ট্যগুলি আপডেট করে । তদ্ব্যতীত, Widthএবং Heightদর্শন মডেলটি সর্বদা ActualWidthএবং ActualHeightএর সাথে সুসংগত থাকে UserControl

সম্ভবত নিখুঁত সমাধান নয় (আমি সম্মত হই - কেবল পঠনযোগ্য ডিপিগুলিকে বাইন্ডিংগুলি সমর্থন করা উচিতOneWayToSource ) তবে এটি কার্যকর হয় এবং এটি এমভিভিএম প্যাটার্নটিকে সমর্থন করে। স্পষ্টতই, ObservedWidthএবং ObservedHeightডিপিগুলি কেবল পঠনযোগ্য নয়

আপডেট: এখানে কোড যা উপরে বর্ণিত কার্যকারিতা কার্যকর করে:

public static class SizeObserver
{
    public static readonly DependencyProperty ObserveProperty = DependencyProperty.RegisterAttached(
        "Observe",
        typeof(bool),
        typeof(SizeObserver),
        new FrameworkPropertyMetadata(OnObserveChanged));

    public static readonly DependencyProperty ObservedWidthProperty = DependencyProperty.RegisterAttached(
        "ObservedWidth",
        typeof(double),
        typeof(SizeObserver));

    public static readonly DependencyProperty ObservedHeightProperty = DependencyProperty.RegisterAttached(
        "ObservedHeight",
        typeof(double),
        typeof(SizeObserver));

    public static bool GetObserve(FrameworkElement frameworkElement)
    {
        frameworkElement.AssertNotNull("frameworkElement");
        return (bool)frameworkElement.GetValue(ObserveProperty);
    }

    public static void SetObserve(FrameworkElement frameworkElement, bool observe)
    {
        frameworkElement.AssertNotNull("frameworkElement");
        frameworkElement.SetValue(ObserveProperty, observe);
    }

    public static double GetObservedWidth(FrameworkElement frameworkElement)
    {
        frameworkElement.AssertNotNull("frameworkElement");
        return (double)frameworkElement.GetValue(ObservedWidthProperty);
    }

    public static void SetObservedWidth(FrameworkElement frameworkElement, double observedWidth)
    {
        frameworkElement.AssertNotNull("frameworkElement");
        frameworkElement.SetValue(ObservedWidthProperty, observedWidth);
    }

    public static double GetObservedHeight(FrameworkElement frameworkElement)
    {
        frameworkElement.AssertNotNull("frameworkElement");
        return (double)frameworkElement.GetValue(ObservedHeightProperty);
    }

    public static void SetObservedHeight(FrameworkElement frameworkElement, double observedHeight)
    {
        frameworkElement.AssertNotNull("frameworkElement");
        frameworkElement.SetValue(ObservedHeightProperty, observedHeight);
    }

    private static void OnObserveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
    {
        var frameworkElement = (FrameworkElement)dependencyObject;

        if ((bool)e.NewValue)
        {
            frameworkElement.SizeChanged += OnFrameworkElementSizeChanged;
            UpdateObservedSizesForFrameworkElement(frameworkElement);
        }
        else
        {
            frameworkElement.SizeChanged -= OnFrameworkElementSizeChanged;
        }
    }

    private static void OnFrameworkElementSizeChanged(object sender, SizeChangedEventArgs e)
    {
        UpdateObservedSizesForFrameworkElement((FrameworkElement)sender);
    }

    private static void UpdateObservedSizesForFrameworkElement(FrameworkElement frameworkElement)
    {
        // WPF 4.0 onwards
        frameworkElement.SetCurrentValue(ObservedWidthProperty, frameworkElement.ActualWidth);
        frameworkElement.SetCurrentValue(ObservedHeightProperty, frameworkElement.ActualHeight);

        // WPF 3.5 and prior
        ////SetObservedWidth(frameworkElement, frameworkElement.ActualWidth);
        ////SetObservedHeight(frameworkElement, frameworkElement.ActualHeight);
    }
}

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

1
ধন্যবাদ কেন্ট। আমি এই "সাইজঅবসভার" শ্রেণীর জন্য নীচে একটি কোড নমুনা পোস্ট করেছি।
স্কট হুইটলক

52
এই অনুভূতির কাছে +1: "কেবলমাত্র পঠনযোগ্য ডিপিগুলিকে ওয়ানওয়েটোসোর্স বাইন্ডিংগুলি সমর্থন করা উচিত"
ত্রিস্তান

3
Sizeহাইগথ এবং প্রস্থকে একত্রিত করে কেবলমাত্র একটি সম্পত্তি তৈরি করা আরও ভাল । প্রায়. 50% কম কোড।
জেরার্ড

1
@ জেরার্ড: কোনও ActualSizeসম্পত্তি নেই বলে এটি কাজ করবে না FrameworkElement। আপনি সংযুক্ত বৈশিষ্ট্য বাঁধাই সরাসরি চান, আপনি দুই বৈশিষ্ট্য আবদ্ধ হতে তৈরি করতে হবে ActualWidthএবং ActualHeightযথাক্রমে।
ডটনেট

58

আমি একটি সার্বজনীন সমাধান ব্যবহার করি যা কেবলমাত্র অ্যাক্টিওয়েথ এবং অ্যাকুয়ালহাইটের সাথেই কাজ করে না, আপনি যে কোনও ডেটা দিয়েও অন্তত পড়া মোডে আবদ্ধ হতে পারেন with

মার্কআপটি দেখতে এর মতো দেখাচ্ছে, প্রদত্ত ভিউপোর্টউইথ এবং ভিউপোর্টহাইটটি ভিউ মডেলের বৈশিষ্ট্য

<Canvas>
    <u:DataPiping.DataPipes>
         <u:DataPipeCollection>
             <u:DataPipe Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualWidth}"
                         Target="{Binding Path=ViewportWidth, Mode=OneWayToSource}"/>
             <u:DataPipe Source="{Binding RelativeSource={RelativeSource AncestorType={x:Type Canvas}}, Path=ActualHeight}"
                         Target="{Binding Path=ViewportHeight, Mode=OneWayToSource}"/>
          </u:DataPipeCollection>
     </u:DataPiping.DataPipes>
<Canvas>

কাস্টম উপাদানগুলির জন্য উত্স কোডটি এখানে

public class DataPiping
{
    #region DataPipes (Attached DependencyProperty)

    public static readonly DependencyProperty DataPipesProperty =
        DependencyProperty.RegisterAttached("DataPipes",
        typeof(DataPipeCollection),
        typeof(DataPiping),
        new UIPropertyMetadata(null));

    public static void SetDataPipes(DependencyObject o, DataPipeCollection value)
    {
        o.SetValue(DataPipesProperty, value);
    }

    public static DataPipeCollection GetDataPipes(DependencyObject o)
    {
        return (DataPipeCollection)o.GetValue(DataPipesProperty);
    }

    #endregion
}

public class DataPipeCollection : FreezableCollection<DataPipe>
{

}

public class DataPipe : Freezable
{
    #region Source (DependencyProperty)

    public object Source
    {
        get { return (object)GetValue(SourceProperty); }
        set { SetValue(SourceProperty, value); }
    }
    public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof(object), typeof(DataPipe),
        new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnSourceChanged)));

    private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((DataPipe)d).OnSourceChanged(e);
    }

    protected virtual void OnSourceChanged(DependencyPropertyChangedEventArgs e)
    {
        Target = e.NewValue;
    }

    #endregion

    #region Target (DependencyProperty)

    public object Target
    {
        get { return (object)GetValue(TargetProperty); }
        set { SetValue(TargetProperty, value); }
    }
    public static readonly DependencyProperty TargetProperty =
        DependencyProperty.Register("Target", typeof(object), typeof(DataPipe),
        new FrameworkPropertyMetadata(null));

    #endregion

    protected override Freezable CreateInstanceCore()
    {
        return new DataPipe();
    }
}

(ব্যবহারকারীর পক্ষে একটি উত্তরের মাধ্যমে ৫৪৩6464৪): এটি কোনও উত্তর নয় তবে দিমিত্রি-র একটি মন্তব্য - আমি আপনার সমাধানটি ব্যবহার করেছি এবং এটি দুর্দান্ত কাজ করেছে। দুর্দান্ত সর্বজনীন সমাধান যা বিভিন্ন জায়গায় সাধারণভাবে ব্যবহার করা যেতে পারে। আমি এটি আমার ভিউ মডেলটিতে কিছু ইউআই উপাদান বৈশিষ্ট্য (অ্যাকুয়ালহাইট এবং অ্যাকুয়ালউইথ) ঠেলাতে ব্যবহার করেছি।
মার্ক গ্র্যাভেল

2
ধন্যবাদ! এটি আমাকে কেবলমাত্র সম্পত্তি পেতে বাঁধতে সহায়তা করে। দুর্ভাগ্যক্রমে সম্পত্তি INotifyPropertyChanged ইভেন্টগুলি প্রকাশ করে নি। আমি এটি ডেটাপাইপ বাইন্ডিংয়ের নাম নির্ধারণ করে এবং পরিবর্তিত ইভেন্টগুলিতে নিম্নলিখিতগুলি যুক্ত করে সমাধান করেছি: বাইন্ডিংপ্রেসস.গেটবাইন্ডিং এক্সপ্রেশনবেস (বাইন্ডিংনাম, ডাটাপাইপ.সোর্সপ্রোপার্টি) .উপেটেটরেট ();
চিলডেম্প

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

1
এই সমাধানটি সম্পর্কে একমাত্র গ্রিপ মনে হয় এটি পরিষ্কার এনক্যাপসুলেশনটি ভেঙে দেয়, কারণ Targetসম্পত্তিটি বাইরে থেকে পরিবর্তন করা উচিত নয় এমনকী লেখার জন্য তৈরি করতে হয়: - /
অথবা ম্যাপার

কোডটি অনুলিপি-এন-পেস্ট করার চেয়ে যারা নুগেট প্যাকেজটিকে পছন্দ করবেন তাদের জন্য: আমি আমার ওপেনসোর্স জঙ্গলকন্ট্রোলস লাইব্রেরিতে ডেটা পাইপ যুক্ত করেছি। ডেটা পাইপ ডকুমেন্টেশন দেখুন ।
রবার্ট ভান

21

অন্য কারও যদি আগ্রহী হয় তবে আমি এখানে কেন্টের সমাধানটির প্রায় একটি কোড কোড করে রেখেছি:

class SizeObserver
{
    #region " Observe "

    public static bool GetObserve(FrameworkElement elem)
    {
        return (bool)elem.GetValue(ObserveProperty);
    }

    public static void SetObserve(
      FrameworkElement elem, bool value)
    {
        elem.SetValue(ObserveProperty, value);
    }

    public static readonly DependencyProperty ObserveProperty =
        DependencyProperty.RegisterAttached("Observe", typeof(bool), typeof(SizeObserver),
        new UIPropertyMetadata(false, OnObserveChanged));

    static void OnObserveChanged(
      DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    {
        FrameworkElement elem = depObj as FrameworkElement;
        if (elem == null)
            return;

        if (e.NewValue is bool == false)
            return;

        if ((bool)e.NewValue)
            elem.SizeChanged += OnSizeChanged;
        else
            elem.SizeChanged -= OnSizeChanged;
    }

    static void OnSizeChanged(object sender, RoutedEventArgs e)
    {
        if (!Object.ReferenceEquals(sender, e.OriginalSource))
            return;

        FrameworkElement elem = e.OriginalSource as FrameworkElement;
        if (elem != null)
        {
            SetObservedWidth(elem, elem.ActualWidth);
            SetObservedHeight(elem, elem.ActualHeight);
        }
    }

    #endregion

    #region " ObservedWidth "

    public static double GetObservedWidth(DependencyObject obj)
    {
        return (double)obj.GetValue(ObservedWidthProperty);
    }

    public static void SetObservedWidth(DependencyObject obj, double value)
    {
        obj.SetValue(ObservedWidthProperty, value);
    }

    // Using a DependencyProperty as the backing store for ObservedWidth.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ObservedWidthProperty =
        DependencyProperty.RegisterAttached("ObservedWidth", typeof(double), typeof(SizeObserver), new UIPropertyMetadata(0.0));

    #endregion

    #region " ObservedHeight "

    public static double GetObservedHeight(DependencyObject obj)
    {
        return (double)obj.GetValue(ObservedHeightProperty);
    }

    public static void SetObservedHeight(DependencyObject obj, double value)
    {
        obj.SetValue(ObservedHeightProperty, value);
    }

    // Using a DependencyProperty as the backing store for ObservedHeight.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ObservedHeightProperty =
        DependencyProperty.RegisterAttached("ObservedHeight", typeof(double), typeof(SizeObserver), new UIPropertyMetadata(0.0));

    #endregion
}

আপনার অ্যাপ্লিকেশনে এটিকে নির্দ্বিধায় ব্যবহার করুন। এটা ভাল কাজ করে. (ধন্যবাদ কেন্ট!)


10

আমি এই "বাগ" এর আরেকটি সমাধান এখানে দিয়েছি যা সম্পর্কে আমি এখানে ব্লগ করেছি:
কেবলমাত্র পঠনযোগ্য নির্ভরশীল সম্পত্তির জন্য ওয়ানওয়েটোসোর্স বাঁধাই

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

<TextBlock Name="myTextBlock"
           Background="LightBlue">
    <pb:PushBindingManager.PushBindings>
        <pb:PushBinding TargetProperty="ActualHeight" Path="Height"/>
        <pb:PushBinding TargetProperty="ActualWidth" Path="Width"/>
    </pb:PushBindingManager.PushBindings>
</TextBlock>

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

একটি সর্বশেষ নোট, নেট 4.0 থেকে আমরা এর জন্য অন্তর্নির্মিত সমর্থন থেকে আরও দূরে রয়েছি , যেহেতু ওয়ানওয়ে টোসোর্স বাইন্ডিং এটি আপডেট করার পরে উত্স থেকে মানটি পুনরায় পাঠ করে


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

4

আমি দিমিত্রি তাশকিনভের সমাধানটি পছন্দ করি! তবে এটি আমার ভিএস ডিজাইন মোডে ক্র্যাশ করেছে। এজন্য আমি অনসোর্স পরিবর্তন পদ্ধতিতে একটি লাইন যুক্ত করেছি:

    প্রাইভেট স্ট্যাটিক অকার্যকর অনসোর্স পরিবর্তিত (DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (! ((bool) DesignerProperties.IsInDesignModeProperty.GetMetadata (typof (dependendObject))। DefaultValue))
            ((DataPipe) ঘ) (ঙ) .OnSourceChanged;
    }

0

আমি মনে করি এটি কিছুটা সহজ করা যায়:

xaml:

behavior:ReadOnlyPropertyToModelBindingBehavior.ReadOnlyDependencyProperty="{Binding ActualWidth, RelativeSource={RelativeSource Self}}"
behavior:ReadOnlyPropertyToModelBindingBehavior.ModelProperty="{Binding MyViewModelProperty}"

CS:

public class ReadOnlyPropertyToModelBindingBehavior
{
  public static readonly DependencyProperty ReadOnlyDependencyPropertyProperty = DependencyProperty.RegisterAttached(
     "ReadOnlyDependencyProperty", 
     typeof(object), 
     typeof(ReadOnlyPropertyToModelBindingBehavior),
     new PropertyMetadata(OnReadOnlyDependencyPropertyPropertyChanged));

  public static void SetReadOnlyDependencyProperty(DependencyObject element, object value)
  {
     element.SetValue(ReadOnlyDependencyPropertyProperty, value);
  }

  public static object GetReadOnlyDependencyProperty(DependencyObject element)
  {
     return element.GetValue(ReadOnlyDependencyPropertyProperty);
  }

  private static void OnReadOnlyDependencyPropertyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
  {
     SetModelProperty(obj, e.NewValue);
  }


  public static readonly DependencyProperty ModelPropertyProperty = DependencyProperty.RegisterAttached(
     "ModelProperty", 
     typeof(object), 
     typeof(ReadOnlyPropertyToModelBindingBehavior), 
     new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

  public static void SetModelProperty(DependencyObject element, object value)
  {
     element.SetValue(ModelPropertyProperty, value);
  }

  public static object GetModelProperty(DependencyObject element)
  {
     return element.GetValue(ModelPropertyProperty);
  }
}

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