2016-04-01 27 views
1

MVVP programı geliştirirken, özellikleri değiştiğinde sınıfın değiştirilememesine dayanarak bir sorunla karşılaşıyorum. Örneğin, İçinde Delik Sayısı ve Çatlaklar bulunduran özelliklere sahip Tuğla taban sınıfına sahibiz.Altpropetikler değiştiğinde DependencyProperty geri çağrısı

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 

} 

Sınıf Duvar Tuğla ve Standart Tuğla ait koleksiyona sahiptir (DependencyProperty hem koymak zorunlu değildir - sadece gerekli geri arama göstermek için).

Ayrıca Duvar Tuğla ve Standart Tuğla arasında koleksiyonunda çatlak ve deliklerin sayısı hesaplamak aynı özelliklere Tuğla sahiptir. Standart Tuğladaki değiştirilen parametreler veya değiştirilen koleksiyonlar olduğunda her seferinde hesaplamalıdır (madde ekle, öğeyi kaldır veya öğede değiştirilmiş parametreler).

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); 
     } 
    } 

Bugüne kadar bu sorun için çözüm bulmak lazım asla: MainWindow.cs için

<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> 

ve kodu:

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 
} 

Ben bu test alanı için XAML kullanılan DependencyProperties kullanarak.
Yardımlarınız ve desteğiniz için umarım.

+1

Sorun nedir? Ayrıca, bana Class_Wall ve Class_Brick gibi temelde viewmodel sınıfları gibi görünüyor. DependencyProperties kullanmak yerine INotifyPropertyChanged uygulamak daha geleneksel olurdu. –

cevap

0

INotifyPropertyChanged sorunu çözmemde yardımcı olur. İşte
güncellenen Sınıflar Tuğla için bazı kod:

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 

} 

ve Duvar:

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 
} 

Ama DependencyProperty kullanarak aynı sonucu elde etmek için herhangi bir yolu var mı?