繁体   English   中英

在WPF中将UserControl的依赖项属性绑定到MainWindow ViewModel

[英]Binding Dependency Property of UserControl to MainWindow ViewModel in WPF

请允许我将问题简化为基本问题。

我的项目中有一个UserControl1。 它具有如下所示的TextBox:

<TextBox Text="{Binding TextProperty}"/>

在后面的代码中,我有一个像这样的依赖项属性:

public string TextProperty
{
    get { return (string)GetValue(TextPropertyProperty); }
    set { SetValue(TextPropertyProperty, value); }
}

public static readonly DependencyProperty TextPropertyProperty = DependencyProperty.Register("TextProperty", typeof(string), typeof(UserControl1), new PropertyMetadata(null));

而且UserControl的构造函数很简单

public UserControl1()
{
    InitializeComponent();  
    DataContext = this;  
}

在MainWindow中,我有这个:

<userctrl:UserControl1 TextProperty="{Binding ABC, UpdateSourceTrigger=PropertyChanged}"/>
<TextBox Grid.Row="1" Text="{Binding PQR, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>

现在,在MainWindow的viewModel中,我有:

    private string _abc;
    public string ABC
    {
        get { return _abc; }
        set 
        { _abc = "20";
            OnPropertyChanged();
        }
    }

    private string _pqr;

    public string PQR
    {
        get { return _pqr; }
        set
        {
            if(value != _pqr)
            {
                _pqr = value;
                ABC = PQR;
                OnPropertyChanged();
            }
        }
    }

现在,即使UserControl也应该复制我在文本框中编写的内容,对吗?

但事实并非如此。 我已经在ABC的设置器上设置了断点。 它得到更新,但该更新未到达UserControl。 我的直觉说绑定无提示地失败了,这是因为我已经在UserControl的构造函数中将DataContext设置this

我应该如何解决?

实际情况:

这是UserControl的XAML:

