在开发MVVP程序时,当属性发生变化时,我会根据类的不可读性而碰到一些问题。
例如,我们有基类 Brick ,它具有表示孔数和裂缝的属性。
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
}
类 Wall 具有 Bricks 和标准块的集合(在DependencyProperty中放置两者不是强制性的 - 仅用于演示所需的回调)。< / p>
Wall 与 Brick 具有相同的属性,用于计算砖块集合和标准砖>中的裂缝和孔洞数。每当更改标准砖中的参数或更改集合时,Tey必须计算(添加项目,删除项目或更改项目中的参数)。
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
}
我将这个XAML用于测试领域:
<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>
和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);
}
}
直到今天,我还没有找到解决这个问题的方法,使用DependencyProperties 希望得到您的帮助和支持。
答案 0 :(得分:0)
Well, INotifyPropertyChanged helps solve my problem.
Here some code for updated Classes 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
}
and Wall:
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
}
But is there any way to achieve same result using DependencyProperty?