[英]How do I remove the layer of control box of the second(child) form within the MDI form as parent form in C#?
[英]How do I dynamicaly update a child control within a form every second without changing the code behind the form?
我在一個表格中有一個兒童控制器,顯示了WiFi信號的強度。因為這個應用程序將在平板電腦上使用在車輛周圍的移動車輛上。 我想在我的WPF應用程序的每個形式中都有這個控件,我希望它每秒刷新一次,而不必更改它所在的每個表單后面的代碼。
通過調用signalQualityView.Refresh(),可以使用父窗體的代碼來刷新此控件。 每秒鍾,但希望在SignalQualityView用戶控件中實現此功能。
public partial class SignalQualityView : UserControl, INotifyPropertyChanged
{
// wifi signal indicator taken from from https://stackoverflow.com/questions/20085284/c-sharp-wpf-rating-control-similar-to-wifi-signal-indicator
private NetworkInformationService _networkInformationService;
public SignalQualityView()
{
InitializeComponent();
DataContext = this;
_networkInformationService = new NetworkInformationService();
Refresh();
}
public void Refresh()
{
Task.Run(() =>
{
WirelessNetwork wirelessNetwork = _networkInformationService.GetWirelessNetworkDetails();
var signalQuality = wirelessNetwork.SignalQuality;
if (signalQuality >= 80)
RatingValue = 5;
else if (signalQuality >= 60)
RatingValue = 4;
else if (signalQuality >= 40)
RatingValue = 3;
else if (signalQuality >= 20)
RatingValue = 2;
else if (signalQuality >= 1)
RatingValue = 1;
else
RatingValue = 0;
Task.Delay(1000);
Refresh();
});
}
public int RatingValue
{
get { return (int)GetValue(RatingValueProperty); }
set
{
SetValue(RatingValueProperty, value);
OnPropertyChanged();
}
}
// Using a DependencyProperty as the backing store for RatingValue. This enables animation, styling, binding, etc...
public static readonly DependencyProperty RatingValueProperty =
DependencyProperty.Register("RatingValue", typeof(int), typeof(SignalQualityView), new UIPropertyMetadata(0));
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class RatingConverter : IValueConverter
{
public Brush OnBrush { get; set; }
public Brush OffBrush { get; set; }
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
int rating = 0;
int number = 0;
if (int.TryParse(value.ToString(), out rating) && int.TryParse(parameter.ToString(), out number))
{
if (rating >= number)
{
return OnBrush;
}
return OffBrush;
}
return Brushes.Transparent;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
<UserControl x:Class="App.PlugIn.Controls.SignalQualityView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:DPWorld.PlugIn.Controls"
mc:Ignorable="d"
Height="40" Width="60">
<Grid Background="black" >
<Grid.Resources>
<local:RatingConverter x:Key="RatingConverter" OnBrush="LightBlue" OffBrush="Black" />
<Style TargetType="Rectangle">
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Bottom" />
<Setter Property="Margin" Value="5,0,0,0" />
</Style>
</Grid.Resources>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Background="Black" VerticalAlignment="Center">
<Rectangle Width="5" Height="5" Fill="{Binding RatingValue, Converter={StaticResource RatingConverter}, ConverterParameter=1}"/>
<Rectangle Width="5" Height="10" Fill="{Binding RatingValue, Converter={StaticResource RatingConverter}, ConverterParameter=2}"/>
<Rectangle Width="5" Height="15" Fill="{Binding RatingValue, Converter={StaticResource RatingConverter}, ConverterParameter=3}"/>
<Rectangle Width="5" Height="20" Fill="{Binding RatingValue, Converter={StaticResource RatingConverter}, ConverterParameter=4}"/>
<Rectangle Width="5" Height="25" Fill="{Binding RatingValue, Converter={StaticResource RatingConverter}, ConverterParameter=5}"/>
</StackPanel>
<Label Content="SIGNAL" Foreground="LightBlue" VerticalAlignment="Top" Height="15" FontSize="8" Margin="10,0,18,0" Padding="0,0,0,0"/>
</Grid>
</UserControl>
<Window x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:pi="clr-namespace:App.PlugIn.Controls;assembly=PlugIn"
Title="Window1" Height="300" Width="300">
<Grid>
<pi:SignalQualityView Name="signalQualityView" />
</Grid>
</Window>
根據信號強度突出顯示信號條的數量,但突出顯示0條。
使用WPF時,更改窗口上的數據應來自綁定對象的IObservable屬性。 屬性更改時,顯示值會更改。 使用每秒運行一次的任務將當前值放入共享對象的屬性中。 在所有綁定對象之間共享對象,不需要后面的代碼。
您可以從一個可以共享和觀察的類開始:
public class WiFiStrength : IObservable<int>
{
private int _signalQuality;
private int _ratingValue;
private class Unsubscriber : IDisposable
{
private List<IObserver<int>> _observers;
private readonly IObserver<int> _observer;
public Unsubscriber(List<IObserver<int>> observers, IObserver<int> observer)
{
_observers = observers;
_observer = observer;
}
public void Dispose()
{
if (_observers != null)
{
_observers.Remove(_observer);
_observers = null;
}
}
}
private List<IObserver<int>> _observers = new List<IObserver<int>>();
private void SetAndRaiseIfChanged(int newRating)
{
if (_ratingValue != newRating)
{
_ratingValue = newRating;
foreach (var observer in _observers)
{
observer.OnNext(newRating);
}
}
}
private static WiFiStrength _sharedInstance;
private static Task _updater;
private static CancellationTokenSource cts;
private static void UpdateStrength(WiFiStrength model, CancellationToken ct)
{
var rnd = new Random();
while (!ct.IsCancellationRequested)
{
model.SignalQuality = rnd.Next(100);
Thread.Sleep(1000);
}
}
public static WiFiStrength SharedInstance()
{
if (_sharedInstance == null)
{
_sharedInstance = new WiFiStrength();
cts = new CancellationTokenSource();
_updater = new Task(() => UpdateStrength(_sharedInstance, cts.Token));
_updater.Start();
}
return _sharedInstance;
}
public int SignalQuality
{
get => _signalQuality;
set
{
_signalQuality = value;
if (_signalQuality >= 80)
{
SetAndRaiseIfChanged(5);
}
else if (_signalQuality >= 60)
{
SetAndRaiseIfChanged(4);
}
else if (_signalQuality >= 40)
{
SetAndRaiseIfChanged(3);
}
else if (_signalQuality >= 20)
{
SetAndRaiseIfChanged(2);
}
else if (_signalQuality >= 1)
{
SetAndRaiseIfChanged(1);
}
else
{
SetAndRaiseIfChanged(0);
}
}
}
public int SignalRating => _ratingValue;
public IDisposable Subscribe(IObserver<int> observer)
{
_observers.Add(observer);
return new Unsubscriber(_observers, observer);
}
}
您將它附加到您的綁定類:
public class ViewModel1 : INotifyPropertyChanged
{
public string TextField { get; set; }
public WiFiStrength WiFi { get; set; }
private IObserver<int> _observer;
private class WiFiObserver : IObserver<int>
{
private readonly ViewModel1 _parent;
private readonly IDisposable _unsubscribe;
public WiFiObserver(ViewModel1 parent, WiFiStrength observed)
{
_parent = parent;
_unsubscribe = parent.WiFi.Subscribe(this);
}
public void OnNext(int value)
{
_parent.NotifyPropertyChanged("WiFi");
}
public void OnError(Exception error)
{
_unsubscribe.Dispose();
}
public void OnCompleted()
{
_unsubscribe.Dispose();
}
}
public ViewModel1()
{
WiFi = WiFiStrength.SharedInstance();
_observer = new WiFiObserver(this, WiFi);
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
您的班級會查找更改,並在更改時通知擁有的表單。
您的XAML只需綁定到屬性,如下所示:
<Label Content="{Binding WiFi.SignalRating, Mode=OneWay}"/>
使用盡可能多的表單。
定期更新的簡單UserControl將使用帶有Tick
事件處理程序的DispatcherTimer
來更新控件的依賴項屬性。 控件的XAML中的元素將通過RelativeSource
綁定綁定控件屬性。
以簡單的數字時鍾為例:
<UserControl ...>
<Grid>
<TextBlock Text="{Binding Time,
RelativeSource={RelativeSource AncestorType=UserControl}}"/>
</Grid>
</UserControl>
代碼背后:
public partial class Clock : UserControl
{
public Clock()
{
InitializeComponent();
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(0.5) };
timer.Tick += (s, e) => Time = DateTime.Now.ToString("HH:mm:ss");
timer.Start();
}
public static readonly DependencyProperty TimeProperty =
DependencyProperty.Register(nameof(Time), typeof(string), typeof(Clock));
public string Time
{
get { return (string)GetValue(TimeProperty); }
set { SetValue(TimeProperty, value); }
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.