2010-09-21 14 views
6

का उपयोग कर मॉडल के विभिन्न राज्यों के आधार पर विभिन्न नियंत्रणों को अक्षम करने और सक्षम करने का सुरुचिपूर्ण तरीका मैं निम्नलिखित समस्या के लिए एक सुरुचिपूर्ण समाधान ढूंढ रहा हूं।डब्ल्यूपीएफ - एमवीवीएम

मान लेते हैं हम निम्न बूलियन गुणों के साथ एक (देखें) मॉडल करते हैं:

  • अल्फा
  • बीटा
  • गामा
  • डेल्टा

अगला मैं पर 5 नियंत्रण है सतह जो केवल तब दिखाई देगी जब उन गुणों के आधार पर एक शर्त पूरी हो जाती है। बेशक, जैसे ही उन गुणों परिवर्तन अद्यतन किया जाता है में से एक immediatelly प्रचारित के रूप में किया जाना चाहिए:

  • ControlA -> अल्फा & & (बीटा || गामा)
  • ControlB -> डेल्टा
  • ControlC -> डेल्टा || बीटा
  • ControlD -> गामा & & अल्फा & & डेल्टा
  • controle -> अल्फा || गामा

एकमात्र समाधान जो मैं अब तक आया हूं वह मल्टीवैल्यू कन्वर्टर्स का उपयोग कर रहा है। ControlA के लिए

उदाहरण:

<ControlA> 
    <ControlA.Visibility> 
     <MultiBinding Converter={StaticResource ControlAVisibilityConverter}> 
      <Binding Path="Alpha"/> 
      <Binding Path="Beta"/> 
      <Binding Path="Gamma"/> 
     </MultiBinding> 
    </ControlA.Visibility> 
</ControlA> 

हालत के लिए यह ControlAVisibilityConverter चेकों "अल्फा & & (बीटा || गामा)" और उचित मान देता है।

यह काम करता है .. अच्छा .. लेकिन शायद आप एक और अधिक सुरुचिपूर्ण समाधान के साथ आ सकते हैं? नियंत्रण आदेशों का समर्थन (उदाहरण के लिए यदि वे बटन होते हैं), आदेश पैटर्न का उपयोग करते हैं

धन्यवाद, TwinHabit

+0

मुझे लगता है कि यह एक अच्छा दृष्टिकोण है –

उत्तर

5

प्रत्येक नियम के लिए एक कनवर्टर लिखना इस मामले में आपके व्यापार तर्क दो स्थानों (कनवर्टर और दृश्य मॉडल में) डालता है। मैं सुझाव देता हूं कि नियंत्रण दृश्यमान (या अन्य व्यवहार) है या नहीं, यह तय करने के लिए IotifyPropertyChanged ईवेंट के साथ अपने ViewModel में प्रत्येक नियंत्रण के लिए एक संपत्ति/ध्वज बनाना है।

ध्यान दें, कि जब आप मेरे व्यूमोडेल (नीचे) देखते हैं तो आप देखेंगे कि मैं प्रकार के बूल और Visibilty के गुणों का पर्दाफाश करता हूं।

यदि आपको सामान्य नियम के रूप में संपत्ति का उपयोग करने की आवश्यकता है तो बूल और डेटा ट्रिगर का उपयोग करें।

public bool ControlD 

आप सीधे दृश्यता के लिए बाध्य कर सकते हैं आप केवल दृश्यता को नियंत्रित करने की जरूरत है:

public Visibility ControlA 

अद्यतन: @Wallstreet प्रोग्रामर द्वारा टिप्पणी की वजह से , मैं एक BooleanVisibilityConverter उपयोग करने के लिए एक और विकल्प जोड़ा । कनवर्टर का उपयोग करने के तरीके को प्रतिबिंबित करने के लिए मैंने नीचे पांचवां नियंत्रण अपडेट किया। मैंने नीचे कनवर्टर के लिए कोड जोड़ा।

