1

Bei der Entwicklung von MVVP-Programm kollidiere ich mit einem Problem basierend auf Unsensibilität der Klasse, wenn es Eigenschaften geändert.Rückruf von DependencyProperty bei geänderten Untereigenschaften

Zum Beispiel haben wir Basisklasse Brick, die Eigenschaften haben Anzahl der Löcher und Risse darin indizieren.

class Class_Brick : DependencyObject 
{ 

    public Class_Brick() 
    { 
    } 

    #region DependencyProperties 

    public static DependencyProperty NumberOfHoles_Property = DependencyProperty.Register("NumberOfHoles", typeof(int), typeof(Class_Brick), 
     new FrameworkPropertyMetadata() 
     { 
      DefaultValue = 0, 
      BindsTwoWayByDefault = true, 
      DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged 
     }); 

    public static DependencyProperty NumberOfCracks_Property = DependencyProperty.Register("NumberOfCracks", typeof(int), typeof(Class_Brick), 
     new FrameworkPropertyMetadata() 
     { 
      DefaultValue = 0, 
      BindsTwoWayByDefault = true, 
      DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged 
     }); 

    #endregion 

    #region Properties 

    public int NumberOfHoles 
    { 
     get { return (int)GetValue(NumberOfHoles_Property); } 
     set { SetValue(NumberOfHoles_Property, value); } 
    } 

    public int NumberOfCracks 
    { 
     get { return (int)GetValue(NumberOfCracks_Property); } 
     set { SetValue(NumberOfCracks_Property, value); } 
    } 

    #endregion 

} 

Klasse Wand hat Sammlung von Bricks und Standard Brick (setzen beide in DependencyProperty ist nicht zwingend - nur benötigt Rückruf zu demonstrieren).

Auch Wand hat gleiche Eigenschaften wie Brick, die Anzahl der Risse und Löcher in Sammlung von Bricks und Standard Brick berechnen. Tey muss jedes Mal berechnen, wenn die Parameter im Standard Brick geändert oder die Kollektion geändert wurde (Artikel hinzufügen, Artikel entfernen oder Parameter im Artikel ändern).

class Class_Wall : DependencyObject 
{ 
    public Class_Wall() 
    { 
     SetValue(Standard_Brick_Property, new Class_Brick()); 
     SetValue(Bricks_Property, new ObservableCollection<Class_Brick>()); 
    } 

    #region DependencyProperties 

    public static DependencyProperty NumberOfHoles_Property = DependencyProperty.Register("NumberOfHoles", typeof(int), typeof(Class_Wall), 
     new FrameworkPropertyMetadata() 
     { 
      DefaultValue = 0, 
      BindsTwoWayByDefault = true, 
      DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged 
     }); 

    public static DependencyProperty NumberOfCracks_Property = DependencyProperty.Register("NumberOfCracks", typeof(int), typeof(Class_Wall), 
     new FrameworkPropertyMetadata() 
     { 
      DefaultValue = 0, 
      BindsTwoWayByDefault = true, 
      DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged 
     }); 

    public static DependencyProperty Standard_Brick_Property = DependencyProperty.Register("Standard_Brick", typeof(Class_Brick), typeof(Class_Wall), 
     new FrameworkPropertyMetadata() 
     { 
      BindsTwoWayByDefault = true, 
      DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged, 
      PropertyChangedCallback = new System.Windows.PropertyChangedCallback(On_Property_Change) 
     }); 

    public static DependencyProperty Bricks_Property = DependencyProperty.Register("Bricks", typeof(ObservableCollection<Class_Brick>), typeof(Class_Wall), 
     new FrameworkPropertyMetadata() 
     { 
      BindsTwoWayByDefault = true, 
      DefaultUpdateSourceTrigger = System.Windows.Data.UpdateSourceTrigger.PropertyChanged, 
      PropertyChangedCallback = new System.Windows.PropertyChangedCallback(On_Property_Change) 
     }); 

