c# - WPF UserControl - 为什么值没有传播?
问题描述
我正在开发的这个用户控件正在工作,现在它已经停止工作,我无法弄清楚发生了什么变化。(我已经关闭并重新打开了 VS2019 几次,它在构建或运行时没有显示错误。)为了清楚起见,我在下面包含了相关的代码部分,但我在底部包含了所有代码。
消息面板.xaml.cs
public string MessageResponse
{
get { return (string)GetValue(MessageResponseProperty); }
set { SetValue(MessageResponseProperty, value); }
}
// Using a DependencyProperty as the backing store for MessageResponse. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MessageResponseProperty =
DependencyProperty.Register("MessageResponse", typeof(string), typeof(MessagePanel), new PropertyMetadata(""));
private void ButtonProceed_Click(object sender, RoutedEventArgs e)
{
MessageResponse = "Proceed";
}
private void ButtonHalt_Click(object sender, RoutedEventArgs e)
{
MessageResponse = "Halt";
}
消息面板.xaml
<TextBox Text="{Binding MessageResponse, RelativeSource={RelativeSource AncestorType=UserControl}}" />
主窗口.xaml
<uc:MessagePanel MessageResponse="{Binding MainMessageResponse}" />
主虚拟机.cs
private string mainMessageResponse;
public string MainMessageResponse
{
get => mainMessageResponse;
set
{
mainMessageResponse = value;
NotifyPropertyChanged();
}
}
据我所知,DependencyProperty MessageResponse
inMessagePanel
应该传播到MainMessageResponse
view model 中的属性MainVM.cs
。当然,如果我在视图模型中插入代码来设置MainMessageResponse
值,NotifyPropertyChanged()
就会触发并且值出现TextBox
在MainWindow.xaml
. 但是,当我单击用户控件的任一按钮时,尽管该值出现在绑定TextBox
中MessagePanel.xaml
,但该值不再传播到MainMessageResponse
.
我在这里想念什么?
完整代码如下(剥离到最基本的必需品):
消息面板.xaml
<UserControl x:Class="Common.UserControls.MessagePanel"
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"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="400"
Visibility="Visible" >
<Grid>
<Border
MinWidth="50" MinHeight="50"
Background="LightCoral"
BorderBrush="Black"
BorderThickness="1"
HorizontalAlignment="Center"
VerticalAlignment="Center">
<StackPanel>
<StackPanel Width="400" Margin="5,5,5,0">
<TextBox x:Name="Title" TextWrapping="Wrap" MinHeight="16" Background="LightPink" HorizontalAlignment="Center" />
<TextBox x:Name="Message" IsReadOnly="True" TextWrapping="Wrap" MinHeight="42" Background="LightPink" HorizontalAlignment="Stretch" />
</StackPanel>
<DockPanel >
<CheckBox x:Name="CheckBoxConfirm" Checked="CheckBoxConfirm_Checked" Unchecked="CheckBoxConfirm_Unchecked" FontStyle="Italic" FontWeight="Bold" HorizontalAlignment="Center" />
</DockPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button x:Name="ButtonProceed" Click="ButtonProceed_Click" Width="50" Margin="5,5" />
<Button x:Name="ButtonHalt" Click="ButtonHalt_Click" Width="50" Margin="5,5" />
</StackPanel>
<TextBox Visibility="Visible" Name="Response" Text="{Binding MessageResponse, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</StackPanel>
</Border>
</Grid>
</UserControl>
消息面板.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace Common.UserControls
{
/// <summary>
/// Interaction logic for MessagePanel.xaml
/// </summary>
public partial class MessagePanel : UserControl
{
public enum MessageType
{
Ok,
OkCancel,
YesNo
}
public MessagePanel()
{
InitializeComponent();
Title.Text = "This is a title";
Message.Text = "This is a test message with title and [Yes] and [No] buttons and requires a confirmation.";
ButtonProceed.Content = "Yes";
ButtonHalt.Content = "No";
CheckBoxConfirm.Visibility = Visibility.Collapsed;
}
#region Dependeny Properties
public string MessageResponse
{
get { return (string)GetValue(MessageResponseProperty); }
set { SetValue(MessageResponseProperty, value); }
}
// Using a DependencyProperty as the backing store for MessageResponse. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MessageResponseProperty =
DependencyProperty.Register("MessageResponse", typeof(string), typeof(MessagePanel), new PropertyMetadata(""));
#endregion
#region Event Handlers
private void ButtonProceed_Click(object sender, RoutedEventArgs e)
{
// User wants to proceed
MessageResponse = "Proceed";
}
private void ButtonHalt_Click(object sender, RoutedEventArgs e)
{
// User wants to not proceed
MessageResponse = "Halt";
}
private void CheckBoxConfirm_Checked(object sender, RoutedEventArgs e)
{
ButtonProceed.IsEnabled = true;
}
private void CheckBoxConfirm_Unchecked(object sender, RoutedEventArgs e)
{
ButtonProceed.IsEnabled = false;
}
#endregion
}
}
主窗口.xaml
<Window x:Class="WpfUserControl.Views.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:uc="clr-namespace:Common.UserControls;assembly=Common"
xmlns:local="clr-namespace:WpfUserControl"
mc:Ignorable="d"
Title="Demo"
Height="300" Width="600">
<Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="10" />
<RowDefinition Height="50" />
<RowDefinition Height="50" />
<RowDefinition Height="10" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="1" Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center">
<TextBox Text="{Binding MainMessageResponse}" Width="50" Height="22" />
</StackPanel>
</Grid>
<uc:MessagePanel MessageResponse="{Binding MainMessageResponse}" />
</Grid>
</Window>
主窗口.xaml.cs
using System.Windows;
using WpfUserControl.ViewModels;
namespace WpfUserControl.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MainVM vm = new MainVM();
DataContext = vm;
}
}
}
主虚拟机.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace WpfUserControl.ViewModels
{
public partial class MainVM : INotifyPropertyChanged
{
public MainVM()
{
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
#region MessagePanel
private string mainMessageResponse;
public string MainMessageResponse
{
get => mainMessageResponse;
set
{
mainMessageResponse = value;
NotifyPropertyChanged();
}
}
#endregion
}
}
解决方案
您应该将 的设置Mode
为。您可以对 XAML 标记中的单个绑定执行此操作:Binding
TwoWay
<uc:MessagePanel MessageResponse="{Binding MainMessageResponse, Mode=TwoWay}" />
或者您可以在控件中注册依赖属性时为所有绑定指定默认值:
public static readonly DependencyProperty MessageResponseProperty =
DependencyProperty.Register("MessageResponse", typeof(string), typeof(MessagePanel),
new FrameworkPropertyMetadata("") { BindsTwoWayByDefault = true });
推荐阅读
- c# - 找不到方法:'System.Object Microsoft.EntityFrameworkCore.Infrastructure.IAnnotatable.get_Item(System.String)'
- watchos - 如何确定手表方向(即数字表冠在右侧还是左侧?)
- c - 在 VSCode - C 中将 coreDumpPath 添加到 launch.json
- html - 角度无法访问 object.id
- django - Django 3.0:django-notifications-hq,当卖家创建产品时,管理员会收到通知
- python - 读取txt文件中的数据并将其放入特定格式
- javascript - 覆盖 z-index
- python - 在 Discord.Py 中,如何解决 TooManyRequests 的错误?
- python - 在python中构造一个包含6N个元素的向量
- android - Kotlin: enqueueWork + JobIntentService