我有一个属性( FileName ),当我在调试器中观察它时(当在视图模型和XAML中都悬停在属性上时)正在更新,但是UI不会反映价值更新。我在set { this.MutateVerbose(ref _fileName, value, RaisePropertyChanged()); }
设置了一个断点,可以看到它输入并通过RaisePropertyChanged()
提出更改通知。
我将其实例化为初始值"未更新"通过FileName = "Not Updated";
,当属性通过应用程序的运行时间FileName = SelectRandomString();
成功更新为其他值时,UI永远不会更新。相关的UI代码:
<TextBlock Text="{Binding FileName}" HorizontalAlignment="Center">
<TextBlock.DataContext>
<ns:ProgressViewModel />
</TextBlock.DataContext>
</TextBlock>
全视图模型:
using MaterialDesignThemes.Wpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading.Tasks;
namespace MaterialDesignTest
{
public class ProgressViewModel : INotifyPropertyChanged
{
System.Windows.Forms.Timer progressTimer;
private double _saveProgressButton;
public double SaveProgressButton
{
get { return _saveProgressButton; }
set { this.MutateVerbose(ref _saveProgressButton, value, RaisePropertyChanged()); }
}
private string _fileName;
public string FileName
{
get { return _fileName; }
set { this.MutateVerbose(ref _fileName, value, RaisePropertyChanged()); }
}
private bool _isSaveComplete;
public bool IsSaveComplete
{
get { return _isSaveComplete; }
private set { this.MutateVerbose(ref _isSaveComplete, value, RaisePropertyChanged()); }
}
private bool _isSaving;
public bool IsSaving
{
get { return _isSaving; }
private set { this.MutateVerbose(ref _isSaving, value, RaisePropertyChanged()); }
}
int progress = 0;
int cycles = 0;
public ProgressViewModel()
{
FileName = "Not Updated";
}
public void KickOffProgressTimer()
{
progressTimer = new System.Windows.Forms.Timer();
progressTimer.Tick += new EventHandler(progressTimerTick);
progressTimer.Interval = 40;
progressTimer.Start();
}
private async void progressTimerTick(object sender, EventArgs e)
{
FileName = SelectRandomString();
if (progress < 100 && cycles < 2)
{
if (progress == 99)
{
cycles++;
progress = 0;
}
IsSaveComplete = false;
IsSaving = true;
progress++;
SaveProgressButton = progress;
}
else
{
IsSaveComplete = true;
IsSaving = false;
progressTimer.Enabled = false;
SaveProgressButton = 0;
await NonBlockingDelay(1750);
DialogHost.CloseDialogCommand.Execute(null, null);
}
}
async Task NonBlockingDelay(int value)
{
await Task.Delay(value);
}
public event PropertyChangedEventHandler PropertyChanged;
private Action<PropertyChangedEventArgs> RaisePropertyChanged()
{
return args => PropertyChanged?.Invoke(this, args);
}
static string SelectRandomString()
{
var random = new Random();
var questions = new List<string>{
@"C:\Files\Filename1",
@"C:\Filename2",
@"C:\Filename3",
@"C:\Filename4",
@"C:\Temp\Files\Filename5",
@"C:\Filename6",
@"C:\Demo\LongFolderName\Filename7",
@"C:\Filename8",
@"C:\Filename9",
};
int index = random.Next(questions.Count);
return(questions[index]);
}
}
}
MutateVerbose的代码:
public static void MutateVerbose<TField>(this INotifyPropertyChanged instance, ref TField field, TField newValue, Action<PropertyChangedEventArgs> raise, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<TField>.Default.Equals(field, newValue)) return;
field = newValue;
raise?.Invoke(new PropertyChangedEventArgs(propertyName));
}
更新:如果我启动进度计时器作为视图模型加载的一部分,如下所示:
public ProgressViewModel()
{
KickOffProgressTimer();
}
UI应该更新。但我不明白这种行为,这是不可取的。我不希望应用程序启动后立即执行KickOffProgressTimer();
方法,而只是在从后面的主窗口代码中单击按钮时才会执行:
private void CircleButtonClick(object sender, RoutedEventArgs e)
{
ProgressViewModel pvm = new ProgressViewModel();
CircleButton.DataContext = pvm;
pvm.KickOffProgressTimer();
}
答案 0 :(得分:0)
您需要指定将触发UI更新的UpdateSourceTrigger
事件:
<TextBlock Text="{Binding FileName, UpdateSourceTrigger=PropertyChanged}" ...
答案 1 :(得分:0)
这可能是您提升房产变更事件的方式。您是否尝试过使用为PropertyChanged
添加的新C# 6.0
实施。我将你的代码剥离到以下内容并且工作正常。
public class ProgressViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _fileName;
public string FileName
{
get { return _fileName; }
set
{
_fileName = value;
OnPropertyChanged();
}
}
public ProgressViewModel()
{
var random = new Random();
var timer = new Timer
{
Interval = 200,
};
timer.Elapsed += (s, e) => FileName = random.Next().ToString();
timer.Start();
}
}