    #endregion 

    #region Inner Methods 

    public static void On_Property_Change(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ObservableCollection<Class_Brick> inWall; 

     int wallCracks = 0; 
     int wallHoles = 0; 

     if (e.Property == Bricks_Property) 
     { 
      inWall = e.NewValue as ObservableCollection<Class_Brick>; 
      Class_Brick mainItem = (Class_Brick)d.GetValue(Standard_Brick_Property); 
      wallCracks = mainItem.NumberOfCracks; 
      wallHoles = mainItem.NumberOfHoles; 
     } 
     else //if (e.Property == Standard_Brick_Property) 
     { 
      inWall = (ObservableCollection<Class_Brick>)d.GetValue(Bricks_Property); 
      Class_Brick newItem = e.NewValue as Class_Brick; 
      wallCracks = newItem.NumberOfCracks; 
      wallHoles = newItem.NumberOfHoles; 
     } 

     if (inWall != null) 
     { 

      foreach (Class_Brick brick in inWall) 
      { 
       wallCracks += brick.NumberOfCracks; 
       wallHoles += brick.NumberOfHoles; 
      } 

      d.SetValue(Home_Quest.Class_Wall.NumberOfCracks_Property, wallCracks); 
      d.SetValue(Home_Quest.Class_Wall.NumberOfHoles_Property, wallHoles); 
     } 

    } 

    #endregion 

    #region Properties 

    public int NumberOfHoles 
    { 
     get { return (int)GetValue(NumberOfHoles_Property); } 
    } 

    public int NumberOfCracks 
    { 
     get { return (int)GetValue(NumberOfCracks_Property); } 
    } 

    public Class_Brick Standard_Brick 
    { 
     get { return (Class_Brick)GetValue(Standard_Brick_Property); } 
     set { SetValue(Standard_Brick_Property, value); } 
    } 

    public ObservableCollection<Class_Brick> Bricks 
    { 
     get { return (ObservableCollection<Class_Brick>)GetValue(Bricks_Property); } 
     set { SetValue(Bricks_Property, value); } 
    } 

    #endregion 
} 

ich verwendet, um dieses XAML für das Testfeld:

