我正在创建一个应用程序,它监视远程机器上的几个跟踪服务器,并在UI上显示处理后的数据。当我使用模拟器生成数据时,一切都按预期工作。问题是当使用实际的数据模型时,UI没有被更新。有时它在启动后更新一次,有时从不更新。ViewModel保持不变,数据得到正确处理并可用。这会影响所有在XAML中使用绑定的控件。在代码中更新的其他控件按预期工作。ViewModel都正确地实现了INotifyPropertyChanged
。
请参见以下示例:
TimeStrip user control
在这个TimeStrip
控件中,文本框和行应该随着时间向右移动。
UserControl XAML:
<Grid x:Name="TimeSlotGrid">
//..
<local:TimeSlot Grid.Column="2" Text="8:00"/>
<local:TimeSlot Grid.Column="3" Text="9:00"/>
//...
</Grid>
<Grid LayoutUpdated="Grid_LayoutUpdated" Loaded="Grid_Loaded">
<Canvas x:Name="TimeCanvas">
<TextBlock Style="{StaticResource MediumTextTheme}"
Text="{Binding Path=UiStuff.CurrentTimeString}"
Canvas.Left="{Binding Path=UiStuff.TimeTextPos}"
Canvas.Top="1"/>
<Line x:Name="CurrentTimeCursor"
X1="{Binding Path=UiStuff.TimePos}"
X2="{Binding Path=UiStuff.TimePos}"
Y1="0" Y2="360" Stroke="Red" StrokeThickness="2"/>
</Canvas>
</Grid>
灰框(TimeSlot
)用Grid_LayoutUpdated
更新,Grid_LayoutUpdated
根据当前时间设置其背景梯度:
后面的代码
private void Grid_LayoutUpdated(object sender, EventArgs e)
{
MainViewModel context = DataContext as MainViewModel;
context.UiStuff.GridWidth = TimeCanvas.ActualWidth;
DateTime dt = context.UiStuff.CurrentTime;
int currentHour = dt.AddHours(-6).Hour;
double currentHourPart = dt.Minute / 60d;
for (int i = 0; i < TimeSlotGrid.Children.Count; i++)
{
TimeSlot slot = TimeSlotGrid.Children[i] as TimeSlot;
if (slot is null) continue;
slot.Visibility = i <= currentHour ? Visibility.Visible : Visibility.Hidden;
slot.Background = Brushes.Gray;
if (i == currentHour)
{
lgb.GradientStops[1].Offset = currentHourPart;
lgb.GradientStops[2].Offset = currentHourPart;
slot.Background = lgb;
}
}
}
ViewModel(minimal)
public class MainViewModel
{
public UIElements UiStuff { get; set; }
private readonly TraceCommunication Trace;
public MainViewModel()
{
Trace = new TraceCommunication();
Trace.MessageReceived += Trace_MessageReceived;
Trace.StartConnection("10.128.251.136", "9334");
}
private void Trace_MessageReceived(DataRow message)
{
if (!DateTime.TryParse(values[Columns.TimeStamp].ToString(), out DateTime dt)) return;
UiStuff.CurrentTime = dt;
}
}
public class UIElements : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string name = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
private DateTime currentTime;
public DateTime CurrentTime
{
get => currentTime;
set
{
currentTime = value;
CurrentTimeString = currentTime.ToString("HH:mm");
double timescale = currentTime.AddHours(-6).TimeOfDay.TotalMinutes / 1440;
TimePos = (int)(GridWidth * timescale);
OnPropertyChanged();
}
}
private string currenTimeString;
public string CurrentTimeString
{
get => currenTimeString;
set { currenTimeString = value; OnPropertyChanged();}
}
}
正如你在屏幕截图中看到的,绑定在启动后只更新了一次(9:51)。该TimeSlots
正确显示(其10:30).
如前所述,当使用模拟器时,这一切都可以工作。唯一的区别在于TraceCommunication
对象,它监视远程系统。ViewModel订阅MessageReceived
事件并相应地设置UI元素。
public class TraceCommunication
{
internal delegate void TraceEventHandler(DataRow value);
internal event TraceEventHandler MessageReceived;
private TraceEngineIntf traceEngine;
private string _Ip;
private string _Port;
public TraceCommunication()
{
//...
}
internal bool StartConnection(string ip, string port)
{
_Ip = ip;
_Port = port;
bool success = true;
if (!ip.Contains("."))
{
TraceSimulator Sim = new TraceSimulator(ip);
Sim.MessageReceived += FireEventIfRelevant;
Sim.StartTracing();
}
else
{
traceEngine = new TraceEngineIntf();
traceEngine.ConnectedChanged += Trace_ConnectedChanged;
traceEngine.MessageReceived += FireEventIfRelevant;
success = traceEngine.SetHost(_Ip, _Port);
}
return success;
}
private void FireEventIfRelevant(DataRow row)
{
if (!TraceFilter.IsRelevant(row)) return;
MessageReceived?.Invoke(row);
}
private void Trace_ConnectedChanged(object sender, EventArgs e)
{
traceEngine = sender as TraceEngineIntf;
if (traceEngine.Connected)
{
traceEngine.StartRead();
}
else
{
Connect();
}
}
}
在这两种情况下,数据都被正确地接收和处理。这些事件被激发,然后在ViewModel中被正确处理。但是UI仅在使用模拟器时才响应。情况并非总是如此。我开始只用真实的东西,效果很好。后来,当我需要更快的数据进行开发时,我实现了模拟器。
我不知道是什么导致了这种行为。有谁知道发生了什么事,或者可以给予我提示下一步要检查什么?
谢谢你,谢谢
1条答案
按热度按时间xiozqbni1#
TimeStrip
控件包含24个TimeSlot
控件,表示一天中的小时。当我在TimeStrip
的Grid_LayoutUpdated
处理程序方法中将当前TimeSlot
的BackGround设置为LinearGradientBrush
而不是实心Brush
时,它就坏了。我通过将“currentHourPart”作为依赖属性传递给
TimeSlot
本身并相应地设置渐变来修复它。我仍然不知道为什么这会导致这个问题,以及为什么当我使用模拟器时它会工作。