来自@ grek40的答案
我已经在我的项目中实现了INotifyPropertyChanged
,并且其他一切工作正常,但是对于这个可变边界的文本块,它只在主窗口加载事件上更新一次。
我可能只是在某处遗漏了一些细节,请帮助!
MainWindow.xaml
<TextBlock HorizontalAlignment="Left" Margin="317,161,0,0"
TextWrapping="Wrap" Text="{Binding ish.IsDoingWork, Mode=OneWay,
UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Top"/>
<Button Command="{Binding hksVm.HentKundeStatus}" Content="Invoke"
HorizontalAlignment="Left" Margin="704,139,0,0" VerticalAlignment="Top"
Width="75"/>
MainWindow.xaml.cs (设置数据上下文)
public MainWindow()
{
if (!ValidationHandler.GrantAccess().Equals(3))
{
InitializeComponent();
DataContext = new
{
hksVm = new HentKundeStatusVm(),
ish = new InvocationServiceHandler()
};
}
else
{
Close();
}
}
ViewModel.cs
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Input;
namespace MyNamespace
{
public class HentKundeStatusVm : IViewModel
{
private ICommand _hentKundeStatus;
private readonly InvocationServiceHandler _invocationServiceHandler = new InvocationServiceHandler();
public ICommand HentKundeStatus => HentKundeStatusCommand();
public ICommand HentKundeStatusCommand()
{
if (ValidationHandler.GrantAccess() < 2)
{
return _hentKundeStatus ?? (_hentKundeStatus = new RelayCommand(param =>
ElapsedTime = _invocationServiceHandler.ExecuteAndTimeAction(
() =>
{
//web API kaldes asynkront - husk: using System.Net.Http;
using (var client = new HttpClient().GetAsync("API-url"))
{
client.Result.Content.ReadAsStringAsync();
}
}, AntalKald)));
}
return null;
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}
InvocationServiceHandler.cs
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading.Tasks;
using App005_WebServiceTestingTool_Domain.Annotations;
namespace App005_WebServiceTestingTool_Domain.Handlers
{
public class InvocationServiceHandler : INotifyPropertyChanged
{
// This works on the main_window load event and set the textblock in the view
private string _isDoingWork = "Currently not working";
public string IsDoingWork
{
get => _isDoingWork;
set
{
_isDoingWork = value;
NotifyPropertyChanged(nameof(IsDoingWork));
}
}
/// <summary>
/// Method that invokes action parameter x times in multiple threads (parallel) and returns the elapsed time
/// </summary>
/// <param name="action"></param>
/// <param name="antalKald"></param>
/// <returns></returns>
public string ExecuteAndTimeAction(Action action, string antalKald)
{
// Here is set the bound variable, and if I debug I can see it getting set to Working...
IsDoingWork = "Working...";
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < Convert.ToInt32(antalKald); i++)
{
action.Invoke();
}
sw.Stop();
// Here I am resetting the variable and again in debug I can see it change, but nothing happens in the view
IsDoingWork = "";
return $"Elapsed time: {sw.Elapsed}";
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
public void NotifyPropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
}
}
答案 0 :(得分:0)
您的逻辑很好,所有内容都看起来已正确附加,并且值会按预期更新。唯一的问题是你的UI没有更新它,因为你在主线程上执行For循环,不幸的是阻止了所有的UI更新。
所以你可以
ExecuteAndTimeAction
。Backgroundworker/[Task Library][1]
醇>
2.使用Dispatcher刷新您的UI消息,例如:
/// <summary>
/// Enters the message loop to process all pending messages down to the specified
/// priority. This method returns after all messages have been processed.
/// </summary>
/// <param name="priority">Minimum priority of the messages to process.</param>
public static void DoEvents(DispatcherPriority priority = DispatcherPriority.Background)
{
DispatcherFrame frame = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
priority,
new DispatcherOperationCallback(ExitFrame), frame);
Dispatcher.PushFrame(frame);
}
private static object ExitFrame(object f)
{
((DispatcherFrame)f).Continue = false;
return null;
}
并致电
/// <summary>
/// Method that invokes action parameter x times in multiple threads (parallel) and returns the elapsed time
/// </summary>
/// <param name="action"></param>
/// <param name="antalKald"></param>
/// <returns></returns>
public string ExecuteAndTimeAction(Action action, string antalKald)
{
// Here is set the bound variable, and if I debug I can see it getting set to Working...
IsDoingWork = "Working...";
DoEvent();//flushes the UI msg queue
var sw = new Stopwatch();
sw.Start();
for (int i = 0; i < Convert.ToInt32(antalKald); i++)
{
action.Invoke();
}
sw.Stop();
// Here I am resetting the variable and again in debug I can see it change, but nothing happens in the view
IsDoingWork = "";
DoEvent();//flushes the UI msg queue
return $"Elapsed time: {sw.Elapsed}";
}
第二种方法是黑客攻击,它仍然会冻结 用户界面,但将为您完成工作。 我建议你选择第一种方法, 这样做会更好,但需要付出努力才能实施。
答案 1 :(得分:0)
基本上,您有两个InvocationServiceHandler
个实例。一个位于DataContext
内ish = new InvocationServiceHandler()
,另一个位于MyViewModel
内private readonly InvocationServiceHandler _invocationServiceHandler = new InvocationServiceHandler();
显示ish.IsDoingWork
,更新hksVm._invocationServiceHandler.IsDoingWork
之类的内容。由于HentKundeStatusVm
和MyViewModel
在问题中并不是真的相同,所以并不是很清楚。
应该可以通过服务处理程序的构造函数注入来解决这种情况:
public class HentKundeStatusVm : IViewModel
{
private readonly InvocationServiceHandler _invocationServiceHandler;
public HentKundeStatusVm(InvocationServiceHandler ish)
{
_invocationServiceHandler = ish;
}
// the other stuff
}
然后
// In the MainWindow constructor
var ishInstance = new InvocationServiceHandler();
DataContext = new
{
hksVm = new HentKundeStatusVm(ishInstance),
ish = ishInstance
};
然后你有相同的处理程序实例可用于绑定和执行。