<DockPanel LastChildFill="True"> 
    <TextBlock Text="Wall" 
       DockPanel.Dock="Top" 
       HorizontalAlignment="Center"/> 

    <Grid> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition Width="*"/> 
      <ColumnDefinition Width="*"/> 
     </Grid.ColumnDefinitions> 
     <Grid.RowDefinitions> 
      <RowDefinition Height="*"/> 
      <RowDefinition Height="*"/> 
     </Grid.RowDefinitions> 

     <DockPanel Grid.Column="0" 
        Grid.Row="0" Grid.RowSpan="2" 
        LastChildFill="True"> 

      <TextBlock Text="Bricks" 
         DockPanel.Dock="Top" /> 

      <Button Content="-" DockPanel.Dock="Bottom" 
        Click="btn_Remove" /> 
      <Button Content="+" DockPanel.Dock="Bottom" 
        Click="btn_Add" /> 

      <ListBox x:Name="lB_Bricks" 
        ItemsSource="{Binding Path=Bricks}" 
        HorizontalContentAlignment="Stretch"> 
       <ListBox.ItemTemplate> 
        <DataTemplate> 
         <Border Margin="2" 
           BorderBrush="Azure" 
           BorderThickness="1"> 
          <Grid> 
           <Grid.ColumnDefinitions> 
            <ColumnDefinition Width="*"/> 
            <ColumnDefinition Width="*"/> 
           </Grid.ColumnDefinitions> 
           <Grid.RowDefinitions> 
            <RowDefinition Height="Auto"/> 
            <RowDefinition Height="Auto"/> 
           </Grid.RowDefinitions> 

           <TextBlock Text="Holes" 
              Grid.Column="0" Grid.Row="0"/> 
           <TextBox Text="{Binding Path=NumberOfHoles, Mode=TwoWay}" 
             Grid.Column="1" Grid.Row="0" 
             TextAlignment="Center"/> 

           <TextBlock Text="Cracks" 
              Grid.Column="0" Grid.Row="1"/> 
           <TextBox Text="{Binding Path=NumberOfCracks, Mode=TwoWay}" 
             Grid.Column="1" Grid.Row="1" 
             TextAlignment="Center"/> 

          </Grid> 
         </Border>        
        </DataTemplate> 
       </ListBox.ItemTemplate> 

      </ListBox> 

     </DockPanel> 

     <DockPanel Grid.Column="1" 
        Grid.Row="0" 
        LastChildFill="True" 
        DataContext="{Binding Path=Standard_Brick}"> 

      <TextBlock Text="Standard Brick" 
         DockPanel.Dock="Top" /> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*"/> 
        <ColumnDefinition Width="*"/> 
       </Grid.ColumnDefinitions> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="*"/> 
        <RowDefinition Height="*"/> 
       </Grid.RowDefinitions> 

       <TextBlock Text="Holes" 
          Grid.Column="0" Grid.Row="0"/> 
       <TextBox Text="{Binding Path=NumberOfHoles, Mode=TwoWay}" 
         Grid.Column="1" Grid.Row="0" 
         TextAlignment="Center"/> 

       <TextBlock Text="Cracks" 
          Grid.Column="0" Grid.Row="1"/> 
       <TextBox Text="{Binding Path=NumberOfCracks, Mode=TwoWay}" 
         Grid.Column="1" Grid.Row="1" 
         TextAlignment="Center"/> 

      </Grid> 

     </DockPanel> 

     <DockPanel Grid.Column="1" 
        Grid.Row="1" 
        LastChildFill="True"> 

      <TextBlock Text="Resulted Cracks and Holes" 
         DockPanel.Dock="Top" /> 

      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*"/> 
        <ColumnDefinition Width="*"/> 
       </Grid.ColumnDefinitions> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="*"/> 
        <RowDefinition Height="*"/> 
       </Grid.RowDefinitions> 

       <TextBlock Text="Holes" 
          Grid.Column="0" Grid.Row="0"/> 
       <TextBox Text="{Binding Path=NumberOfHoles}" 
         Grid.Column="1" Grid.Row="0" 
         IsReadOnly="True" 
         TextAlignment="Center"/> 

       <TextBlock Text="Cracks" 
          Grid.Column="0" Grid.Row="1"/> 
       <TextBox Text="{Binding Path=NumberOfCracks}" 
         Grid.Column="1" Grid.Row="1" 
         IsReadOnly="True" 
         TextAlignment="Center"/> 

      </Grid> 

     </DockPanel> 

    </Grid> 

</DockPanel> 

und Code für MainWindow.cs:

public MainWindow() 
    { 
     InitializeComponent(); 
     this.DataContext = currentWall; 
    } 

    Class_Wall currentWall = new Class_Wall(); 

    private void btn_Add(object sender, RoutedEventArgs e) 
    { 
     currentWall.Bricks.Add(new Class_Brick()); 
    } 

    private void btn_Remove(object sender, RoutedEventArgs e) 
    { 
     Class_Brick selectedBrick = this.lB_Bricks.SelectedItem as Class_Brick; 
     if (selectedBrick != null) 
     { 
      currentWall.Bricks.Remove(selectedBrick); 
     } 
    } 

Bis heute habe ich nie die Lösung für dieses Problem finden mit DependencyProperties.
Hoffnung für Ihre Hilfe und Unterstützung.

+1

Was ist das Problem? Außerdem sieht es so aus, als wären Class_Wall und Class_Brick im Wesentlichen Viewmodel-Klassen. Es wäre eher üblich, INotifyPropertyChanged zu implementieren, anstatt DependencyProperties zu verwenden. –