<UserControl x:Class="MyDiskTools.UserControls.NodeGrid.NodeGrid"
             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:MyDiskTools.UserControls.NodeGrid"             
             mc:Ignorable="d">
    <Grid>
        <Grid.Resources>
            <Style TargetType="Button">
                <Setter Property="Padding" Value="5"/>
                <Setter Property="BorderThickness" Value="1"/>
                <Setter Property="Command" Value="{Binding InputCommand}"/>
                <Setter Property="CommandParameter" Value="{Binding Path=Content, RelativeSource={RelativeSource Self}}"/>                
                <Style.Triggers>                    
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="BorderThickness" Value="5"/>
                        <Setter Property="FontSize" Value="20"/>
                        <Setter Property="FontFamily" Value="Times New Roman"/>
                    </Trigger>                    
                </Style.Triggers>
            </Style>
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <UniformGrid Grid.Row="0" Rows="1">
            <Button Content="A" />
            <Button Content="B" />
            <Button Content="C" />
            <Button Content="D" />
            <Button Content="E" />
            <Button Content="F" />
        </UniformGrid>
        <UniformGrid Grid.Row="1" Rows="1">
            <Button Content="G" />
            <Button Content="H" />
            <Button Content="I" />
            <Button Content="J" />
            <Button Content="K" />
            <Button Content="L" />
            <Button Content="M" />
        </UniformGrid>
        <UniformGrid Grid.Row="2" Rows="1">
            <Button Content="N" />
            <Button Content="O" />
            <Button Content="P" />
            <Button Content="Q" />
            <Button Content="R" />
            <Button Content="S" />
            <Button Content="T" />
        </UniformGrid>
        <UniformGrid Grid.Row="3" Rows="1">
            <Button Content="U" />
            <Button Content="V" />
            <Button Content="W" />
            <Button Content="X" />
            <Button Content="Y" />
            <Button Content="Z" />
        </UniformGrid>
        <TextBox Name="InputMessage" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" IsEnabled="False" Background="Beige" Grid.Row="4" Text="{Binding PasswordDisplay, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</UserControl>

下面是代码:

public partial class NodeGrid : UserControl
{
    public NodeGrid()
    {
        InitializeComponent();            
        InputCommand = new InputCharacterCommand(this);
        DataContext = this;
    }

    public string PasswordDisplay
    {
        get { return (string)GetValue(PasswordDisplayProperty); }
        set { SetValue(PasswordDisplayProperty, value); }
    }


    public static readonly DependencyProperty PasswordDisplayProperty =
        DependencyProperty.Register("PasswordDisplay", typeof(string), typeof(NodeGrid), new PropertyMetadata(""));


    private ICommand _inputCommand;

    public ICommand InputCommand
    {
        get
        {
            return _inputCommand;
        }

        set
        {
            _inputCommand = value;
        }
    }


    public void AddCharacter(string input)
    {
        if (input != null)
        {
            PasswordDisplay = string.Concat(PasswordDisplay, input);
        }
    }

    public bool InputAllowed()
    {
        if (PasswordDisplay == null)
        {
            return true;
        }

        if (PasswordDisplay.Length < 50)
        {
            return true;
        }

        return false;
    }

    private void OnPropertyChange([CallerMemberName] string property = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;

}

class InputCharacterCommand : ICommand
{
    private NodeGrid _vmodel;

    public InputCharacterCommand(NodeGrid vm)
    {
        _vmodel = vm;
    }

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return (_vmodel.InputAllowed());
    }

    public void Execute(object parameter)
    {
        _vmodel.AddCharacter(parameter as string);
    }
}

这是我在MainWindow中使用它的方式:

<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
    <WrapPanel HorizontalAlignment="Center">
        <Label Content="Enter PIN"/>
        <TextBox CommandManager.PreviewCanExecute="HandleCanExecute" Foreground="Transparent" MinWidth="100" Padding="10,0" Text="{Binding PIN, UpdateSourceTrigger=PropertyChanged}"/>
    </WrapPanel>
    <customlock:NodeGrid  MinHeight="250" MinWidth="500" PasswordDisplay="{Binding NodeGridDisplay}"/>
    <Button VerticalAlignment="Center" HorizontalAlignment="Center" Content="Unlock!"/>
</StackPanel>

背后的代码:

private void HandleCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    if (e.Command == ApplicationCommands.Cut ||
        e.Command == ApplicationCommands.Copy ||
        e.Command == ApplicationCommands.Paste)
        {
            e.CanExecute = false;
            e.Handled = true;
        }

}

现在,ViewModel:

    private string _PIN;

    public string PIN
    {
        get
        {
            return _PIN;
        }
        set
        {
            if(value != _PIN)
            {
                _PIN = value;                    
                OnPropertyChanged();
                NodeGridDisplay = HashIt(_PIN);
            }
        }
    }

    private string _nodeGridDisplay;

    public string NodeGridDisplay
    {
        get
        {
            return _nodeGridDisplay;
        }

        set
        {
            if (value != _nodeGridDisplay)
            {
                _nodeGridDisplay = value;
                OnPropertyChanged();
            }                
        }
    }

    private string HashIt(string input)
    {
        using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
        {
            return System.Text.Encoding.Default.GetString(md5.ComputeHash(System.Text.Encoding.ASCII.GetBytes(input))).GetHashCode().ToString();
        }
    }

预期功能是什么?

让我说明一下。

可以输入PIN,其哈希将显示在NodeGrid中。 然后,用户将单击将与哈希连接的字母。 然后,用户可以单击解锁。

您应该在UserControl使用ElementName或使用RaltiveResource来找到它,并且不应该使用DataContext = this。 (请参阅此答案此链接

给您的userControl命名并输入:

<UserControl x:Class= ......
      Name="userControl">
     <TextBox Text="{Binding Text, ElementName = userControl}"/>
</UserControl>

请注意,您应该使用Text而不是TextProperty并确保将_abc = "20"更改为_abc = value

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM