2016-08-21 9 views
0

この問題は非常に基本的なことです。私はWPFを学んだだけで、文字列プロパティへのtextbox.textへの単純な双方向バインディングを作成できませんでした。単純なWPFテキストボックステキストのバインドTwoWay

XAMLコード:

<Window x:Class="WpfApplication1.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:WpfApplication1" 
    mc:Ignorable="d" 
    Title="MainWindow" Height="350" Width="525"> 
<Grid x:Name="StuInfo"> 
    <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" Margin="10,26,0,0" TextWrapping="Wrap" Text="{Binding Path=str,Mode=TwoWay}" VerticalAlignment="Top" Width="120"/> 
    <Button x:Name="button" Content="Check" HorizontalAlignment="Left" Margin="10,67,0,0" VerticalAlignment="Top" Width="75" Click="button_Click"/> 
</Grid> 

C#コード

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     str = "OK"; 
    } 

    public string str { get; set; } 

    private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Console.WriteLine(str); 
    } 
} 

まず、テキストボックスには "OK" と表示されませんが、それは空白になっています。次に、引用符を付けずに「blablabla」と入力して、テキストボックスに別のテキストを入力しました。次に、ボタンをクリックして、自分のstrプロパティが更新されているかどうかを確認します。明らかに、strにはまだ "OK"が含まれています。

私はここで何が間違っていましたか?私は拘束力のある仕事をするために何を失いましたか?

答えて

1

問題は、あなたはWindowのCodebehindにバインドするのではなく、DataContextにバインドすることです。

はこれを試してみてください:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = new DC(); 
    } 

    public class DC 
    { 
     public string str { get; set; } 

     public DC() 
     { 
      str = "OK"; 
     } 
    } 
} 

通常は、2つの異なるファイルを持っているだろうが、テストのために、あなたは一つのファイルにそれを行うことができます。 その後、DC(DataContext)はINotifyPropertyChangedインターフェイスを実装する必要があります。

がWPFに新人としてこのhttp://www.codeproject.com/Articles/165368/WPF-MVVM-Quick-Start-Tutorial

+0

またはこれにあなたのDataContextを設定することができますが、それは本当に悪い考えです。 ViewModelとビューを分離する必要があります。 –

+0

したがって、DataContextを設定することで問題は解決します。とにかく、私はオブジェクトをインスタンス化せずに文字列プロパティを直接使用することなく動作させることができますか?この質問の答えはこれにDataContextを設定していますか? – kurakura88

+1

ウィンドウのコードビーンにバインドすることはできますが、それには何も問題はありません: 'public MainWindow {InitializeComponent(); ** DataContext = this; **} ' – slugster

1

のようなMVVMに関するいくつかの記事を検索してみてください、このすべてのバインドとDataContextのジャズは非常に混乱することができます。これが何を言っていることは、あなたがTextBoxDataContextがあるものは何でもあなたのTextプロパティをバインドしたいということです...のは、最初のあなたのバインディング式で始まる

<TextBox Text="{Binding Path=str, Mode=TwoWay}"/>

をしてみましょう。 DataContextは本質的にあなたのTextBoxからのデータを取得している「もの」です。今ここにはこすりがあります。 DataContextは、明示的に設定されていなければ、ビジュアルツリーの "上の"要素から継承されます。あなたのコードでは、TextBoxはから継承され、Grid要素はDataContextの要素をWindowから継承しています。 DataContextWindowに設定されていないことを確認すると、nullというDataContextプロパティのデフォルト値が適用されます。 DataContextは、ウィンドウの子要素のいずれにも設定されていません。継承を介して、そのウィンドウのすべての子のDataContextnullに設定されます。

バインド式にSourceプロパティを指定しなかったことに注意してください。

<TextBox Text="{Binding Source=left_out, Path=str, Mode=TwoWay}"/>

このプロパティが省略された場合、バインディングのソースが、この場合、上記の理由のために、ヌルである、要素DataContextであることが示唆されます。基本的に、あなたの表現がここで言うことは、テキストプロパティをWPFで解決されたDataContext.strにバインドしたいということです。null.strです。

