我的viewmodel中有一个可观察的集合,如下所示。不完美但只是代码,如下所示填充可观察集合并将其绑定到datagrid。我在datagrid旁边还有两个按钮,一个用于upcommand,另一个用于down命令。当我单击upbutton时,一切正常,所选行向上移动并且序列顺序更新,Observable Collection也会更新。但是这些更改并没有绑定到DataGrid。同样对于down命令。我的观点如下。只有视图没有更新,命令才能正常工作。 。请帮忙。 问题在于可观察的收集,向上移动和向下移动。
视图模型:
public class JobConfigurationViewModel : BindableBase
{
public JobConfigurationLogic JobConfigurationLogic =
new JobConfigurationLogic(new JobConfigurationResultsRepository());
public SrcDestConfigurationLogic SrcDestConfigurationLogic =
new SrcDestConfigurationLogic(new SrcDestCofigurationRepository());
private string _enterprise;
public string Enterprise
{
get { return _enterprise; }
set { SetProperty(ref _enterprise, value); }
}
private int currentJobID;
private int currentSequence;
private int previousJobID;
private int previousSequence;
private string _site;
public string Site
{
get { return _site; }
set { SetProperty(ref _site, value); }
}
private int _siteID;
public int SiteID
{
get { return _siteID; }
set { SetProperty(ref _siteID, value); }
}
private ObservableCollection<JobConfigurationResults> _jobEntities;
public ObservableCollection<JobConfigurationResults> JobEntities
{
get { return _jobEntities; }
set
{
SetProperty(ref _jobEntities, value);
//JobEntities.CollectionChanged += JobEntities_CollectionChanged;
OnPropertyChanged("JobEntities");
}
}
//void JobEntities_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
//{
// if (e.OldItems != null)
// {
// foreach (var item in e.OldItems)
// {
// this.GetJobConfigurationResults();
// }
// }
//}
//Source System List for Job
private List<SourceSiteSystem> _lstJobSrcSystems;
public List<SourceSiteSystem> LstJobSrcSystems
{
get { return _lstJobSrcSystems; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _lstJobSrcSystems, value);
}
}
//Deestination System List for Job
private List<DestinationSiteSystem> _lstJobDestSystems;
public List<DestinationSiteSystem> LstJobDestSystems
{
get { return _lstJobDestSystems; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _lstJobDestSystems, value);
}
}
//the Selected Source Site system ID
private int _selectedSrcSiteSystemId = 0;
public int SelectedSrcSiteSystemId
{
get { return _selectedSrcSiteSystemId; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _selectedSrcSiteSystemId, value);
}
}
//the Selected Source Site system from the dropdown
private SourceSiteSystem _selectedSrcSiteSystem;
public SourceSiteSystem SelectedSrcSiteSystem
{
get { return _selectedSrcSiteSystem; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
if (value != null)
{
SetProperty(ref _selectedSrcSiteSystem, value);
SelectedSrcSiteSystemId = SelectedSrcSiteSystem.SiteSystemId;
}
}
}
//the Selected Destination Site system ID
private int _selectedDestSiteSystemId = 0;
public int SelectedDestSiteSystemId
{
get { return _selectedDestSiteSystemId; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
SetProperty(ref _selectedDestSiteSystemId, value);
}
}
//the Selected Destination Site system from the dropdown
private DestinationSiteSystem _selectedDestSiteSystem;
public DestinationSiteSystem SelectedDestSiteSystem
{
get { return _selectedDestSiteSystem; }
set
{
//Using bindable base setproperty method instead of older inotify prop changed method
if (value != null)
{
SetProperty(ref _selectedDestSiteSystem, value);
SelectedDestSiteSystemId = SelectedDestSiteSystem.SiteSystemId;
}
}
}
private JobConfigurationResults _jeJobConfigurationResults;
public JobConfigurationResults JEJobConfigurationResults
{
get { return _jeJobConfigurationResults; }
set { _jeJobConfigurationResults = value; }
}
private List<JobTaskConfiguration> _taskSelectionList = new List<JobTaskConfiguration>();
private CancellationTokenSource _source;
private RelayCommand<object> _commandSaveInstance;
private RelayCommand<object> _hyperlinkInstance;
private RelayCommand<object> _commandRunJob;
private RelayCommand<object> _upCommand;
private RelayCommand<object> _downCommand;
private IEventAggregator _aggregator;
/// <summary>
/// This is a Subscriber to the Event published by EnterpriseViewModel
/// </summary>
/// <param name="agg"></param>
public JobConfigurationViewModel(IEventAggregator agg)
{
_aggregator = agg;
PubSubEvent<Message> evt = _aggregator.GetEvent<PubSubEvent<Message>>();
evt.Subscribe(message => Enterprise = message.Enterprise.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => Site = message.Site.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => SiteID = message.SiteID, ThreadOption.BackgroundThread);
//evt.Unsubscribe();
StartPopulate();
}
private async void StartPopulate()
{
await TaskPopulate();
}
//This is to ensure that the publisher has published the data that is needed for display in this workspace
private bool TaskProc()
{
Thread.Sleep(500);
PubSubEvent<Message> evt = _aggregator.GetEvent<PubSubEvent<Message>>();
evt.Subscribe(message => Enterprise = message.Enterprise.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => Site = message.Site.ToString(), ThreadOption.BackgroundThread);
evt.Subscribe(message => SiteID = message.SiteID, ThreadOption.BackgroundThread);
return DoPopulate();
}
private Task<bool> TaskPopulate()
{
_source = new CancellationTokenSource();
return Task.Factory.StartNew<bool>(TaskProc, _source.Token);
}
/// <summary>
/// This method handles the populating of the Source and Destination Dropdowns and the Job entity and Task Datagrid
/// This is mainly driven by the Site selected in the previous workspace
/// </summary>
/// <returns></returns>
private bool DoPopulate()
{
PopulateSourceDestinations(this.SiteID);
return true;
}
/// <summary>
/// this method displays all entities and tasks for the site.
/// This is done async so that the Publisher thread is not held up
/// </summary>
public void GetJobConfigurationResults()
{
if (SelectedSrcSiteSystem == null)
{
SelectedSrcSiteSystem = LstJobSrcSystems[0];
}
if (SelectedDestSiteSystem == null)
{
SelectedDestSiteSystem = LstJobDestSystems[0];
}
SelectedSrcSiteSystemId = SelectedSrcSiteSystem.SiteSystemId;
SelectedDestSiteSystemId = SelectedDestSiteSystem.SiteSystemId;
var jobConfigurationResults = new JobConfigurationResults
{
SourceId = SelectedSrcSiteSystemId,
DestinationId = SelectedDestSiteSystemId
};
JobEntities = new ObservableCollection<JobConfigurationResults>();
JobEntities = JobConfigurationLogic.GetResults(jobConfigurationResults.SourceId,
jobConfigurationResults.DestinationId);
_taskSelectionList = new List<JobTaskConfiguration>(JobEntities.Count * 3);
}
/// <summary>
/// //Adding a method to pupulate the Source and Destination dropdown lists.
/// This is done async so that the Publisher thread is not held up
/// </summary>
///
///
public async void PopulateSourceDestinations(int siteId)
{
this.LstJobSrcSystems = SrcDestConfigurationLogic.LoadSourceSiteSystems(siteId);
this.LstJobDestSystems = SrcDestConfigurationLogic.LoadDestinationSystems(siteId);
GetJobConfigurationResults();
}
public ICommand HyperlinkCommand
{
get
{
if (_hyperlinkInstance == null)
_hyperlinkInstance = new RelayCommand<object>(openDialog);
return _hyperlinkInstance;
}
}
private void openDialog(object obj)
{
JobConfigurationResults results = obj as JobConfigurationResults;
JEJobConfigurationResults = JobEntities.SingleOrDefault(x => x.JobEntityId == results.JobEntityId);
}
public ICommand CommandSave
{
get
{
if (_commandSaveInstance == null)
_commandSaveInstance = new RelayCommand<object>(saveJobConfigurationChanges);
return _commandSaveInstance;
}
}
public ICommand CommandRunJob
{
get { return _commandRunJob ?? (_commandRunJob = new RelayCommand<object>(RunJob)); }
}
/// <summary>
/// this saves all the changes in the selection made by the user
/// </summary>
/// <param name="ob"></param>
public void saveJobConfigurationChanges(object ob)
{
foreach (var job in JobEntities)
{
JobConfigurationLogic.UpdateSequence(job.SequenceOrder, job.JobEntityId); //Save Sequence Changes
int jobEntityId = job.JobEntityId;
foreach (var task in job.TaskDetails)
{
int id = task.JobTask_ID;
bool isSelected = task.IsSelected;
_taskSelectionList.Add(task);
}
}
JobConfigurationLogic.UpdateTaskSelection(_taskSelectionList);
}
public ICommand UpCommand
{
get
{
if (_upCommand == null)
_upCommand = new RelayCommand<object>(MoveUp);
return _upCommand;
}
}
private void MoveUp(object obj)
{
if (obj != null)
{
JobConfigurationResults results = obj as JobConfigurationResults;
currentJobID = results.JobEntityId;
currentSequence = results.SequenceOrder - 1;
JobConfigurationResults previousResult =
JobEntities.FirstOrDefault(n => n.SequenceOrder == currentSequence);
try
{
previousJobID = previousResult.JobId;
previousSequence = previousResult.SequenceOrder;
int newindex = JobEntities.IndexOf(results);
int oldindex = JobEntities.IndexOf(previousResult);
JobEntities[newindex].SequenceOrder = previousResult.SequenceOrder;
JobEntities[oldindex].SequenceOrder = results.SequenceOrder + 1;
//foreach (var i in JobEntities)
//{
// MessageBox.Show(i.EntityName + " " + i.SequenceOrder);
//}
}
catch (NullReferenceException)
{
MessageBox.Show("You have reached the top");
}
}
else
{
MessageBox.Show("Select a row first");
}
}
public ICommand DownCommand
{
get
{
if (_downCommand == null)
_downCommand = new RelayCommand<object>(MoveDown);
return _downCommand;
}
}
private void MoveDown(object obj)
{
if (obj != null)
{
JobConfigurationResults results = obj as JobConfigurationResults;
currentJobID = results.JobEntityId;
currentSequence = results.SequenceOrder + 1;
JobConfigurationResults previousResult =
JobEntities.FirstOrDefault(n => n.SequenceOrder == currentSequence);
try
{
previousJobID = previousResult.JobId;
previousSequence = previousResult.SequenceOrder;
int newindex = JobEntities.IndexOf(results);
int oldindex = JobEntities.IndexOf(previousResult);
JobEntities[newindex].SequenceOrder = previousResult.SequenceOrder;
JobEntities[oldindex].SequenceOrder = results.SequenceOrder - 1;
foreach (var i in JobEntities)
{
MessageBox.Show(i.EntityName + " " + i.SequenceOrder);
}
}
catch (NullReferenceException)
{
MessageBox.Show("You cannot move further down");
}
}
else
{
MessageBox.Show("Select a row first");
}
}
/// <summary>
/// Execute an etl job using the current job id
/// </summary>
private void RunJob(object obj)
{
JobEngine jobEngine = new JobEngine();
var jobId = JobEntities[0].JobId;
jobEngine.ProcessJob(jobId);
}
}
View.XAML:
<UserControl.Resources>
<DataTemplate x:Key="ItemTemplate1">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="ItemTemplate2">
<StackPanel>
<TextBlock Text="{Binding Status}"/>
</StackPanel>
</DataTemplate>
<Style TargetType="{x:Type Border}">
<Setter Property="Background" Value="Bisque" />
<Setter Property="TextBlock.FontSize" Value="14" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="HorizontalAlignment" Value="Stretch" />
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="3*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="0.14*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Grid.ColumnSpan="2">
<TextBlock>
<Label FontSize="16">Enterprise:</Label>
<Label Name="lblEnterprise" FontSize="16" Content="{Binding Enterprise}" />
<Label FontSize="16">Site:</Label>
<Label Name="lblSite" FontSize="16" Content="{Binding Site}" HorizontalAlignment="Right" />
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="1" Grid.Column="0">
<TextBlock>
<Label FontSize="16">Source System:</Label>
<ComboBox Name="CmbSource" Margin="3" SelectedIndex="0" Width="220" ItemsSource="{Binding LstJobSrcSystems}" SelectedItem="{Binding SelectedSrcSiteSystem, Mode=TwoWay}" DisplayMemberPath ="SourceSystemType"></ComboBox>
</TextBlock>
</StackPanel>
<StackPanel Grid.Column="0" Grid.Row="1">
<TextBlock HorizontalAlignment="Right" Margin="2,2,14,2">
<Label FontSize="16">Destination System:</Label>
<ComboBox Name="CmbDestination" SelectedIndex="0" Margin="2" Width="220" ItemsSource="{Binding LstJobDestSystems}" SelectedItem="{Binding SelectedDestSiteSystem, Mode=TwoWay}" DisplayMemberPath ="DestinationSystemType"></ComboBox>
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="2" Grid.ColumnSpan="2" Margin="0,2,0,46" Grid.RowSpan="3">
<Border BorderThickness="1" Width="{Binding ElementName=dgEntities,Path=Width}" Margin="35,48,60,48" Height="{Binding ElementName=grd,Path=Height}">
<Grid Name="grd" Height="30" Width="{Binding ElementName=JobConfigCol,Path=Width}" ShowGridLines="True">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="c1" Width="82*"/>
<ColumnDefinition x:Name="c2" Width="83*"/>
<ColumnDefinition x:Name="c3" Width="83*"/>
<ColumnDefinition x:Name="c4" Width="96*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" HorizontalAlignment="Center" FontWeight="Bold" FontSize="16" Margin="24,0,78,0" Width="62" Content="Extract"/>
<Label Grid.Column="1" HorizontalAlignment="Center" FontWeight="Bold" FontSize="16" Margin="40,0,38,0" Width="88" Content="Transform"/>
<Label Grid.Column="2" HorizontalAlignment="Center" FontWeight="Bold" FontSize="16" Margin="66,0,54,0" Width="46" Content="Load"/>
</Grid>
</Border>
<DataGrid x:Name="dgEntities" Width="690" Height="370" Margin="40,-48,65,-8" CanUserAddRows="false" SelectionMode="Single" ItemsSource="{Binding}" AutoGenerateColumns="False" CanUserSortColumns="False">
<DataGrid.DataContext>
<CollectionViewSource x:Name="CollectionViewSource" Source="{Binding Path=JobEntities,Mode=TwoWay,NotifyOnTargetUpdated=True}">
</CollectionViewSource>
</DataGrid.DataContext>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Status" Width="138" MaxWidth="138">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Margin="5" Content="{Binding TaskDetails[0].Status,Mode=TwoWay,NotifyOnTargetUpdated=True}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.HyperlinkCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Foreground="Blue" Cursor="Hand" MouseDoubleClick="Control_OnMouseDoubleClick" >
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn MinWidth="{Binding ElementName=c1,Path=ActualWidth}">
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderExtract" Checked="ChkHeaderExtract_OnChecked" Unchecked="ChkHeaderExtract_OnUnchecked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" Name="chkExtract" IsChecked="{Binding TaskDetails[0].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Status" Width="138" MaxWidth="138">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Margin="5" Content="{Binding TaskDetails[1].Status,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.HyperlinkCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Cursor="Hand" Foreground="Blue" MouseDoubleClick="Control_OnMouseDoubleClick_2" >
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn MinWidth="{Binding ElementName=c2,Path=ActualWidth}">
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderTransform" Checked="ChkHeaderTransform_OnChecked" Unchecked="ChkHeaderTransform_OnUnchecked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" Name="chkTransform" IsChecked="{Binding TaskDetails[1].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Status" Width="138" MaxWidth="138">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Margin="5" Content="{Binding TaskDetails[2].Status,Mode=TwoWay,NotifyOnTargetUpdated=True}" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=DataContext.HyperlinkCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Cursor="Hand" Foreground="Blue" MouseDoubleClick="Control_OnMouseDoubleClick" >
<Button.Template>
<ControlTemplate TargetType="Button">
<TextBlock TextDecorations="Underline">
<ContentPresenter />
</TextBlock>
</ControlTemplate>
</Button.Template>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn MinWidth="{Binding ElementName=c3,Path=ActualWidth}">
<DataGridTemplateColumn.Header>
<CheckBox Name="chkHeaderLoad" Checked="ChkHeaderLoad_OnChecked" Unchecked="ChkHeaderLoad_OnUnchecked"></CheckBox>
</DataGridTemplateColumn.Header>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox HorizontalAlignment="Center" VerticalAlignment="Center" Name="chkLoad" IsChecked="{Binding TaskDetails[2].IsSelected,Mode=TwoWay,NotifyOnTargetUpdated=True,UpdateSourceTrigger=PropertyChanged}"></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding EntityName}" Header="Entity" Width="{Binding ElementName=c4,Path=ActualWidth}"/>
</DataGrid.Columns>
</DataGrid>
<StackPanel HorizontalAlignment="Right" Margin="0,-388,43,0" Height="108">
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Top"><InlineUIContainer>
<Button Height="40" Width="40" x:Name="btnup" Command="{Binding UpCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Click="Btnup_OnClick">
<Image x:Name="Up" Source="../Images/up.jpg" Height="40" />
</Button>
</InlineUIContainer></TextBlock>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,2"><InlineUIContainer>
<Button Height="40" Width="40" x:Name="btndown" Command="{Binding DownCommand}" CommandParameter="{Binding ElementName=dgEntities,Path=SelectedItem}" Click="btndown_Click">
<Image x:Name="Down" Source="../Images/Down.jpg" Height="40" />
</Button>
</InlineUIContainer></TextBlock>
</StackPanel>
</StackPanel>
<StackPanel Grid.Row="4" Grid.Column="0">
<TextBlock Name="tbldemo" HorizontalAlignment="Right">
<Button Name="btnRun" Height="30" Width="90" FontSize="18" Margin="9" Command="{Binding CommandRunJob}" >Run</Button>
<Button Name="btnSave" Height="30" Width="90" FontSize="18" Margin="9" Command="{Binding CommandSave, Mode=OneWay}">Save</Button>
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="4" Grid.Column="0">
<TextBlock HorizontalAlignment="Left">
<Button Name="btnclose" Height="30" Width="90" FontSize="18" Margin="19,9">Close</Button>
</TextBlock>
</StackPanel>
</Grid>
</UserControl>
CS:我说的是CollectionViewSource.View.Refresh();
答案 0 :(得分:1)
我相信你走在正确的轨道上。当您从视图模型更改集合中的属性时,视图未更新的原因是因为当您使用ObservableCollection使其按照您描述的方式正常工作时,您需要确保类型您在集合中绑定的实现INotifyProperyChanged。执行此操作后,ObservableCollection将收到此消息,然后通知您查看更改并最终导致视图更新。
因此,在您的情况下,您需要确保JobConfigurationResults类型实现INotifyPropertyChanged接口。
作为参考,您可以查看此链接,并在页面底部找到描述我建议的注释。 http://msdn.microsoft.com/en-us/library/ms748365(v=vs.110).aspx