c# - 如何以两种方式绑定属性WPF
问题描述
我是一个真正的菜鸟初学者 WPF 开发人员,并且掌握了 c# 的窍门。我正在创建一个应用程序,我需要一个旋钮 Button 和一个 TextBox Display,其中旋钮调整显示屏上的文本,如果文本更改,显示屏会更新旋钮位置。
我设法创建了旋钮按钮,它在单击和拖动时会旋转,并且还设法将它的值绑定到 TextBox,它完美地显示了该值,但我无法让 TextBox 文本更新旋钮的位置,即由 Angle 变量定义(来自 RotateTransform 事物),代码如下:
<UserControl x:Class="quaselaeuespero.VolumeControl"
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:quaselaeuespero"
mc:Ignorable="d"
d:DesignHeight="154" d:DesignWidth="148">
<Grid>
<Image Name="aPorradoknob" Source="Knob.png" RenderTransformOrigin="0.5,0.5">
<Image.RenderTransform>
<RotateTransform Angle="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:VolumeControl}}, Path=Angle}"/>
</Image.RenderTransform>
</Image>
</Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace quaselaeuespero
{
/// <summary>
/// Interaction logic for VolumeControl.xaml
/// </summary>
public partial class VolumeControl : UserControl
{
public static readonly DependencyProperty AngleProperty =
DependencyProperty.Register("Angle", typeof(double), typeof(VolumeControl), new UIPropertyMetadata(0.0));
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
public VolumeControl()
{
InitializeComponent();
this.Angle = 120;
this.MouseLeftButtonDown += new MouseButtonEventHandler(OnMouseLeftButtonDown);
this.MouseUp += new MouseButtonEventHandler(OnMouseUp);
this.MouseMove += new MouseEventHandler(OnMouseMove);
}
private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(this);
}
private void OnMouseUp(object sender, MouseButtonEventArgs e)
{
Mouse.Capture(null);
}
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (Mouse.Captured == this)
{
// Get the current mouse position relative to the volume control
Point currentLocation = Mouse.GetPosition(this);
// We want to rotate around the center of the knob, not the top corner
Point knobCenter = new Point(this.ActualHeight / 2, this.ActualWidth / 2);
// Calculate an angle
double radians = Math.Atan((currentLocation.Y - knobCenter.Y) /
(currentLocation.X - knobCenter.X));
this.Angle = radians * 180 / Math.PI;
// Apply a 180 degree shift when X is negative so that we can rotate
// all of the way around
if (currentLocation.X - knobCenter.X < 0)
{
this.Angle += 180;
}
if(this.Angle >= -90 && this.Angle <= -45)
{
this.Angle = 270;
}
if (this.Angle >= -45 && this.Angle <= 0)
{
this.Angle = 1;
}
this.Angle = Math.Round(this.Angle, 1);
}
}
}
}
Knob is<VolumeControl/>
和 Display is <DisplayBPM/>
,在主窗口中我尝试将它们都绑定:
<Window x:Class="quaselaeuespero.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:local="clr-namespace:quaselaeuespero"
mc:Ignorable="d"
Title="MainWindow" Height="540" Width="960">
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Background.png"/>
</Grid.Background>
<local:VolumeControl x:Name="Knobão" Margin="123,240,675,111" RenderTransformOrigin="0.5,0.5" Angle="{Binding ElementName=BPMDisplay, Path=BPM, UpdateSourceTrigger=Explicit}"/>
<local:DisplayBPM x:Name="BPMDisplay" BPM="{Binding ElementName=Knobão, Path=Angle, UpdateSourceTrigger=Explicit}" Margin="68,153,656,274" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</Window>
以下是 DisplayBPM 的代码:
<UserControl x:Class="quaselaeuespero.DisplayBPM"
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:quaselaeuespero"
mc:Ignorable="d"
d:DesignHeight="79
" d:DesignWidth="229"
Name="Display">
<Grid Margin="0">
<TextBox x:Name="BPMTexto" Text="{Binding ElementName=Display, Path=BPM}" HorizontalAlignment="Right" Margin="0,0,4,0" Width="222" BorderBrush="{x:Null}" SelectionBrush="{x:Null}" Foreground="#FFCF1D1D" FontSize="80" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" FontFamily="DS-Digital" RenderTransformOrigin="0.5,0.5" CaretBrush="#FFCF1D1D">
<TextBox.Background>
<ImageBrush ImageSource="Display BPM.png" Stretch="Uniform"/>
</TextBox.Background>
</TextBox>
</Grid>
</UserControl>
和 DisplayBPM.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace quaselaeuespero
{
/// <summary>
/// Interaction logic for DisplayBPM.xaml
/// </summary>
public partial class DisplayBPM : UserControl
{
private void BPMTexto_TextChanged(object sender, EventArgs e)
{
BPM = Convert.ToDouble(BPMTexto.Text);
}
public static readonly DependencyProperty BPMProperty =
DependencyProperty.Register("BPM", typeof(double), typeof(DisplayBPM), new UIPropertyMetadata(0.0));
public double BPM
{
get { return (double)GetValue(BPMProperty); }
set { SetValue(BPMProperty, value); }
}
public DisplayBPM()
{
InitializeComponent();
BPM = 1;
}
}
}
问题是 BPM(来自 DisplayBPM 的变量,TextBox 从中获取输入)似乎没有改变,如果它改变了,它不会改变 Angle(来自确定旋钮位置的 RotateTransform 的变量)。谁能帮我?我知道可能有很多基本问题,如果你能向我解释一下,那真的会对我有所帮助。非常感谢!
解决方案
首先,制作一个自定义用户控件并Dependency Properties
不能解决WPF
.
WPF
应用程序的主要架构是MVVM
:模型 - 视图 - 视图模型
根据您的特定需求,我会保留,VolumeControl
因为这是创建具有自定义的自定义的正确UserControls
方法DependencyProperties
然后我会删除该类DisplayBPM
,因为它不需要。
我将设置一个ViewModel
在包含单个BPM
字符串属性的控件之间进行交互。
ViewModel
这是我将使用的示例:
public class MainWindowViewModel : INotifyPropertyChanged
{
private string _bpm;
public string BPM
{
get => _bpm;
set
{
_bpm = value;
RaisePropertyChanged(nameof(BPM));
}
}
public void RaisePropertyChanged(string property)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
}
public event PropertyChangedEventHandler PropertyChanged;
}
作为旁注,我建议
INotifyPropertyChanged
您继续阅读,因为那里有许多图书馆可以用来帮助WPF
和MVVM
然后我会Window
用 theVolumeControl
和 aTextBox
来设置这个BPM
值。这两个都应该有一个{Binding BPM, Mode=TwoWay}
,以便您BPM
在控件之间传递值。
TextBox
然后,如果您希望在用户键入时或在用户离开字段后(通常使用Tab
键)获取值,则可以决定绑定。要VolumeControl
在用户键入时更新值,请UpdateSourceTrigger=PropertyChanged
在绑定中使用。
在此处查看我的示例:
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="Background.png"/>
</Grid.Background>
<local:VolumeControl
x:Name="Knobão"
Margin="123,240,675,111"
RenderTransformOrigin="0.5,0.5"
Angle="{Binding BPM, Mode=TwoWay}" />
<TextBox
Text="{Binding BPM, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Margin="68,153,656,274"
MinWidth="222"
VerticalAlignment="Center"
HorizontalAlignment="Center">
<TextBox.Background>
<ImageBrush
ImageSource="Display BPM.png"
Stretch="Uniform" />
</TextBox.Background>
</TextBox>
</Grid>
如果您不熟悉其中的工作方式ViewModels
和DataContext
工作方式,WPF
我建议您阅读一下,因为这是MVVM
为应用程序设置架构的主要方式WPF
。
推荐阅读
- r - 将日期时间转换为 R(即 5 月 18 日)
- javascript - 在 indesign 脚本中获取当前文本框宽度
- javascript - 为什么javascript比较(“真”==真)是假的?
- c - 如何一次为结构中的多个成员赋值
- r - R中的if语句与for结合
- css - 使用类激活图片标签中的某些图像
- typescript - Teams Bot - 租户管理员禁用此机器人,getTeamsDetails 时出错
- assembly - 使用寄存器与值调用 JMP 的不同行为
- c++ - C++ 错误:由于 swprintf 从 'int' 到 'const wchar_t* 的转换无效
- sql-server - ASP.NET MVC 显示用户最近搜索和添加到 SQL Server 数据库