我正在使用Entity作为我的模型实现MVVM模式...当我在setter中实例化Model时,我向对象添加了propertychanged处理程序以捕获实体对象中的字段更改...
当我单步执行代码时,我发现在修改对象中的字段后,它会多次触发Property Change事件... 这让我相信我做错了什么......
我想将实体用作我的模型,因为我不想将对象重新创建为一个禁止的对象...
可以在下面的代码库中找到任何可能导致SelectedCompany.PropertyChanged在修改datagrid字段时触发多次的错误...
我原本以为那个属性改变了的事件只会发射一次而且有点困惑为什么它会多次发射......
在Setter中添加propertyChange事件是错误的吗?
这是ViewModel ......
public class CompanyMaintenanceVM : INotifyPropertyChanged
{
private ServiceHandler _serviceHandler = new ServiceHandler();
private bool _ignorePropertyChange = false; //by default we will execute on every property change...
public CompanyMaintenanceVM()
{
_companyList = new ObservableCollection<Company>(_serviceHandler.GetCompanies().ToList());
_selectedCompany = _companyList.First();
UpdateCommand = new RelayCommand(Update) { IsEnabled = true };
SearchCommand = new RelayCommand(Search) { IsEnabled = true };
_companyTypeList = new ObservableCollection<CompanyType>(_serviceHandler.GetCompanyTypes().ToList());
}
private string _selectedKey;
public string SelectedKey
{
get { return _selectedKey; }
set
{
if (_selectedKey != value)
{
_selectedKey = value;
OnPropertyChanged("SelectedKey");
}
}
}
private Company _selectedCompany = new Company();
public Company SelectedCompany
{
get { return _selectedCompany; }
set
{
if (_selectedCompany != value)
{
_selectedCompany = value;
OnPropertyChanged("SelectedCompany");
SelectedCompany.PropertyChanged += new PropertyChangedEventHandler(SelectedCompany_PropertyChanged);
}
}
}
private ObservableCollection<Company> _companyList;
public ObservableCollection<Company> CompanyList
{
get { return _companyList; }
set
{
_companyList = value;
OnPropertyChanged("CompanyList");
}
}
private ObservableCollection<CompanyType> _companyTypeList;
public ObservableCollection<CompanyType> CompanyTypeList
{
get { return _companyTypeList; }
set { _companyTypeList = value; }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
switch (propertyName)
{
case "SelectedKey":
if (_ignorePropertyChange == false)
{
SelectedKeyChanged();
}
_ignorePropertyChange = false;
break;
case "SelectedCompany":
_ignorePropertyChange = true;
SelectedKey = SelectedCompany.CompanyID;
break;
}
}
void SelectedCompany_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
//
}
#endregion
private void SelectedKeyChanged()
{
var companies = _serviceHandler.GetCompanyByID(SelectedKey);
if (companies.FirstOrDefault() != null)
{
CompanyList = new ObservableCollection<Company>(companies);
SelectedCompany = CompanyList.First();
}
else
{
MessageBox.Show("No Company Record Exsists Matching CompanyID " + _selectedKey);
}
}
private ICommand _updateCommand;
public ICommand UpdateCommand
{
get
{
if (_updateCommand == null)
_updateCommand = new Updater();
return _updateCommand;
}
set
{
_updateCommand = value;
}
}
private class Updater : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(Object parameter)
{
}
#endregion
}
private void Update()
{
_serviceHandler.UpdateRepository(SelectedCompany);
_serviceHandler.CommitRepository();
}
private ICommand _searchCommand;
public ICommand SearchCommand
{
get
{
if (_searchCommand == null)
_searchCommand = new Searcher();
return _searchCommand;
}
set
{
_searchCommand = value;
}
}
private class Searcher : ICommand
{
#region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(Object parameter)
{
}
#endregion
}
private void Search()
{
}
}
这是XAML ......
<Window x:Class="XERP.Client.WPF.CompanyMaintenance.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Company Maintenance" Height="800" Width="600">
<Grid>
<Grid.Resources>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="422*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="156*"></ColumnDefinition>
<ColumnDefinition Width="422*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock HorizontalAlignment="Center" Grid.Column="1" Text="Company Maintenance Form"
FontSize="13"
Margin="130,3,129,5"></TextBlock>
<Menu IsMainMenu="True" Grid.ColumnSpan="2" Margin="2,2,370,2" Width="180">
<MenuItem Header="_File" >
<MenuItem Header="_New" Command="New">
</MenuItem>
<MenuItem Header="_Save"
IsCheckable="True"
Command="{Binding UpdateCommand}" Click="SaveMenuItem_Click">
</MenuItem>
<MenuItem Header="_Exit" Command="Close">
</MenuItem>
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Header="_Cut" Command="Cut">
</MenuItem>
<MenuItem Header="_Copy" Command="Copy">
</MenuItem>
<MenuItem Header="_Paste" Command="Paste">
</MenuItem>
</MenuItem>
<MenuItem Header="_Tools" />
<MenuItem Header="_Actions" />
<MenuItem Header="_Help" />
</Menu>
<GridSplitter Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" Width="4" Background="Yellow"/>
<ListView Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="5"
ItemsSource="{Binding CompanyList}"
SelectedItem="{Binding SelectedCompany, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True"
>
<ListView.ItemTemplate>
<DataTemplate >
<TextBlock Text="{Binding Path=CompanyID, Mode=TwoWay}" Margin="5"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TabControl Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<TabItem Header="Detail">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="46"></RowDefinition>
<RowDefinition Height="657*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="165*"></ColumnDefinition>
<ColumnDefinition Width="246*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Horizontal" Grid.Row="0" Grid.ColumnSpan="2">
<Button Width="100" Height="20" Margin="10"
Command="{Binding SearchCommand}">Company...</Button>
<TextBox Width="100" Height="20" Margin=" 10"
Text="{Binding Path=SelectedKey, Mode=TwoWay}"
/>
</StackPanel>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="1" Grid.Column="0">
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Top" Margin="8">Name:</TextBlock>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Top" Margin="8">Description:</TextBlock>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Top" Margin="8">Type:</TextBlock>
</StackPanel>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Orientation="Vertical" Grid.Row="1" Grid.Column="1">
<TextBox HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" Width="200"
Text="{Binding Path=SelectedCompany.Name, Mode=TwoWay}"
/>
<TextBox
HorizontalAlignment="Left" VerticalAlignment="Top" Margin="5" Width="200"
Text="{Binding Path=SelectedCompany.Description, Mode=TwoWay}"
/>
<ComboBox HorizontalAlignment="Left" Width="200" Margin="5"
ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CompanyTypeList, Mode=TwoWay}"
DisplayMemberPath="Type"
SelectedValuePath="CompanyTypeID"
SelectedValue="{Binding Path=SelectedCompany.CompanyTypeID, Mode=TwoWay}"/>
<TextBox Height="23" Name="ghost" Width="0" />
</StackPanel>
</Grid>
</TabItem>
<TabItem Header="List" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid>
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding CompanyList}"
SelectedItem="{Binding SelectedCompany, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionMode="Single"
IsSynchronizedWithCurrentItem="True"
>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding CompanyID, Mode=TwoWay}"
Header="ID" Width="auto" IsReadOnly="True"/>
<DataGridTextColumn Binding="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
Header="Name" Width="Auto"/>
<DataGridTextColumn Binding="{Binding Description, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
Header="Description" Width="Auto"/>
<DataGridComboBoxColumn Header="Type" Width="Auto"
SelectedValueBinding ="{Binding CompanyTypeID, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
DisplayMemberPath="Type"
SelectedValuePath="CompanyTypeID">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CompanyTypeList, Mode=TwoWay}"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.CompanyTypeList, Mode=TwoWay}"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
</DataGrid>
<TextBox Height="23" Name="ghost2" Width="0" />
</Grid>
</TabItem>
</TabControl>
</Grid>
</Window>
答案 0 :(得分:0)
注意使用带有双向绑定的selectitem并且IsSynchronizedWithCurrentItem =“True” - 也许你可以在那里进行往返。
以下是您的原因?
if (_selectedCompany != value)
{
_selectedCompany = value;
OnPropertyChanged("SelectedCompany");
SelectedCompany.PropertyChanged += new PropertyChangedEventHandler(SelectedCompany_PropertyChanged); //<-- whats that?
}
为什么要这样做?
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
switch (propertyName)//why you do this?
{
case "SelectedKey":
if (_ignorePropertyChange == false)
{
SelectedKeyChanged();
}
_ignorePropertyChange = false;
break;
case "SelectedCompany":
_ignorePropertyChange = true;
SelectedKey = SelectedCompany.CompanyID;
break;
}
}