Antwort

0

Nun, INotifyPropertyChanged hilft mein Problem zu lösen.
Hier einige Code für aktualisierte Klassen Brick:

class Class_Brick_NPC : INotifyPropertyChanged 
{ 

    public Class_Brick_NPC() 
    { 

    } 

    #region Event Functions 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 

     if(handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    #endregion 

    #region Inner Parametres 

    private int numberOfHoles = 0; 

    private int numberOfCracks = 0; 

    #endregion 

    #region Parametres 

    public int NumberOfHoles 
    { 
     get { return numberOfHoles; } 
     set 
     { 
      numberOfHoles = value; 

      OnPropertyChanged("NumberOfHoles"); 
     } 
    } 

    public int NumberOfCracks 
    { 
     get { return numberOfCracks; } 
     set 
     { 
      numberOfCracks = value; 

      OnPropertyChanged("NumberOfCracks"); 
     } 
    } 

    #endregion 

} 

und Wand:

class Class_Wall_NPC : INotifyPropertyChanged 
{ 
    public Class_Wall_NPC() 
    { 
     standard_Brick.PropertyChanged += InnerUpdate; 
    } 

    #region Event Methods 
    public event PropertyChangedEventHandler PropertyChanged; 

    protected void OnPropertyChanged(string name) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 

     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    public void InnerUpdate(object sender, PropertyChangedEventArgs args) 
    { 
     if (args.PropertyName == "NumberOfHoles") 
     { 
      OnPropertyChanged("NumberOfHoles"); 
     } 
     else if (args.PropertyName == "NumberOfCracks") 
     { 
      OnPropertyChanged("NumberOfCracks"); 
     } 
    } 
    #endregion 

    #region Inner Properties 
    private ObservableCollection<Class_Brick_NPC> bricks = new ObservableCollection<Class_Brick_NPC>(); 

    private Class_Brick_NPC standard_Brick = new Class_Brick_NPC(); 

    private int numberOfHoles = 0; 

    private int numberOfCracks = 0; 
    #endregion 

    #region Properties 

    public ObservableCollection<Class_Brick_NPC> Bricks 
    { 
     get { return bricks; } 
     set 
     { 
      bricks = value; 

      OnPropertyChanged("Bricks"); 
     } 
    } 

    public Class_Brick_NPC Standard_Brick 
    { 
     get { return standard_Brick; } 
     set 
     { 
      standard_Brick = value; 
     } 
    } 



    public int NumberOfHoles 
    { 
     get 
     { 
      int wallHoles = standard_Brick.NumberOfHoles; 

      foreach (Class_Brick_NPC brick in bricks) 
      { 
       wallHoles += brick.NumberOfHoles; 
      } 

      return wallHoles; 
     }    
    } 

    public int NumberOfCracks 
    { 
     get 
     { 
      int wallCracks = standard_Brick.NumberOfCracks; 

      foreach (Class_Brick_NPC brick in bricks) 
      { 
       wallCracks += brick.NumberOfCracks;      
      } 

      return wallCracks; 
     }    
    } 

    #endregion 

    #region Methods 

    public void Add_Brick(Class_Brick_NPC addedItem) 
    { 
     bricks.Add(addedItem); 

     addedItem.PropertyChanged += InnerUpdate; 

     OnPropertyChanged("Bricks"); 
    } 

    public void Remove_Brick(Class_Brick_NPC removedItem) 
    { 
     bricks.Remove(removedItem); 
     removedItem.PropertyChanged -= InnerUpdate; 

     OnPropertyChanged("Bricks"); 
     OnPropertyChanged("NumberOfHoles"); 
     OnPropertyChanged("NumberOfCracks"); 
    } 

    #endregion 
} 

Aber ist es eine Möglichkeit, gleiches Ergebnis mit DependencyProperty zu erreichen?

Verwandte Themen