<Window x:Class="ControlVisibleTrigger.Views.MainView" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Main Window" Height="400" Width="800"> 
    <Window.Resources> 
    <Style x:Key="DropDownStyle" TargetType="TextBox"> 
     <Setter Property="Visibility" Value="Hidden"/> 
     <Style.Triggers> 
      <DataTrigger Binding="{Binding ControlC}" Value="True"> 
       <Setter Property="Visibility" Value="Visible"/> 
      </DataTrigger> 
     </Style.Triggers> 
    </Style> 
    </Window.Resources> 
    <DockPanel> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 
     <StackPanel Grid.Row="0"> 
      <CheckBox IsChecked="{Binding Path=Alpha,Mode=TwoWay}" Content="Alpha"/> 
      <CheckBox IsChecked="{Binding Path=Beta,Mode=TwoWay}" Content="Beta"/> 
      <CheckBox IsChecked="{Binding Path=Gamma,Mode=TwoWay}" Content="Gamma"/> 
      <CheckBox IsChecked="{Binding Path=Delta,Mode=TwoWay}" Content="Delta"/> 
     </StackPanel> 
     <TextBox Grid.Row="1" Visibility="{Binding Path=ControlA}" Text="Binding to visibility"/> 
     <Button Grid.Row="2" Visibility="{Binding Path=ControlB}" Content="Binding to visibility"/> 
     <TextBox Grid.Row="3" Style="{StaticResource DropDownStyle}" Text="Using WindowResource DataTrigger"/> 
     <TextBox Grid.Row="4" Text="Using Local DataTrigger"> 
      <TextBox.Style> 
       <Style TargetType="TextBox"> 
       <Setter Property="Visibility" Value="Hidden"/> 
       <Style.Triggers> 
        <DataTrigger Binding="{Binding ControlD}" Value="True"> 
         <Setter Property="Visibility" Value="Visible"/> 
        </DataTrigger> 
       </Style.Triggers> 
       </Style> 
      </TextBox.Style> 
     </TextBox> 
     <Button Grid.Row="5" 
       Content="Press me" 
       Visibility="{Binding Path=ControlE, Converter={StaticResource booleanVisibilityConverter}, ConverterParameter=True, Mode=OneWay}"> 
    </Grid> 
    </DockPanel> 
</Window> 

यहाँ ViewModel है:

यहाँ XAML में एक परीक्षण खिड़की है

public class MainViewModel : ViewModelBase 
{ 
    public MainViewModel() 
    { 
    } 

    private bool _alpha = true; 
    public bool Alpha 
    { 
    get 
    { 
     return _alpha; 
    } 
    set 
    { 
     _alpha = value; 
     OnPropertyChanged("ControlA"); 
     OnPropertyChanged("ControlB"); 
     OnPropertyChanged("ControlC"); 
     OnPropertyChanged("ControlD"); 
     OnPropertyChanged("ControlE"); 
    } 
    } 

    private bool _beta = true; 
    public bool Beta 
    { 
    get 
    { 
     return _beta; 
    } 
    set 
    { 
     _beta = value; 
     OnPropertyChanged("ControlA"); 
     OnPropertyChanged("ControlB"); 
     OnPropertyChanged("ControlC"); 
     OnPropertyChanged("ControlD"); 
     OnPropertyChanged("ControlE"); 
    } 
    } 

    private bool _gamma = true; 
    public bool Gamma 
    { 
    get 
    { 
     return _gamma; 
    } 
    set 
    { 
     _gamma = value; 
     OnPropertyChanged("ControlA"); 
     OnPropertyChanged("ControlB"); 
     OnPropertyChanged("ControlC"); 
     OnPropertyChanged("ControlD"); 
     OnPropertyChanged("ControlE"); 
    } 
    } 

    private bool _delta = true; 
    public bool Delta 
    { 
    get 
    { 
     return _delta; 
    } 
    set 
    { 
     _delta = value; 
     OnPropertyChanged("ControlA"); 
     OnPropertyChanged("ControlB"); 
     OnPropertyChanged("ControlC"); 
     OnPropertyChanged("ControlD"); 
     OnPropertyChanged("ControlE"); 
    } 
    } 

    public Visibility ControlA 
    { 
    get 
    { 
     Visibility result = Visibility.Hidden; 
     if (Alpha && (Beta || Gamma)) 
     { 
      result = Visibility.Visible; 
     } 
     return result; 
    } 
    } 

