質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

.NET Framework 4.0

Microsoft Windows用のソフトウェア開発環境/実行環境である .NET Frameworkの4番目のメジャーバージョンです。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

3回答

20557閲覧

WPFでコントロールを別クラスとバインディングする方法

alths122

総合スコア16

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

.NET Framework 4.0

Microsoft Windows用のソフトウェア開発環境/実行環境である .NET Frameworkの4番目のメジャーバージョンです。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

0グッド

1クリップ

投稿2017/01/26 13:33

編集2017/01/26 14:19

WPFでコントロールを別クラスとバインディングする方法

C#/WPFにて、コントロールと別のクラスを上手くバインディングすることが出来ず困っています。
ViewModelから、コントロール(Button)に対応した別のクラスを経由して、画面に値を設定したいと思っています。
しかし画面に反映することができないため質問します。

※補足です
ここでは、MainWindow.xaml, MainWindow.xaml.cs の2ファイルは変更しないことを前提とさせてください。
XAMLにて DataContext="{Binding Btn1} と書いているのは間違えているわけではありません。
XAMLでは、ButtonにはDataContextのみを指定し、Contentは指定しないこととします。

ちなみに、本来やりたいことはもう少し複雑で、
最終的にはこれを発展させ、Buttonを継承したMyButtonを画面に設置、MyButtonとButtonDataをViewModelを経由してBindingする、という形を取ることになります。

構成

プロジェクトの構成(主なもの)は以下の通りです。

  • MainWindow.xaml
  • MainWindow.xaml.cs
  • ViewModel.cs
  • ButtonData.cs

MainWindow.xaml.cs

MainWindow は DataContextにViewModelを指定します。

[MainWindows.xaml.cs]

cs

1 public partial class MainWindow : Window 2 { 3 public MainWindow() 4 { 5 InitializeComponent(); 6 this.DataContext = new ViewModel(); 7 } 8 }

MainWindow.xaml

画面にはボタンを一つだけ設置します。
Btn1のDataContextには、ViewModelの"Btn1"というプロパティをバインドします。

[MainWindow.xaml]

cs

1<Window x:Class="WpfApplication2.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:WpfApplication2" 7 mc:Ignorable="d" 8 Title="MainWindow" Height="350" Width="525"> 9 <Grid> 10 <Button x:Name="Btn1" DataContext="{Binding Btn1,Mode=TwoWay}" /> 11 </Grid> 12</Window>

ButtonData.cs

ButtonDataは、コントロールのButtonクラスに対応するクラスです。
ViewModelからはButtonクラスではなく、このButtonDataクラスのContentプロパティに値をセットすることで、画面に文字を反映しようとします。

cs

1 public class ButtonData : INotifyPropertyChanged 2 { 3 public ButtonData() { } 4 5 private string _Content; 6 public string Content 7 { 8 get 9 { 10 return this._Content; 11 } 12 set 13 { 14 if (this._Content == value) 15 return; 16 this._Content = value; 17 OnPropertyChanged("Content"); 18 } 19 } 20 21 public event PropertyChangedEventHandler PropertyChanged; 22 protected void OnPropertyChanged(string name) 23 { 24 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 25 } 26 }

ViewModel.cs

最後にViewModelクラスです。
ViewModelには、MainWindow.xamlに設置したボタン"Btn1"に対応するプロパティ"Btn1"を用意します。
ViewModel上で、Btn1.Contentに値をセットすると、これが画面に反映されることを想定しています。

cs

1 public class ViewModel : INotifyPropertyChanged 2 { 3 public ViewModel() 4 { 5 var button = new ButtonData(); 6 button.Content = "hello"; 7 Btn1 = button; 8 } 9 10 private ButtonData _Btn1; 11 public ButtonData Btn1 12 { 13 get 14 { 15 return _Btn1; 16 } 17 set 18 { 19 _Btn1 = value; 20 OnPropertyChanged("Btn1"); 21 } 22 } 23 24 public event PropertyChangedEventHandler PropertyChanged; 25 protected void OnPropertyChanged(string name) 26 { 27 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name)); 28 } 29 }

疑問

上記のようにコードを作成しました。
想定では、画面に表示されるボタンに"hello"と表示されるはずでしたが、何も表示されません。
なぜボタンには何も表示されないのでしょうか。
(ここではButtonDataやViewModelクラスを必ず使用する、という前提の質問です。)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

こんにちは。

DataContextに設定したからといってButtonのプロパティに反映されるわけではありません。
ButtonのContentnにViewModelの値を設定したいのであれば、以下のような感じでしょう。

C#

1public class MyButton : Button 2{ 3 public MyButton() 4 { 5 SetBinding(ContentProperty, new Binding("Content")); 6 } 7}

投稿2017/01/26 14:01

編集2017/01/26 14:35
Tak1wa

総合スコア4791

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alths122

2017/01/26 14:07

解答ありがとうございます。 xamlでは、ボタンにはDataContextのみを指定することが前提(今回の仕様)とさせてください。
Tak1wa

