2017-02-19 47 views
0

我有一個表格,它綁定到模型。有一個標準的,基本的模型和少數兒童模型(附加字段)。如何避免在將控件綁定到類層次結構時繁瑣的代碼?

在模型的控件上方有一個單選按鈕組,當選擇其中一個時,會出現前面提到的其他字段(在本例中爲句子字段)。

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

    private void sentencedPersonRadioButton_Checked(object sender, RoutedEventArgs e) 
    { 
     sentenceTextBox.Visibility = Visibility.Visible; 
     DataContext = new SentencedPerson(); 
    } 

    private void personRadioButton_Checked(object sender, RoutedEventArgs e) 
    { 
     sentenceTextBox.Visibility = Visibility.Hidden; 
     DataContext = new Person(); 
    } 
} 

比方說,有一個人與SentencedPerson:

public class Person: INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    public void OnPropertyChanged(String propertyName) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    private String name; 
    public String Name 
    { 
     get 
     { 
      return name; 
     } 

     set 
     { 
      if (value == name) 
      { 
       return; 
      } 

      name = value; 
      OnPropertyChanged("Name"); 
     } 
    } 
} 

public class SentencedPerson : Person 
{ 
    private String sentence; 
    public String Sentence 
    { 
     get 
     { 
      return sentence; 
     } 

     set 
     { 
      if (value == sentence) 
      { 
       return; 
      } 

      sentence = value; 
      OnPropertyChanged("Sentence"); 
     } 
    } 
} 

什麼是設計這種連接的正確方法?添加新的'checked'事件處理程序讓人覺得很麻煩......我聽說過MVVM模式,其中有一些PersonContext與Person和SentencedPerson道具。但它並沒有改變'檢查'事件的需要。

也知道有一個問題,因爲常用字段的值是在設置新的DataContext之後。

回答

1

這是一個相當廣泛的問題,但我會給你一些指示。

MVVM是推薦的設計模式在構建基於XAML的應用程序時使用。

您可以創建一個視圖模型類object型或Person的,綁定的RadioButton到「CurrentSelectedContent」屬性和enum財產。

請參考以下鏈接瞭解更多信息和如何將RadioButtonenum源屬性使用MVVM綁定一個例子:

How to bind RadioButtons to an enum?

一旦你做到了這一點,你可以設置的值

private MyLovelyEnum _enum; 
public MyLovelyEnum VeryLovelyEnum 
{ 
    get 
    { 
     return _enum; 
    } 
    set 
    { 
     _enum = value; 
     switch (value) 
     { 
      case MyLovelyEnum.Person: 
       CurrentSelectedContent = new Person(); 
       break; 
      //... 
     } 
     OnPropertyChanged("VeryLovelyEnum"); 

    } 
} 

馬:基於在enum源屬性的視圖中的模型中的設定器的單選按鈕選擇「CurrentSelectedContent」屬性確保「Cu​​rrentSelectedContent」屬性引發了PropertyChanged事件,並且視圖模型類實現了INotifyPropertyChanged接口。

在視圖然後你可以使用ContentControl及其Content屬性綁定到了「CurrentSelectedContent」屬性:

<ContentControl Content="{Binding Content}"> 
     <ContentControl.ContentTemplate> 
      <DataTemplate> 
       <TextBox Text="{Binding Name}" /> 
      </DataTemplate> 
     </ContentControl.ContentTemplate> 
    </ContentControl> 

另外,還要確保你設置視圖的DataContext到您的視圖模型的實例:

public MainWindow() 
{ 
    InitializeComponent(); 
    DataContext = new ViewModel(); 
} 

這是如何做到這一點使用MVVM模式的粗略的想法。您不必處理視圖代碼後面的事件,而是綁定到源屬性,而不是明確設置特定UI元素的DataContext屬性,而是將ContentControlContent屬性綁定到您在視圖模型類中創建的對象。

希望有所幫助。

+0

我不認爲我得到這個。如果枚舉被設置爲被判刑人員,我仍然需要定義某個地方。必須顯示句子TextBox。除此之外,我還看到填充DataContext視圖模型的問題。在MyLovelyEnum的枚舉設置器中,我丟失了控件中的數據,我的意思是來自基礎對象的公共數據。它描述了名稱屬性的值。 – y434y

0

你只需要一個模型:

public class Person : INotifyPropertyChanged 
{ 
    string _name; 
    public string Name { get { return _name; } set { _name = value; RaisePropertyChanged("Name"); } } 

    bool _isSentenced; 
    public bool IsSentenced { get { return _isSentenced; } set { _isSentenced = value; RaisePropertyChanged("IsSentenced"); } } 

    string _sentence; 
    public string Sentence { get { return _sentence; } set { _sentence = value; RaisePropertyChanged("Sentence"); } } 

    public event PropertyChangedEventHandler PropertyChanged; 
    void RaisePropertyChanged(string propname) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname)); 
    } 
} 

使用IsSentenced和單選按鈕綁定到它。此外,使用Visibility to Bool轉換器,檢查顯示Sentence字符串的文本框的可見性到RadioButton的IsChecked屬性。下面是一個簡單的例子:

<Window.Resources> 
    <local:VisibilityToBoolConverter x:Key="VisibilityToBoolConverter"/> 
