0

允许我将问题简化为其基本块。将UserControl绑定到WPF中MainWindow ViewModel的依赖属性

我在我的项目中有一个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)); 

而且用户控件的构造函数是简单地

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

在MainWindow中,我有这个:

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

现在,在主窗口的视图模型,我有:

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(); 
      } 
     } 
    } 

现在,即使在用户控件应该复制无论我在文本框中写的,对不对?

但它没有。我为ABC的制定者设定了断点。它得到更新,但该更新没有达到UserControl。我的直觉说绑定失败了,这是因为我在UserControl的构造函数中设置了DataContextthis

我该如何解决它?

的实际情景:

下面是用户控件的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); 
    } 
} 

,这里是我如何使用它在我的主窗口中:

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

} 

而现在,视图模型:

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(); 
     } 
    } 

什么是预期的功能?

让我来说明一下。

The Lock

人们可以输入PIN码,该散列将显示在NodeGrid。然后用户将点击与散列连接的字母。然后用户可以点击解锁。

回答

1

您应该在UserControl中使用ElementName或使用RaltiveResource找到它,并且不应该使用DataContext = this。(见this answerthis link

给你的用户控件的名称并写:

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

请注意,你应该使用Text代替TextProperty并确保改变_abc = "20"_abc = value

+0

对不起'_abc =“20”'。我正在使用它来查看它是否以恒定值工作。 –

+0

也许我给出的问题描述过于简单。我的情况稍微复杂一点。我编辑了我的问题来说明我的特殊问题。 –

+0

和你的简单例子一样。在这部分使用''ElementName'''Text =“{Binding PasswordDisplay,Mode = TwoWay,UpdateSourceTrigger = PropertyChanged}”''。其他的事情似乎很好。 – Ron