WPF UserControl - Почему значение не распространяется? - PullRequest
0 голосов
/ 08 апреля 2020

Этот пользовательский элемент управления, который я разрабатываю, работал, и теперь он перестал работать, и я не могу понять, что изменилось. (Я закрывал и повторно открывал VS2019 несколько раз, он не показывает ошибок при сборке или запуске.) Для ясности я включил соответствующие разделы кода ниже, но включил весь код внизу.

MessagePanel.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";
}

MessagePanel.xaml

<TextBox Text="{Binding MessageResponse, RelativeSource={RelativeSource AncestorType=UserControl}}" />

MainWindow.xaml

<uc:MessagePanel MessageResponse="{Binding MainMessageResponse}" />

MainVM.cs

private string mainMessageResponse;
public string MainMessageResponse
{
    get => mainMessageResponse;
    set
    {
       mainMessageResponse = value;
       NotifyPropertyChanged();
    }
}

Насколько я могу судить, DependencyProperty MessageResponse в MessagePanel следует распространить на свойство MainMessageResponse в модели представления MainVM.cs. Конечно, если я вставляю код в модель представления для установки значения MainMessageResponse, срабатывает NotifyPropertyChanged(), и значение появляется в границах TextBox в MainWindow.xaml. Но когда я нажимаю на любую кнопку пользовательского элемента управления, хотя значение отображается в пределах TextBox в MessagePanel.xaml, значение больше не распространяется на MainMessageResponse.

Чего мне здесь не хватает?

Далее следует полный код (при необходимости):

MessagePanel.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>

MesssagePanel.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
    }
}

MainWindow .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>

MainWindow.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;
        }
    }
}

MainVM.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

    }
}

1 Ответ

1 голос
/ 08 апреля 2020

Вы должны установить Mode из Binding на TwoWay. Вы можете сделать это для отдельной привязки в разметке XAML:

<uc:MessagePanel MessageResponse="{Binding MainMessageResponse, Mode=TwoWay}" />

Или вы можете указать значение по умолчанию для всех привязок при регистрации свойства зависимости в элементе управления:

public static readonly DependencyProperty MessageResponseProperty =
    DependencyProperty.Register("MessageResponse", typeof(string), typeof(MessagePanel),
        new FrameworkPropertyMetadata("") { BindsTwoWayByDefault = true });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...