2017/01/26 14:24

XAMLを使わないとなるとコードビハインドを使うしかないです。 何らかの方法でDataContextのプロパティとButtonコントロールのDependencyPropeprtyをバインドする必要があります。 それはOKなのでしょうか
Tak1wa

2017/01/26 14:26

あ、もしやDataTemplateを使っている?
alths122

2017/01/26 14:26

はい、その方法は構いません。 例えばButtonを継承したMyButtonを作ったとして、MyButtonの中でDependencyPropeprtyをバインドするような形になるのでしょうか?
alths122

2017/01/26 14:28

すみません、DataTemplateは使用しません。 DependencyPropeprtyを使用するのが正解だと、うっすらと記憶しております。 (うっすらと記憶にある業務コードの真似事なので…)
Tak1wa

2017/01/26 14:35

うーん…コードビハインドで冗長になっただけで、あまり意味を感じないですけど追記しました。
alths122

2017/01/26 14:45

ありがとうございます。まさに求めていた答えでした。 なぜButtonではできず、MyButtonでは可能なのでしょうか? Buttonクラスには SetBinding(ContentProperty, new Binding("Content")) と同様の機能が組み込まれていると思っていたのですが、違うということなのでしょうか。
ozwk

2017/01/26 14:47

冗長になって 初見だとxamlと動作のギャップに戸惑い、 そこまでしてできることが Contentの代わりにDataContextを書くようになるだけという…
haru666

2017/01/26 14:51

バインドは明示的な作業ですから、どこかで指定しないとできません 動的に変更する必要がない場合は文字列を直接指定すればいいわけですし、無駄なコストですから それと、new BindingではBindingModeをTwoWayにしておかないと、途中でButtonDataのContentを書き換えても表示が変更されません。
alths122

2017/01/26 14:54

>ozwkさん その気持ちはよく分かるのですが… (私もそのギャップに戸惑って質問してしまいましたので) Buttonのような簡単なコントロールではなく、もっと複雑なコントロール(データツリーやデータグリッドなど)を継承してさらにカスタマイズする際に有用だという話を聞きました。 (どう有用なのかは、まだ理解できていませんが…)
haru666

2017/01/26 15:07

動作をアーキテクチャ側でコントロールしたいという発想はありますよ。 複数の設定を一か所で行って置き、またButtonDataのようなクラスを先に複数用意しておくことでコーダーの作業を単純化できます。この手のプログラミングはMagicと言われることがあります。
guest

0

<Button x:Name="Btn1" DataContext="{Binding Btn1,Mode=TwoWay}" Content={Binding Content}/>
または
<Button x:Name="Btn1" Content={Binding Btn1.Content}/>

投稿2017/01/26 13:55

編集2017/01/26 14:00
mikupedia

総合スコア159

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alths122

2017/01/26 13:59

Btn1.ContentをBindingする方法もあるかとは思いますが、 ここはBtn1自体をBindingする方法を取ることを前提とさせてください。
alths122

2017/01/26 14:06

解答ありがとうございます。 xamlでは、ボタンにはDataContextのみを指定することが前提(今回の仕様)となります。
guest

0

答えとしては、できません。

DataContextはその名の通りContextであり、それ自体が表面に影響を及ぼすものではありません。
DataContextに値を設定してもその他のものがBindingされていなければボタンに関連付けられたただのデータです。

ボタンにDataContextのみを指定し、一切XAML・コードビハインドを修正せず画面に表示するようなハックはありません。

投稿2017/01/26 14:20

haru666

総合スコア1591

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

alths122

2017/01/26 14:22

…とは思うのですが、業務コードではこれを実現しており、不思議に思っています…
haru666

2017/01/26 14:28

他のところにコードありませんか? 思いっきり迂回してなんの利便性の無いことをやってみたり、スタイルで必ずContentとBindさせておいたり、そういうことしてませんか?
haru666

2017/01/26 14:32

…っていうか業務コードでやってるのがあるならそっちちゃんと読みましょう。 こっちで違う答えでもし解決したとしてそれをやったら全体としては悪化させてるだけです。
alths122

2017/01/26 14:32

Styleは確認していますが、特別にボタンに対してStyleは指定していなかった認識です。 実際にはButtonを継承したクラスを使用しており、またこのクラスの中でDependencyPropeprtyを使用していた覚えがあります。 (今となっては確認のしようがないのですが…)
haru666

2017/01/26 14:39

Buttonを継承したクラスがあったんですね? それが無きゃこのなぞなぞは解けません。 最初から固定のプロパティにBindする前提のコントロールは確か作れたと思います。 それを伏せて質問しても同じ結果は得られないと思いますよ。 まずその時点でXAML弄ってますからね… UserControlのサンプルなんかで見た記憶がありますし、たぶんContentにBindしておくだけでそういうボタンは作れたと思います。 私の家にはVS環境がないので確認してみることができませんが…
alths122

2017/01/26 14:46

申し訳ありません。構成に関して勘違いをしておりました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問