C# 在ObservableCollection更改后ListView未更新
几个小时以来,我一直在努力让我的ListView和ObservableCollection正常工作。然而,没有运气。我也在这里和那里读了一些帖子,试图匹配,但仍然没有好结果。请告诉我哪里出了问题 基本上,我要做的是将逻辑从VM拆分为Helper类。该类中的逻辑将更新数据,但VM不知道该数据。 我的问题是在复制文件功能中,作业状态不会更改视图数据。我尝试了Messenger.Default.Send(从帮助程序)和Messenger register(在VM中)来接受更改,但仍然没有成功。 顺便说一下,我使用的是MVVM灯光、WPF、C# 这是我的模型代码C# 在ObservableCollection更改后ListView未更新,c#,wpf,mvvm,mvvm-light,observablecollection,C#,Wpf,Mvvm,Mvvm Light,Observablecollection,几个小时以来,我一直在努力让我的ListView和ObservableCollection正常工作。然而,没有运气。我也在这里和那里读了一些帖子,试图匹配,但仍然没有好结果。请告诉我哪里出了问题 基本上,我要做的是将逻辑从VM拆分为Helper类。该类中的逻辑将更新数据,但VM不知道该数据。 我的问题是在复制文件功能中,作业状态不会更改视图数据。我尝试了Messenger.Default.Send(从帮助程序)和Messenger register(在VM中)来接受更改,但仍然没有成功。 顺便
public class MyFile : ViewModelBase
{
public string fullFileName { get; set; }
public string fileName { get; set; }
private string _jobStatus;
public string jobStatus
{
get { return _jobStatus; }
set { Set(ref _jobStatus, value); }
}
}
这是我的助手代码。
class FileHelper
{
public List<MyFile> GetFileName(string dir)
{
List<MyFile> lstFiles = new List<MyFile>();
foreach (var file in (new DirectoryInfo(dir).GetFiles()))
{
if (file.Name.ToLower().Contains("xls") && !file.Name.Contains("~$"))
lstFiles.Add(new MyFile() { fullFileName = file.FullName, fileName = file.Name, jobStatus = "-" });
}
return lstFiles;
}
public bool CopyFiles(string destDir, List<MyFile> lstFiles)
{
try
{
int counter = 0;
foreach (MyFile f in lstFiles)
{
f.jobStatus = "Copying";
File.Copy(f.fullFileName, Path.Combine(destDir, f.fileName),true);
f.jobStatus = "Finished";
counter += 1;
Console.WriteLine("M: " + DateTime.Now.ToString("hh:mm:ss") + " " + counter);
Messenger.Default.Send(counter, "MODEL");
}
return true;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
return false;
}
}
}
类FileHelper
{
公共列表GetFileName(字符串目录)
{
List lstFiles=新列表();
foreach(新目录信息(dir.GetFiles())中的var文件)
{
if(file.Name.ToLower().Contains(“xls”)和&!file.Name.Contains(“~$”)
添加(new MyFile(){fullFileName=file.FullName,fileName=file.Name,jobStatus=“-”});
}
返回文件;
}
公共bool复制文件(字符串destDir,列表lstFiles)
{
尝试
{
int计数器=0;
foreach(lstFiles中的myf文件)
{
f、 jobStatus=“复制”;
File.Copy(f.fullFileName,Path.Combine(destDir,f.fileName),true);
f、 jobStatus=“完成”;
计数器+=1;
Console.WriteLine(“M:+DateTime.Now.ToString”(“hh:mm:ss”)+”+计数器);
Messenger.Default.Send(计数器,“模型”);
}
返回true;
}
捕获(例外e)
{
Console.WriteLine(“错误:+e.Message”);
返回false;
}
}
}
这是我的虚拟机代码
public class MainViewModel : ViewModelBase
{
public ICommand CmdJob { get; private set; }
private ObservableCollection<MyFile> fileList;
public ObservableCollection<MyFile> FileList
{
get { return fileList; }
set { Set(ref fileList, value); }
}
private string counter;
public string Counter
{
get { return counter; }
set { Set(ref counter, value); }
}
public MainViewModel()
{
Messenger.Default.Register<int>(this, "MODEL", UpdateCounter);
CmdJob = new RelayCommand<object>(Action_Job);
Counter = "0";
}
private void UpdateCounter(int bgCounter)
{
Counter = bgCounter.ToString();
RaisePropertyChanged("FileList");
Console.WriteLine("VM: " + DateTime.Now.ToString("hh:mm:ss") + " " + Counter);
}
private void Action_Job(object tag)
{
if (tag == null || string.IsNullOrEmpty(tag.ToString()))
return;
switch (tag.ToString())
{
case "GET": GetFile(); break;
case "COPY": CopyFile(); break;
}
}
private void GetFile()
{
Counter = "0";
List<MyFile> myFs = new FileHelper().GetFileName(@"C:\Test\Original\");
FileList = new ObservableCollection<MyFile>(myFs);
}
private void CopyFile()
{
if (new FileHelper().CopyFiles(@"C:\Test\Destination\", fileList.ToList()))
Messenger.Default.Send("Files copying finished", "VM");
else
Messenger.Default.Send("Files copying failed", "VM");
}
}
public类MainViewModel:ViewModelBase
{
公共ICommand CmdJob{get;private set;}
私有可观察收集文件列表;
公共可观测集合文件列表
{
获取{返回文件列表;}
set{set(ref fileList,value);}
}
专用字符串计数器;
公共字符串计数器
{
获取{返回计数器;}
set{set(ref计数器,值);}
}
公共主视图模型()
{
Messenger.Default.Register(这个“MODEL”,UpdateCounter);
CmdJob=新的RelayCommand(操作\作业);
计数器=“0”;
}
私有void更新计数器(int-bgCounter)
{
Counter=bgCounter.ToString();
RaisePropertyChanged(“文件列表”);
Console.WriteLine(“VM:+DateTime.Now.ToString”(“hh:mm:ss”)+”+计数器);
}
私有无效操作\u作业(对象标记)
{
if(tag==null | | string.IsNullOrEmpty(tag.ToString()))
返回;
开关(tag.ToString())
{
大小写“GET”:GetFile();break;
case“COPY”:CopyFile();break;
}
}
私有void GetFile()
{
计数器=“0”;
List myFs=new FileHelper().GetFileName(@“C:\Test\Original\”);
FileList=新的ObservableCollection(myFs);
}
私有void CopyFile()
{
if(new FileHelper().CopyFiles(@“C:\Test\Destination\”,fileList.ToList())
Send(“文件复制完成”,“虚拟机”);
其他的
senger.Default.Send(“文件复制失败”,“虚拟机”);
}
}
这是我的XAML。
<ListView Grid.Row="0" Grid.Column="0" ItemsSource="{Binding FileList}" Margin="5,5,0,5" HorizontalAlignment="Left" VerticalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Visible">
<ListView.View>
<GridView>
<GridViewColumn Header="File Name" Width="170" DisplayMemberBinding="{Binding fileName}" />
<GridViewColumn Header="Status" Width="170" DisplayMemberBinding="{Binding jobStatus}" >
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Vertical">
<Button Content="Get file list" Tag="GET" Command="{Binding CmdJob}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" Width="80" Height="25" Margin="0,50,0,50"/>
<Button Content="Copy file" Tag="COPY" Command="{Binding CmdJob}" CommandParameter="{Binding RelativeSource={RelativeSource Self}, Path=Tag}" Width="80" Height="25" />
<Label Content="{Binding Counter}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Height="25" FontWeight="Bold" Foreground="Red" Margin="0,50,0,0"/>
</StackPanel>
我通读了一些帖子,上面写着“变更”,ObservableCollection不会反映视图的变更。所以,我遵循这些帖子的解决方案(在模型类中使用NotifyChange),不适合我
对我来说,我的个人文件很大,所以我可以看到我的虚拟机上没有更新如果使用较小的文件大小进行测试,则不会看到差异
我尝试使用Messenger方法,它也不会在视图上更新,但我的VM可以毫无问题地接受传入消息。您不能同时在同一线程上更新UI和复制文件 您应该在后台线程上执行复制,或者使用异步API,例如:
public async Task<bool> CopyFiles(string destDir, List<MyFile> lstFiles)
{
try
{
int counter = 0;
foreach (MyFile f in lstFiles)
{
f.jobStatus = "Copying";
using (Stream source = File.Open(f.fullFileName))
using (Stream destination = System.IO.File.Create(Path.Combine(destDir, f.fileName)))
await source.CopyToAsync(destination);
f.jobStatus = "Finished";
counter += 1;
Console.WriteLine("M: " + DateTime.Now.ToString("hh:mm:ss") + " " + counter);
Messenger.Default.Send(counter, "MODEL");
}
return true;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
return false;
}
}
多亏了Clemens和mm8,我成功地将其更改为async并等待UI更新
我认为我的实现方式仍然是合理的(与mm8相比)。
private async void CopyFile()
{
var fh=new FileHelper();
bool result=wait fh.copyFileAsync(@“C:\Test\Destination\”,fileList.ToList());
如果(结果)
Send(“文件复制完成”,“虚拟机”);
其他的
senger.Default.Send(“文件复制失败”,“虚拟机”);
}
公共异步任务copyFileAsync(字符串destDir,列表lstFiles)
{
尝试
{
int计数器=0;
等待任务。运行(()=>
{
foreach(lstFiles中的myf文件)
{
f、 jobStatus=“复制”;
睡眠(500);
File.Copy(f.fullFileName,Path.Combine(destDir,f.fileName),true);
f、 jobStatus=“完成”;
计数器+=1;
Messenger.Default.Send(计数器,“模型”);
睡眠(500);
}
});
返回true;
}
捕获(例外e)
{
Console.WriteLine(“错误:+e.Message”);
返回false;
}
}
您是否尝试过实现INotifyPropertyChanged接口?@mahlatse,我正在使用MVVM Light,“set{set(ref xxxx})”为我完成任务。我的答案似乎有点不对劲,您是否尝试过此stackoverflow帖子。这是因为您正在UI t中同步设置这些属性
private Task CopyFile()
{
var fh = new FileHelper();
if (await fh.CopyFiles(@"C:\Test\Destination\", fileList.ToList()))
Messenger.Default.Send("Files copying finished", "VM");
else
Messenger.Default.Send("Files copying failed", "VM");
}
private async void Action_Job(object tag)
{
if (tag == null || string.IsNullOrEmpty(tag.ToString()))
return;
switch (tag.ToString())
{
case "GET": GetFile(); break;
case "COPY": await CopyFile(); break;
}
}
private async void CopyFile()
{
var fh = new FileHelper();
bool result = await fh.CopyFilesAsync(@"C:\Test\Destination\", fileList.ToList());
if (result)
Messenger.Default.Send("Files copying finished", "VM");
else
Messenger.Default.Send("Files copying failed", "VM");
}
public async Task<bool> CopyFilesAsync(string destDir, List<MyFile> lstFiles)
{
try
{
int counter = 0;
await Task.Run(() =>
{
foreach (MyFile f in lstFiles)
{
f.jobStatus = "Copying";
Thread.Sleep(500);
File.Copy(f.fullFileName, Path.Combine(destDir, f.fileName), true);
f.jobStatus = "Finished";
counter += 1;
Messenger.Default.Send(counter, "MODEL");
Thread.Sleep(500);
}
});
return true;
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.Message);
return false;
}
}