2017-02-19 42 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

相关问题