    public Visibility ControlB 
    { 
    get 
    { 
     Visibility result = Visibility.Hidden; 
     if (Delta) 
     { 
      result = Visibility.Visible; 
     } 
     return result; 
    } 
    } 

    private bool _controlC = false; 
    public bool ControlC 
    { 
    get 
    { 
     return Delta || Beta; 
    } 
    } 

    private bool _controlD = false; 
    public bool ControlD 
    { 
    get 
    { 
     return Gamma && Alpha && Delta; 
    } 
    } 

    private bool _controlE = false; 
    public bool ControlE 
    { 
    get 
    { 
     return Alpha || Gamma; 
    } 
    } 
} 

यहाँ कनवर्टर है:

public class BooleanVisibilityConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
    if((value == null) || (!(value is bool))) 
     return Binding.DoNothing; 

    Visibility elementVisibility; 
    bool shouldCollapse = ((bool)value); 

    if(parameter != null) 
    { 
     try 
     { 
     bool inverse = System.Convert.ToBoolean(parameter); 

     if(inverse) 
      shouldCollapse = !shouldCollapse; 
     } 
     catch 
     { 
     } 
    } 

    elementVisibility = shouldCollapse ? Visibility.Collapsed : Visibility.Visible; 
    return elementVisibility; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
    throw new NotImplementedException(); 
    } 
} 
+3

यदि एमवीवीएम की बात आती है तो हम सर्वोत्तम अभ्यास के बारे में बात कर रहे हैं, वीएम के पास दृश्यता रिटर्न प्रकारों जैसे विशिष्ट तर्क नहीं दिखना चाहिए। उन गुणों का प्रकार बूल होना चाहिए। दृश्य में, आप नियंत्रण को संकुचित करने के लिए एक बूलियनToVisibilityConverter का उपयोग करेंगे। –

+0

मैं सहमत हूं, मैं भी बूल विकल्प का उपयोग करता हूं। – Zamboni

+0

धन्यवाद @Wallstreet प्रोग्रामर, मैंने कनवर्टर को जोड़ा क्योंकि आपने इस उत्तर का सुझाव दिया था। – Zamboni

0

RelayCommand के साथ (इसे देखो), आप उस स्थिति को निर्दिष्ट कर सकते हैं जिसके तहत नियंत्रण लैम्ब्डा अभिव्यक्ति के साथ सक्षम है (जो आपको वही है)। यद्यपि इसे कुछ कोड-बैक की आवश्यकता है।

+0

असल में यह दृष्टिकोण काम नहीं करता है। सबसे पहले मेरे सभी नियंत्रण आईसीओएमएंड पैटर्न का उपयोग नहीं करते हैं। जहां तक ​​मुझे पता है कि आईसीओएमएंड CanExecute == झूठी केवल नियंत्रण अक्षम करता है। लेकिन मैं यह चुनने के लिए स्वतंत्र होना चाहता हूं कि मैं नियंत्रण को छिपाना या अक्षम करना चाहता हूं या नहीं। इसके अतिरिक्त जब व्यूमोडेल बदलता है तो मुझे तुरंत अपने नियंत्रण की दृश्यता की आवश्यकता होती है। यह CanExecute के साथ नहीं दिया गया है (सिवाय इसके कि यदि आप लगातार CommandManager.Requery ... को कॉल करते हैं) – TwinHabit

3

मान लिया जाये कि वहाँ एक व्यापार तर्क कारण नहीं है कि नियंत्रणों को प्रदर्शित किया जाना चाहिए या नहीं, मेरे पास निश्चित रूप से व्यूमोडेल में एक बूल के रूप में संग्रहीत तर्क होगा (वें हालांकि मैं इसे व्यापार तर्क के अनुसार नाम दूंगा उदाहरण: मानदंड नियंत्रण नहीं है अदृश्य)। यह आसान यूनिट परीक्षण को यह सुनिश्चित करने की अनुमति देता है कि मानदंड अल्फा, बीटा, गामा और डेल्टा परिवर्तन के रूप में सही ढंग से सेट हो। इसके अलावा मैं वॉलस्ट्रीट प्रोग्रामर के उत्तर से सहमत हूं (हालांकि मेरे पास टिप्पणी करने या उसकी प्रतिक्रिया देने का प्रतिनिधि नहीं है)।

संबंधित मुद्दे