</Window.Resources> 
<ListBox DataContext="{Binding}" ItemsSource="{Binding Persons}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel> 
       <TextBox Text="{Binding Name}" /> 
       <RadioButton Content="Is sentenced to death" IsChecked="{Binding IsSentenced}" /> 
       <DockPanel Visibility="{Binding IsSentenced , Converter={StaticResource VisibilityToBoolConverter}}"> 
        <Label Content="Sentence: "/> 
        <TextBlock Text="{Binding Sentence}" /> 
       </DockPanel> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

其中

public class VisibilityToBoolConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if ((bool)value == true) 
      return Visibility.Visible; 
     return Visibility.Collapsed; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if ((Visibility)value == Visibility.Visible) 
      return true; 
     return false; 
    } 
} 

和視圖模型是:

public class PersonViewModel : INotifyPropertyChanged 
{ 
    public PersonViewModel() 
    { 
     Person m1 = new Person() { Name = "person 1", IsSentenced = false, Sentence = "S S S" }; 
     Person m2 = new Person() { Name = "person 2", IsSentenced = false, Sentence = "B B B" }; 
     Person m3 = new Person() { Name = "person 3", IsSentenced = true, Sentence = "F F F" }; 
     _persons = new ObservableCollection<Person>() { m1, m2, m3 }; 

    } 
    ObservableCollection<Person> _persons; 
    public ObservableCollection<Person> Persons { get { return _persons; } set { _persons = value; RaisePropertyChanged("Persons"); } } 

    public event PropertyChangedEventHandler PropertyChanged; 
    void RaisePropertyChanged(string propname) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname)); 
    } 
} 

主窗口應設置的DataContext:

public MainWindow() 
    { 
     PersonViewModel mv = new PersonViewModel(); 
     this.DataContext = mv; 
     InitializeComponent(); 
    } 

編輯

如果一個人有很多狀態,ComboBox是更自然的選擇。你應該有一個描述狀態的枚舉:

public enum MyTypes 
{ 
    None, 
    IsA, 
    IsB, 
    IsC 
} 

和人都應該有一個peroperty顯示狀態:

public class Person : INotifyPropertyChanged 
{ 
    MyTypes _thetype; 
    public MyTypes TheType { get { return _thetype; } set { _thetype = value; RaisePropertyChanged("TheType"); } } 

    string _name; 
    public string Name { get { return _name; } set { _name = value; RaisePropertyChanged("Name"); } } 

    public event PropertyChangedEventHandler PropertyChanged; 
    void RaisePropertyChanged(string propname) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname)); 
    } 
} 

,因爲你需要你的組合框的的ItemsSource綁定到列表狀態,一種可能性是調整視圖模型有這樣一個清單:

public class PersonViewModel : INotifyPropertyChanged 
{ 
    public PersonViewModel() 
    { 
     Person m0 = new Person() { Name = "person 1", TheType = MyTypes.None }; 
     Person m1 = new Person() { Name = "person 1", TheType = MyTypes.IsA }; 
     Person m2 = new Person() { Name = "person 2", TheType = MyTypes.IsB }; 
     Person m3 = new Person() { Name = "person 3", TheType = MyTypes.IsC }; 
     _persons = new ObservableCollection<Person>() { m0, m1, m2, m3 }; 

     _types = Enum.GetNames(typeof(MyTypes)).ToList(); 
    } 

    List<string> _types; 
    public List<string> Types { get { return _types; } } 


    ObservableCollection<Person> _persons; 
    public ObservableCollection<Person> Persons { get { return _persons; } set { _persons = value; RaisePropertyChanged("Persons"); } } 

    public event PropertyChangedEventHandler PropertyChanged; 
    void RaisePropertyChanged(string propname) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname)); 
    } 
} 

,並在最後查看:

<Window.Resources> 
    <local:EnumToSentenceConverterx:Key="EnumToSentenceConverter"/> 
    <local:NoneToCollapsedConverter x:Key="NoneToCollapsedConverter"/> 
    <local:EnumToStringConverter x:Key="EnumToStringConverter"/> 
</Window.Resources> 
<ListBox Name="lb" DataContext="{Binding}" ItemsSource="{Binding Persons}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel> 
       <TextBox Text="{Binding Name}" /> 
       <ComboBox Name="cb" ItemsSource="{Binding ElementName=lb, Path=DataContext.Types}" SelectedValue="{Binding TheType, Mode=TwoWay, Converter={StaticResource EnumToStringConverter}}" /> 
       <DockPanel Visibility="{Binding ElementName=cb, Path=SelectedValue, Converter={StaticResource NoneToCollapsedConverter}}"> 
        <Label Content="Sentence: " DockPanel.Dock="Left"/> 
        <TextBlock Text="{Binding TheType, Converter={StaticResource EnumToStringConverter}}" DockPanel.Dock="Right" VerticalAlignment="Center" /> 
       </DockPanel> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

請注意,您需要三個轉換器。一個集句部分的知名度,暈倒,其類型爲無:

public class NoneToCollapsedConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (value.ToString() == "None") 
      return Visibility.Collapsed; 
     return Visibility.Visible; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

兩個人是自我描述:

public class EnumToStringConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return value.ToString(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     return Enum.Parse(typeof(MyTypes), value.ToString()); 
    } 
} 

public class EnumToSentenceConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     switch ((MyTypes)value) 
     { 
      case MyTypes.IsA: 

       break; 
     } 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

希望它能幫助。

+0

你的想法與布爾值IsSentenced是相當有趣的,但如果有五十個Person的子類具有不同的屬性。會有五十個IsXYZ方法? – y434y

+0

在編輯部分查看我的建議 – Ron

相關問題