C# 将三个滑块值合并为一个Texblock文本/标签内容?
我目前正在开发一个用户界面,用户可以通过三个单独的滑块选择三个值。我在滑块前面有三个文本块,用于指示特定滑块的当前值: 在.xaml中:C# 将三个滑块值合并为一个Texblock文本/标签内容?,c#,wpf,xaml,C#,Wpf,Xaml,我目前正在开发一个用户界面,用户可以通过三个单独的滑块选择三个值。我在滑块前面有三个文本块,用于指示特定滑块的当前值: 在.xaml中: <Label Content="Sample Selection" FontSize="16" FontStyle="Italic" FontWeight="Bold" HorizontalAlignment="Left" Margin="0,-30,0,0" VerticalAlignment="Top"/> <Label Content=
<Label Content="Sample Selection" FontSize="16" FontStyle="Italic" FontWeight="Bold" HorizontalAlignment="Left" Margin="0,-30,0,0" VerticalAlignment="Top"/>
<Label Content="Patient Samples (max 64)" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" FontStyle="Italic"/>
<Slider x:Name="SampleAmountSlider" HorizontalAlignment="Left" Margin="181,14,0,0" VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="64" ValueChanged="SampleAmountSlider_ValueChanged" IsSnapToTickEnabled="True"/>
<TextBlock x:Name="SampleSliderValue" HorizontalAlignment="Left" Margin="165,16,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top"/>
<Label Content="Calibrators (max 7)" HorizontalAlignment="Left" Margin="10,36,0,0" VerticalAlignment="Top" FontStyle="Italic"/>
<Slider x:Name="CalAmountSlider" HorizontalAlignment="Left" Margin="181,40,0,0" VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="7" ValueChanged="CalAmountSlider_ValueChanged" IsSnapToTickEnabled="True"/>
<TextBlock x:Name="CalSliderValue" HorizontalAlignment="Left" Margin="165,42,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top"/>
<Label Content="Control Samples (max 4)" HorizontalAlignment="Left" Margin="10,62,0,0" VerticalAlignment="Top" FontStyle="Italic"/>
<Slider x:Name="ControlAmountSlider" HorizontalAlignment="Left" Margin="181,66,0,0" VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="4" ValueChanged="ControlAmountSlider_ValueChanged" IsSnapToTickEnabled="True"/>
<TextBlock x:Name="ControlSliderValue" HorizontalAlignment="Left" Margin="165,68,0,0" TextWrapping="Wrap" Text="0" VerticalAlignment="Top"/>
<Label Content="Total Sample Preparations Selected:" HorizontalAlignment="Left" Margin="10,105,0,0" VerticalAlignment="Top" FontWeight="Bold" FontStyle="Italic"/>
<TextBlock x:Name="TotalPrepValue" HorizontalAlignment="Left" Margin="225,110,0,0" FontWeight="Bold" FontStyle="Italic" Text="0" VerticalAlignment="Top"/>
在.xaml.cs中:
private void SampleAmountSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
SampleSliderValue.Text = Math.Round(e.NewValue, 0).ToString();
}
private void CalAmountSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
CalSliderValue.Text = Math.Round(e.NewValue, 0).ToString();
}
private void ControlAmountSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
ControlSliderValue.Text = Math.Round(e.NewValue, 0).ToString();
}
private void SampleAmountSlider\u值已更改(对象发送方,RoutedPropertyChangedEventArgs e)
{
SampleSliderValue.Text=Math.Round(例如,NewValue,0.ToString();
}
私有void CalAmountSlider_值已更改(对象发送方,RoutedPropertyChangedEventArgs e)
{
CalSliderValue.Text=Math.Round(例如NewValue,0.ToString();
}
私有void ControlAmountSlider\u值已更改(对象发送方,RoutedPropertyChangedEventArgs e)
{
ControlSliderValue.Text=Math.Round(例如NewValue,0.ToString();
}
我想要的是最后一个文本块(名为TotalPrepValue)包含患者样本量、校准器量和对照样本量的总和
我不确定我问的问题是否很多,或者事情是否不清楚(如果是,请让我知道。我会尽快回答)。
问题是,我是一个非常缺乏经验的程序员,但愿意学习!
提前感谢您的帮助 就我个人而言,我会这么做。然而,如果你喜欢的话,也请去投票@JerryNixon's,因为使用滑块代替他的例子基本上是一种重新分解,他应该得到更多的赞扬。通常我会直接告诉你,但我知道当你刚开始做一些事情的时候,一个更清晰的PoC会更有用 不管怎样,给你,一个美丽的开始 XAML
<Window.Resources>
<local:SumConverter x:Key="MySumConverter" />
</Window.Resources>
<Grid>
<StackPanel VerticalAlignment="Center">
<StackPanel.Resources>
<Style TargetType="Slider">
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="200"/>
<Setter Property="Minimum" Value="0"/>
<Setter Property="Maximum" Value="100"/>
</Style>
</StackPanel.Resources>
<Slider x:Name="Slider1"></Slider>
<Slider x:Name="Slider2"></Slider>
<Slider x:Name="Slider3"></Slider>
<TextBlock HorizontalAlignment="Center" TextAlignment="Center">
<Run Text="{Binding Value, ElementName=Slider1}"/>
<LineBreak/><LineBreak/>
<Run Text="{Binding Value, ElementName=Slider2}"/>
<LineBreak/><LineBreak/>
<Run Text="{Binding Value, ElementName=Slider3}"/>
<LineBreak/>
<Run Text="______________________"/>
<LineBreak/><LineBreak/>
<Run>
<Run.Text>
<MultiBinding Converter="{StaticResource MySumConverter}"
StringFormat="{}{0:C}"
FallbackValue="Error" TargetNullValue="Null">
<Binding Path="Value" ElementName="Slider1"/>
<Binding Path="Value" ElementName="Slider2"/>
<Binding Path="Value" ElementName="Slider3"/>
</MultiBinding>
</Run.Text>
</Run>
</TextBlock>
</StackPanel>
</Grid>
希望这有帮助,干杯。正如其他人所建议的,您可以在此场景中使用
IMultiValueConverter
。但我的观点是,虽然在其他情况下这是一个有用的工具,但在这里这是一个错误的工具。原因是,在这种情况下,它将被用来永久不适当地使用UI元素作为存储非UI数据的地方
在编写WPF程序时,如果您承诺遵循WPF打算与之一起使用的MVVM编程风格,您将得到更好的服务。术语“MVVM”字面意思是“模型、视图、视图模型”。从这个角度来看,模型和视图之间总会有特殊用途的“适配器”类型。但根据我的经验,MVVM范例的重要部分是严格地将视图逻辑与模型逻辑分开,这通常可以在没有额外的“视图模型”类型的情况下完成。这使MVVM与MVC(“模型、视图、控制器”)和MVP(“模型、视图、演示者”)处于同一组工具中
所有这些的关键是,您有一些在模型数据结构中表示的业务逻辑,这些逻辑由提供某种形式的值更改通知的类型实现(在WPF中,这里的主要机制是INotifyPropertyChanged
),然后还可以查看完全单独表示的逻辑(在WPF中,视图大部分(并且在许多情况下完全)是用XAML声明的)
在您的示例中,这意味着我们需要一个表示您感兴趣的数据的模型数据结构:样本、校准器、控制和总准备计数。最后一个是前三个的总和。只要我们有一个类可以跟踪这些,并且在其他三个值中的任何一个发生变化时正确更新求和值ge,我们可以直接将其绑定到XAML中声明的视图,而无需使用任何C#代码
例如:
class ViewModel : INotifyPropertyChanged
{
private int _sampleCount;
public int SampleCount
{
get { return _sampleCount; }
set { _UpdateField(ref _sampleCount, value, OnCountChanged); }
}
private int _calibratorCount;
public int CalibratorCount
{
get { return _calibratorCount; }
set { _UpdateField(ref _calibratorCount, value, OnCountChanged); }
}
private int _controlCount;
public int ControlCount
{
get { return _controlCount; }
set { _UpdateField(ref _controlCount, value, OnCountChanged); }
}
private int _totalPrepCount;
public int TotalPrepCount
{
get { return _totalPrepCount; }
set { _UpdateField(ref _totalPrepCount, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnCountChanged(int previousValue)
{
TotalPrepCount = SampleCount + CalibratorCount + ControlCount;
}
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
(旁白:除了改变以支持MVVM方法外,我根本没有修改您的基本UI声明。我同意您需要开始熟悉的另一件事是如何利用WPF的各种布局容器和元素样式特性。但是我认为在这里介绍这些只会混淆问题。通过如果您的原始用户界面基本上完好无损,您可以只关注那些与您最初拥有的不同的东西,帮助您更好地理解数据绑定方面,而不会分心。)
在此实现中,没有任何代码添加到MainWindow.xaml.cs
文件中。该文件中的所有内容都是对构造函数中InitializeComponent()
的默认调用,由Visual Studio的WPF项目模板提供
另一方面,在XAML中,我将事件处理程序订阅替换为直接绑定到Slider.Value
属性的绑定。还要注意的是TextBlock.Text
属性也绑定到相同的属性。通过这种方式,WPF完成了在仅业务逻辑的数据结构中存储Slider值的所有繁重工作cture,然后在视图的文本字段中重新显示这些值。您会注意到WPF甚至处理各种数据类型之间的转换:视图模型存储int
值,但滑块使用double
,文本块当然使用string
当然,TotalPrepCount
字段也绑定到要显示的TextBlock.Text
属性
最后,我将注意到,即使在您的简单示例中,您也可能需要在其他地方应用此数据绑定方法。特别是,您的滑块都有最大值,这些值都硬编码到视图中。MVVM的观点是视图不必封装任何关于业务逻辑的知识。这包括e不必知道允许值的完整范围(*)
因此,您的视图模型还可以有一个MaxSampleCount
属性,该属性绑定到滑块.max
属性和标签.Content
属性。在后一种情况下,您可以使用绑定.StringFormat
属性
class ViewModel : INotifyPropertyChanged
{
private int _sampleCount;
public int SampleCount
{
get { return _sampleCount; }
set { _UpdateField(ref _sampleCount, value, OnCountChanged); }
}
private int _calibratorCount;
public int CalibratorCount
{
get { return _calibratorCount; }
set { _UpdateField(ref _calibratorCount, value, OnCountChanged); }
}
private int _controlCount;
public int ControlCount
{
get { return _controlCount; }
set { _UpdateField(ref _controlCount, value, OnCountChanged); }
}
private int _totalPrepCount;
public int TotalPrepCount
{
get { return _totalPrepCount; }
set { _UpdateField(ref _totalPrepCount, value); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnCountChanged(int previousValue)
{
TotalPrepCount = SampleCount + CalibratorCount + ControlCount;
}
protected void _UpdateField<T>(ref T field, T newValue,
Action<T> onChangedCallback = null,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, newValue))
{
return;
}
T oldValue = field;
field = newValue;
onChangedCallback?.Invoke(oldValue);
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<Window x:Class="TestSO45170241SliderExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:l="clr-namespace:TestSO45170241SliderExample"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<l:ViewModel/>
</Window.DataContext>
<Grid>
<Label Content="Sample Selection" FontSize="16" FontStyle="Italic" FontWeight="Bold"
HorizontalAlignment="Left" Margin="0,-30,0,0" VerticalAlignment="Top"/>
<Label Content="Patient Samples (max 64)" HorizontalAlignment="Left" Margin="10,10,0,0"
VerticalAlignment="Top" FontStyle="Italic"/>
<Slider HorizontalAlignment="Left" Margin="181,14,0,0"
VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="64"
Value="{Binding SampleCount}" IsSnapToTickEnabled="True"/>
<TextBlock HorizontalAlignment="Left" Margin="165,16,0,0"
TextWrapping="Wrap" Text="{Binding SampleCount}" VerticalAlignment="Top"/>
<Label Content="Calibrators (max 7)" HorizontalAlignment="Left" Margin="10,36,0,0"
VerticalAlignment="Top" FontStyle="Italic"/>
<Slider HorizontalAlignment="Left" Margin="181,40,0,0"
VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="7"
Value="{Binding CalibratorCount}" IsSnapToTickEnabled="True"/>
<TextBlock HorizontalAlignment="Left" Margin="165,42,0,0"
TextWrapping="Wrap" Text="{Binding CalibratorCount}" VerticalAlignment="Top"/>
<Label Content="Control Samples (max 4)" HorizontalAlignment="Left" Margin="10,62,0,0"
VerticalAlignment="Top" FontStyle="Italic"/>
<Slider HorizontalAlignment="Left" Margin="181,66,0,0"
VerticalAlignment="Top" Cursor="Hand" Width="160" Maximum="4"
Value="{Binding ControlCount}" IsSnapToTickEnabled="True"/>
<TextBlock HorizontalAlignment="Left" Margin="165,68,0,0"
TextWrapping="Wrap" Text="{Binding ControlCount}" VerticalAlignment="Top"/>
<Label Content="Total Sample Preparations Selected:" HorizontalAlignment="Left"
Margin="10,105,0,0" VerticalAlignment="Top" FontWeight="Bold" FontStyle="Italic"/>
<TextBlock HorizontalAlignment="Left" Margin="225,110,0,0"
FontWeight="Bold" FontStyle="Italic" Text="{Binding TotalPrepCount}"
VerticalAlignment="Top"/>
</Grid>
</Window>