OK、さて、あなたのTextBox.TextDataContextをウィンドウのコードビハインドにバインドするには、どうすればそのstrプロパティを取得できますか?これを行うにはいくつかの方法がありますが、私たちの目的のために、TextBox.Textプロパティのバインディングで明示的に設定することに焦点を当てます。さて、バインディングの3つの異なる "ソース"タイプのプロパティがあります。 "ソース"は、コントロール/要素のバインドでデータを取得する場所です。我々はSource,RelativeSource、およびElementNameを持っています。ここではElementNameに焦点を絞るつもりですが、他のものは研究や理解に不可欠です。

Window要素をElementNameプロパティでアクセスできるようにします。

<Window x:Class="WpfApplication1.MainWindow" 
     x:Name="_window" 
     ... 

今、私たちはウィンドウを参照するために結合TextBox.TextElementNameプロパティを設定することができます。

<TextBox Text="{Binding ElementName=_window, Path=str, Mode=TwoWay}"/>

これは、バインディングです解決しようとすると結合が_window.strプロパティを探しすることを意味します。この時点では、まだstrの値がTextBoxに反映されていない可能性があります。これは、値がウィンドウのコンストラクタのInitializeComponentメソッドの後に設定されているためです。この関数では、初めてバインディングが解決されます。 InitializeComponentを呼び出す前にstrの値を設定すると、値はTextBoxに反映されます。

これにより、依存関係のプロパティが表示されます。今のところ、依存関係のプロパティに変更通知が組み込まれていることがわかります。変更通知は、バインディングが変更されたときに「認識」し、バインド値を再度解決する必要があるために必要です。はい、INotifyPropertyChangedをコードの背後に置くことができますが、DependencyPropertiesを使用するための良い引数がありますが、この時点で問題が混乱するだけです。しかし、それは理解するために不可欠なもののもう一つです。

strプロパティののコードは次のとおりです。

public static readonly DependencyProperty StrProperty 
    = DependencyProperty.Register("Str", typeof(string), typeof(MainWindow), 
     new FrameworkPropertyMetadata(FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 
public string Str 
{ 
    get{return (string)GetValue(StrProperty);} 
    set{SetValue(StrProperty,value);} 
} 

今、あなたは、このようなのような値を設定すると、それはあなたのTextBoxへの結合を介して反映されていることができます。

public MainWindow() 
{ 
    InitializeComponent(); 
    Str = "OK"; 
} 

この時点で、すべて正常であるはずです。これが助けてくれることを願っていますそれは私がしばらくWPFのハングを取得しました。私の提案は、DataContextBinding、およびDependencyPropertyのようにできるだけ多くのものをWPFのコアとして読むことです。がんばろう!

+0

私に説明する時間をとってくれてありがとう。それは、代わりに "Binding Source"に "DataContext"を設定すると意味しますか?あなたの例では、 '{Binding Source = _window ...}'を設定して動作させることができますか? – kurakura88

+0

大歓迎です。助けてくれてありがとう!あなたの質問については、答えはノーです。 'ElementName'プロパティは' Window'の 'x:Name'属性で使用できる唯一のものです。 'Source'は静的リソースと動的リソースに使用されます。これはもう少し進んでいます。 –

+0

'Source'は、バインディングオブジェクトまたは" Source "を明示的に解決する3つの方法のうちの1つに過ぎないと想像するのに役立ちます。私はこれが混乱していることを知っている。相互に排他的な 'Source'、' RelativeSource'、または 'ElementName'を使うことができます。これらのどれも使用せず、 "Source"領域を空白のままにしておくと、それは 'DataContext'に解決されます。 'Source'と' Source'の違いに注目してください。 「Source」はバインディングの実際のプロパティであり、「Source」はバインディングの基礎となるソースオブジェクトを参照するためのセマンティクスである。 –

関連する問題