C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[16]: CoerceValueCallbackとBinding


(過去ログ 63 を表示中)

[トピック内 19 記事 (1 - 19 表示)]  << 0 >>

■36371 / inTopicNo.1)  CoerceValueCallbackとBinding
  
□投稿者/ 倉田 有大 (610回)-(2009/05/28(Thu) 05:41:09)

分類:[.NET 全般] 

2009/05/28(Thu) 05:48:33 編集(投稿者)
こんにちは倉田 有大です。
みなさんのご指摘を元にユーザーコントロールを作成し直しました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace SkypeTRPGToolWPF
{
    /// <summary>
    /// numericUpDown.xaml の相互作用ロジック
    /// </summary>
    public partial class numericUpDown : UserControl
    {
  
        public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(numericUpDown), new FrameworkPropertyMetadata(0,(FrameworkPropertyMetadataOptions.BindsTwoWayByDefault),new PropertyChangedCallback(OnValuablePropertyChanged), new CoerceValueCallback(CoerceValue)));
  
   
        public int Maximum
        {
            set;
            get;
        }
        public int Mininum
        {
            set;
            get;
        }
        public int Value
        {
            set
            {
                SetValue(ValueProperty, value); 
            }
            get
            {                
                return (int)GetValue(ValueProperty); ;
            }
        }

        public numericUpDown()
        {
            Maximum = 100;
            Mininum = 0;            
            InitializeComponent();
            Value = 0;
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {            
            Value++;            
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {
            Value--;
        }

        public void SetText(string text)
        {
            this.textBlock1.Text = text;
        }

        private static void OnValuablePropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            numericUpDown n = d as numericUpDown;

            n.SetText(e.NewValue.ToString());                        
        }

        private static object CoerceValue(DependencyObject d, object baseValue)   
        {
            numericUpDown n = d as numericUpDown;

            int value = (int)baseValue;

            if (value >= n.Maximum)
                value = n.Maximum;
            if (value <= n.Mininum)
                value = n.Mininum;

            return value;
        }          
    }
}

<UserControl x:Class="SkypeTRPGToolWPF.numericUpDown"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Height="25" Width="300">
    <Grid>
        <Grid.RowDefinitions>            
            <RowDefinition/>            
            <RowDefinition/>            
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <TextBlock FontSize="20" Grid.RowSpan="2" Name="textBlock1" Grid.ColumnSpan="2" />
        <Button Grid.Row="0" Grid.Column="1" Height ="Auto" HorizontalAlignment="Right" Margin="0" Name="button1" Width="23" Click="button1_Click" VerticalAlignment="Top">↑</Button>
        <Button Grid.Row="1" Grid.Column="1" Height ="Auto" HorizontalAlignment="Right" Name="button2" Width="23" VerticalAlignment="Bottom" Click="button2_Click">↓</Button>
        <Border BorderThickness="1" Grid.RowSpan="2" BorderBrush ="#FF7F9DB9" Width="auto" Height="Auto"/>
    </Grid>
</UserControl>

上記がユーザーコントロールです。

メインウインドウで

<local:numericUpDown Value = "{Binding Path = DiceNum}" Width="auto" Grid.Row="2" Grid.Column="1" x:Name="numericUpDown1" />

上記のようにはりつけています。

public int DiceNum
     {
         set
         {
             this.TRPGData.DiceNum = value;
         }
         get
         {                
             return this.TRPGData.DiceNum;
         }
     }

上記がバインドしているプロパティです

1)ユーザーコントロールのボタンを押しbutton2_Clickを呼ぶ
2)SetValue(ValueProperty, value)が実行される
3)バインドされているDiceNumプロパティーに値が入る
4)CoerceValueで検証

上記の順番で実行されることを確認したのですが、
3)と4)の順番が想定していたより逆なため、DiceNumプロパティーに値を渡した後に、CoerceValueでユーザーコントロールのValue値が修正されてしまいます。
DiceNumとユーザーコントロールのValueを同期させたいのですが、どのような考え方でソースを修正したらいいでしょうか?
アドバイスをいただけたら幸いです。

引用返信 編集キー/
■36383 / inTopicNo.2)  Re[1]: CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (611回)-(2009/05/28(Thu) 10:52:02)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.ComponentModel;

namespace SkypeTRPGToolWPF
{
    /// <summary>
    /// numericUpDown.xaml の相互作用ロジック
    /// </summary>
    public partial class numericUpDown : UserControl
    {
  
        public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(numericUpDown), new FrameworkPropertyMetadata(0,(FrameworkPropertyMetadataOptions.BindsTwoWayByDefault),new PropertyChangedCallback(OnValuablePropertyChanged), new CoerceValueCallback(CoerceValue)));

        public static readonly DependencyProperty MaximumProperty =
   DependencyProperty.Register("Maximum", typeof(int), typeof(numericUpDown), new FrameworkPropertyMetadata(100, (FrameworkPropertyMetadataOptions.BindsTwoWayByDefault), new PropertyChangedCallback(OnMaximumPropertyChanged), new CoerceValueCallback(CoerceMaximum)));

        public static readonly DependencyProperty MininumProperty =
   DependencyProperty.Register("Mininum", typeof(int), typeof(numericUpDown), new FrameworkPropertyMetadata(0, (FrameworkPropertyMetadataOptions.BindsTwoWayByDefault), new PropertyChangedCallback(OnMininumPropertyChanged), new CoerceValueCallback(CoerceMininum)));
  
   
        public int Maximum
        {
            set
            {
                SetValue(MaximumProperty, value); 

            }
            get
            {
                return (int)GetValue(MaximumProperty);
            }
        }
        public int Mininum
        {
            set
            {
                SetValue(MininumProperty, value);
            }
            get
            {
                return (int)GetValue(MininumProperty);
            }
        }
        public int Value
        {
            set
            {
                SetValue(ValueProperty, value);                
            }
            get
            {                
                return (int)GetValue(ValueProperty); ;
            }
        }

        public numericUpDown()
        {        
            InitializeComponent();            
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            if (Value < this.Maximum)
            {
                Value++;
            }
            else
            {
                Value = this.Maximum;
            }
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {            
            if (Value > this.Mininum)
            {
                Value--;                
            }
            else
            {
                Value = this.Mininum;
            }
        }

        public void SetText(string text)
        {
            this.textBlock1.Text = text;
        }

        private static void OnValuablePropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
        {
            numericUpDown n = d as numericUpDown;

            n.SetText(e.NewValue.ToString());
        }


        private static void OnMaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            
        }

        private static void OnMininumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {

            
        }


        private static object CoerceValue(DependencyObject d, object baseValue)   
        {
            numericUpDown n = d as numericUpDown;

            int value = (int)baseValue;
            
            if (value >= n.Maximum)
                value = n.Maximum;
            if (value <= n.Mininum)
                value = n.Mininum;
            
            return value;
        }

        private static object CoerceMaximum(DependencyObject d, object baseValue)
        {
            numericUpDown n = d as numericUpDown;

            int value = (int)baseValue;

            return value;
        }

        private static object CoerceMininum(DependencyObject d, object baseValue)
        {
            numericUpDown n = d as numericUpDown;

            int value = (int)baseValue;

            return value;
        }          
    }
}

とりあえず、ボタンクリック時にも、判定してあげることで対処しました。(ついでに、最大値、最小値も依存プロパティー化)

1)バインド先からの値チェックにCoerceValueCallbackを使う
2)ユーザーコントロールの値の変化時にも値チェック処理を行う。

これでいいのかな?
2度同じ処理を行っているので、なんかもっとエレガントな方法がありそうですねー^^;

引用返信 編集キー/
■36420 / inTopicNo.3)  Re[2]: CoerceValueCallbackとBinding
□投稿者/ kazuto (9回)-(2009/05/28(Thu) 18:57:24)
kazuto さんの Web サイト
>1)ユーザーコントロールのボタンを押しbutton2_Clickを呼ぶ
>2)SetValue(ValueProperty, value)が実行される
>3)バインドされているDiceNumプロパティーに値が入る
>4)CoerceValueで検証

>上記の順番で実行されることを確認したのですが、
>3)と4)の順番が想定していたより逆なため、DiceNumプロパティーに値を渡した後に、CoerceValueでユーザーコントロールのValue値が修正されてしまいます。

それはTwoWayでのバインドを行っている為に、DiceNumプロパティに値が設定された事によるCoerceValueが働いているのではないでしょうか?
ちょっとコードをそのままコピー実装してみて気になったのですが、メインウィンドウでのDataContextってどのように設定されていますか?
TRPGData.DiceNumといきなり出てきたので詳細が良く分かりませんが、おそらくTRPGDataというデータクラスをメインウィンドウが持っていて、メインウィンドウ自身を「this.DataContext = this;」のようにしてらっしゃるかと思ってそのように実装して確認しました。

確認してみたらOnewayでのデータバインドが出来ないですね。
ちょっと自分も確認してみます。
引用返信 編集キー/
■36445 / inTopicNo.4)  CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (612回)-(2009/05/29(Fri) 04:31:38)
2009/05/29(Fri) 05:41:27 編集(投稿者)
2009/05/29(Fri) 05:41:14 編集(投稿者)

>TRPGData.DiceNumといきなり出てきたので詳細が良く分かりませんが、おそらくTRPGDataというデータクラスをメインウィンドウが持っていて、メインウィンドウ自身を「this.DataContext = this;」のようにしてらっしゃるかと思ってそのように実装して確認しました。

MVVMなので、

private void Application_Startup(object sender, StartupEventArgs e)
     {
         // ウィンドウとViewModelの初期化   
         var window = new Window1
         {
             DataContext = new TRPGViewModel()
         };
         window.Show();
     }   

こんな感じです。

public int DiceNum
{
    set
    {
       this.TRPGData.DiceNum = value;
    }
    get
    {                
        return this.TRPGData.DiceNum;
    }
}

TRPGViewModelがTRPGDataのインスタンスを所持しています。

>ちょっと自分も確認してみます。

どうもありがとうございます_(__)_



ところで、実験を行ってみました。

public int DiceNum
      {
          set
          {
              this.TRPGData.DiceNum = value;
              this.OnPropertyChanged("DiceNum");
          }
          get
          {                
              return this.TRPGData.DiceNum;
          }
      }

OnPropertyChangedを追加しました。

public static readonly DependencyProperty ValueProperty =
    DependencyProperty.Register("Value", typeof(int), typeof(numericUpDown), new FrameworkPropertyMetadata(0, (FrameworkPropertyMetadataOptions.BindsTwoWayByDefault), new PropertyChangedCallback(OnValuablePropertyChanged)));

テストのために、PropertyChangedCallbackだけにしてみました。



1)ボタンを押す
2)SetValue
3)バインド先でOnPropertyChanged
4)PropertyChangedCallback
6)SetValue
7)バインド先でOnPropertyChanged
8)こんどはPropertyChangedCallbackが呼ばれない。

互いに通知しあっているから、無限ループになるかなとおもったのですが、なぜか止まってくれました。

ここらあたりの実装方法これでいいのかな?

追記
あああ、なるほど、値が同じだったらPropertyChangedCallbackが呼ばれないんですね。

引用返信 編集キー/
■36446 / inTopicNo.5)  CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (613回)-(2009/05/29(Fri) 04:33:32)
2009/05/29(Fri) 06:54:26 編集(投稿者)

>それはTwoWayでのバインドを行っている為に、DiceNumプロパティに値が設定された事によるCoerceValueが働いているのではないでしょうか?

ユーザーコントロールで
SetValue→CoerceValueCallback(値が変わる)→PropertyChangedCallback

バインド先のDiceNumプロパティーに値を入れる→OnPropertyChanged→CoerceValueCallback→値が同じなのでPropertyChangedCallbackは呼ばれない

2時間ぐらいテストしてみましたが、いまのところ上記のように動いている気がします。
まだ、完全に自信ないです^^;間違えているかも

おかしいな〜と思うのは
1)SetValue実行
2)バインド先に値を渡す
3)CoerceValueCallbackが呼び出される。値が変わるとバインド先と自分の値が違う

2)と3)の順番は逆のほうがいいのではと思いました。
SetValue前に値のチェックをしてあげればいいだけですが。


引用返信 編集キー/
■36448 / inTopicNo.6)  Re[5]: CoerceValueCallbackとBinding
□投稿者/ Hongliang (402回)-(2009/05/29(Fri) 07:13:00)
// 丸一日私の蒙を啓いてくれるようなレスがなかったので適当に放言。

どうにも仕様バグっぽい動きですね。むしろフィードバックに投げてみるべきかも。

> だったら、CoerceValueCallbackつかわずに。
> SetValueを呼ぶ、Valueプロパティー内で値のチェックした方が一発ですむ気がします。

CoerceValueCallback は単に値を強制するだけの機能ではなく、強制前の値を内部に保持しておく機能もあります。
Max/Min/Value パターンなんかで顕著ですが、たとえば Max = 10 のときに Value = 20 とすると Value の CoerceValueCallback によって Value は 10 が強制されますが、その後 Max を 30 に変更し Max の PropertyChangedCallback で Value を CoerceValue すれば、自動的に Value は設定した値である 20 に戻されます。
ので、単純な値チェックとは別物なんですね。まあ自前で PropertyChangedCallback にそういうコードを書こうと思ったら書けるわけですが。
また双方向バインディングでは当然ながらバインディングソースからの設定に対して CLR プロパティでの値チェックは無力です。直接 SetValue が呼び出されますからね。そもそも SetValue と DependencyProperty は public ですから、バインディングに限らず誰でも直接 SetValue 可能ですし。
バインディング設定時に PropertyChangedCallback で Value を書き換えてもバインディングソースに通知されないみたい、ってのはなにか見落としてる?
いずれにせよ、依存関係プロパティを PropertyChangedCallback / CoerceValueCallback で再設定した場合バインディングのソース・ターゲット間で不整合が起こる場面があるみたい。
自分自身で完結できなくなるけれど、CoerceValueCallback 内でイベントを発生させて強制後の値を通知し、そこでバインディングソースの方の値を修正する、辺りが落としどころかしらん。
// 単純なバインディングなら CoerceValueCallback 内で直接バインディングソースの値書き換えもできるけど、複雑なバインディングになったとき対応できるかどうか。

まあ汎用性を考えなくていいのならどうでもいい話ですが。
引用返信 編集キー/
■36449 / inTopicNo.7)  Re[5]: CoerceValueCallbackとBinding
□投稿者/ 囚人 (365回)-(2009/05/29(Fri) 07:19:34)
>SetValueを呼ぶ、Valueプロパティー内で値のチェックした方が一発ですむ気がします

たぶん、これまでに誰かに言われた記憶があると思いますが、CLR プロパティラッパーで SetValue と GetValue 以外の事はしないほうが良いです。

CLR プロパティラッパーが使われるのはラッパーを使ったときだけ(要するに C# のコードで使ったとき)で、XAML で使ったときは DependencyProperty が使われるので、CLR プロパティは無視されます(つか、DependencyProperty という時点で CLR プロパティラッパーは殆ど使われない)。

それでも、普通は SetValue と GetValue 以外の処理を入れたいので、何種類もコールバックがあるわけです。

検証したいなら、検証コールバックは、FrameworkPropertyMetadate の最後の引数(CoreceValueCallback)ではなく、Dependency.Register に指定するものでは? CoreceValueCallback は文字通り、値を強制するものです。

で、ドキュメントにも書いてありますけど、強制された値は「強制前」の値を保持していて(たぶん、強制前の値とデータソースの値は一致するはず)、強制が解除されれば、強制前の値に近づこうとします。
今回の例で言えば、Value = 10、Maximum = 3、Minimau = 0 なら Value は 3 に強制されるわけですよね。で、この後、仮に Maximum が 11 になったら Value は 10 になるわけです(Value に一切触れずとも)。

この辺の概念は小難しいので、私も理解しているか自信ありません。
引用返信 編集キー/
■36450 / inTopicNo.8)  Re[6]: CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (614回)-(2009/05/29(Fri) 07:53:37)
Hongliangさんお返事ありがとうございます。XAMlのBinding周りの動きは正直難しいですー

>CoerceValueCallback は単に値を強制するだけの機能ではなく、強制前の値を内部に保持しておく機能もあります。
>Max/Min/Value パターンなんかで顕著ですが、たとえば Max = 10 のときに Value = 20 とすると Value の CoerceValueCallback によって Value は 10 が強制されますが、その後 Max を 30 に変更し Max の PropertyChangedCallback で Value を CoerceValue すれば、自動的に Value は設定した値である 20 に戻されます。

うわー、なんですとー。

>Value を CoerceValue すれば、自動的に Value は設定した値である 20 に戻されます。

すいません、実際のコードはどうなるんでしょう?
private static void OnMaximumPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
numericUpDown n = d as numericUpDown;

  //CoerceValue??
}

>また双方向バインディングでは当然ながらバインディングソースからの設定に対して CLR プロパティでの値チェックは無力です。直接 SetValue が呼び出されますからね。

いやー、これ今日の朝ようやく理解しました^^;ああ、直接SetValueが呼ばれるんだなと。

>いずれにせよ、依存関係プロパティを PropertyChangedCallback / CoerceValueCallback で再設定した場合バインディングのソース・ターゲット間で不整合が起こる場面があるみたい。
>どうにも仕様バグっぽい動きですね。むしろフィードバックに投げてみるべきかも。

なるほど、了解しました。
フィードバックとはMSDNのフォーラムでしょうか?




囚人さん、お返事ありがとうございます。

>たぶん、これまでに誰かに言われた記憶があると思いますが、CLR プロパティラッパーで SetValue と GetValue 以外の事はしないほうが良いです。

はい、了解しました。

>今回の例で言えば、Value = 10、Maximum = 3、Minimau = 0 なら Value は 3 に強制されるわけですよね。で、この後、仮に Maximum が 11 になったら Value は 10 になるわけです(Value に一切触れずとも)。

これが一番びっくりしました。
DependencyProperty.Register("Value", typeof(int)...

ここで設定した同じ方の型の値をCoerceValueCallbackが別に保持しているんですね。

>検証したいなら、検証コールバックは、FrameworkPropertyMetadate の最後の引数(CoreceValueCallback)ではなく、Dependency.Register に指定するものでは? CoreceValueCallback は文字通り、値を強制するものです。

申し訳ない、検索してもわかりませんでした。どのような物か教えていただけると幸いです。
引用返信 編集キー/
■36471 / inTopicNo.9)  Re[7]: CoerceValueCallbackとBinding
□投稿者/ Hongliang (403回)-(2009/05/29(Fri) 12:43:49)
> >Value を CoerceValue すれば、自動的に Value は設定した値である 20 に戻されます。
>
> すいません、実際のコードはどうなるんでしょう?
大本の基底クラス DependencyObject にそのもののメソッドがあります。

> フィードバックとはMSDNのフォーラムでしょうか?
それもあり。
でもどっちかというとフィードバックセンターの方。
https://connect.microsoft.com/VisualStudioJapan


> >検証したいなら、検証コールバックは、FrameworkPropertyMetadate の最後の引数(CoreceValueCallback)ではなく、Dependency.Register に指定するものでは? CoreceValueCallback は文字通り、値を強制するものです。
>
> 申し訳ない、検索してもわかりませんでした。どのような物か教えていただけると幸いです。

Register の第五引数に指定する ValidateValueCallback のことでしょう。
でも残念ながら、このコールバックは静的な判断しかできない(コールバック引数に DependencyObject インスタンスが与えられない)ので、Min/Max/Value パターンの検証には使えません。Value の検証時に「現在の Max」が取得できないので。
引用返信 編集キー/
■36472 / inTopicNo.10)  Re[8]: CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (615回)-(2009/05/29(Fri) 12:55:32)
Hongliangさん、お返事ありがとうございます。

>大本の基底クラス DependencyObject にそのもののメソッドがあります。

うほ!ほんまや!びっくりしました。

d.CoerceValue(ValueProperty);
こんな感じかなー

>でもどっちかというとフィードバックセンターの方。
>https://connect.microsoft.com/VisualStudioJapan

どうもありがとうございますー
でも、僕が思ったぐらいですから、すでに誰か取り上げてないのかな?

>Register の第五引数に指定する ValidateValueCallback のことでしょう。

なるほど。了解しました。

>でも残念ながら、このコールバックは静的な判断しかできない(コールバック引数に >DependencyObject インスタンスが与えられない)ので、Min/Max/Value パターンの検証に>は使えません。Value の検証時に「現在の Max」が取得できないので。

以前、試そうとして、あれインスタンスがないやん、staticやから参照できんやん、と悩んだことが。
で、CoerceValueCallbackに実装して現在にいたります^^;
引用返信 編集キー/
■36604 / inTopicNo.11)  Re[9]: CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (619回)-(2009/06/02(Tue) 15:06:42)
えウナウさんが、記事にしてくれたんですが、
http://blogs.wankuma.com/mnow/archive/2009/06/02/174000.aspx

Sliderコントロールはちゃんと動くぞーとのことなんですが、
自分で実装するときはどういう実装をすればいいんでしょうね?
非常に知りたいですー
引用返信 編集キー/
■36630 / inTopicNo.12)  Re[10]: CoerceValueCallbackとBinding
□投稿者/ えムナウ (2回)-(2009/06/02(Tue) 19:20:35)
えムナウ さんの Web サイト
以下の状態での結果はどうですか?
set
{
 if (this.TRPGData.DiceNum != value) {
  this.TRPGData.DiceNum = value;
  this.OnPropertyChanged("DiceNum");
 }
}

引用返信 編集キー/
■36635 / inTopicNo.13)  Re[11]: CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (621回)-(2009/06/02(Tue) 20:22:42)
どうも、お返事ありがとうございます。
試しましたが、値が同じ時はOnPropertyChangedを呼ばないんですよね?結果があまりかわらなかったのですが、何か違うのかな。

ユーザーコントロールのSetValue→CoerceValue(値が変わるときがある)→OnValuablePropertyChanged

プロパティーに値の変更

この流れが、やはり問題に思えます。
Sliderとかはどのような処理を追加しているんでしょうね?

引用返信 編集キー/
■36637 / inTopicNo.14)  Re[12]: CoerceValueCallbackとBinding
□投稿者/ えムナウ (3回)-(2009/06/02(Tue) 20:50:08)
えムナウ さんの Web サイト
いや、 numericUpDown 自体は動作してますよ。
MVVM側が悪いんじゃないですか?

どんなデバッグメッセージになっています?
http://blogs.wankuma.com/mnow/archive/2009/06/02/174000.aspx
http://blogs.wankuma.com/mnow/archive/2009/05/29/173815.aspx
引用返信 編集キー/
■36639 / inTopicNo.15)  CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (623回)-(2009/06/02(Tue) 21:05:06)
2009/06/02(Tue) 21:13:08 編集(投稿者)
2009/06/02(Tue) 21:12:54 編集(投稿者)

 private void button1_Click(object sender, RoutedEventArgs e)
        {
            if (Value < this.Maximum)
            {
                Value++;
            }
            else
            {
                Value = this.Maximum;
            }
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {            
            if (Value > this.Mininum)
            {
                Value--;                
            }
            else
            {
                Value = this.Mininum;
            }
        }

これを 
   private void button1_Click(object sender, RoutedEventArgs e)
        {
                Value++;
        }

        private void button2_Click(object sender, RoutedEventArgs e)
        {            
                Value--;                
        }
CoerceValueを動かすために上記に変更しました。
ユーザーコントロールの値は1で、button2_Clickイベントを起こしました。

System.Windows.Data Warning: 86 : BindingExpression (hash=40644060): Update - got raw value '0'
System.Windows.Data Warning: 90 : BindingExpression (hash=40644060): Update - using final value '0'
System.Windows.Data Warning: 98 : BindingExpression (hash=40644060): SetValue at level 0 to TRPGViewModel (hash=60223214) using RuntimePropertyInfo(DiceNum): '0'
System.Windows.Data Warning: 91 : BindingExpression (hash=40644060): Got PropertyChanged event from TRPGViewModel (hash=60223214)

プロパティー側は0ですが、CoerceValueが働いているためにユーザーコントロールは1になっています。

引用返信 編集キー/
■36641 / inTopicNo.16)  Re[13]: CoerceValueCallbackとBinding
□投稿者/ えムナウ (4回)-(2009/06/02(Tue) 21:18:33)
えムナウ さんの Web サイト
訂正です。
直接 Value を Bind した場合は CoerceValue 前のデータが入りました。
この動作は Slider も同じです。

引用返信 編集キー/
■36642 / inTopicNo.17)  Re[14]: CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (625回)-(2009/06/02(Tue) 21:29:55)
お返事ありがとうございます。

あれ、どうやって、えムナウさんバインドしていたかな。えムナウさんのソース見るか。ちょっと今日はぎぶあっぷさせてくださいw
引用返信 編集キー/
■36644 / inTopicNo.18)  Re[15]: CoerceValueCallbackとBinding
□投稿者/ Hongliang (408回)-(2009/06/02(Tue) 21:58:17)
CoerceValueCallbackについて
・バインディングソースにCoerceValueCallbackが設定されている
<Slider x:Name="slider"/>
<TextBox Text="{Binding ElementName=slider, Path=Value, Mode=TwoWay}"/>
 ターゲット(TextBox.Text)には強制後の値が格納される。
 ただし、一度ターゲットの変更によって強制された後、さらにソースの値が変わらないようにターゲットを変更した場合、ターゲットの値は強制されない値のまま(つまり入力値そのまま)

・バインディングターゲットにCoerceValueCallbackが設定されている
<Slider Value="{Binding ElementName=textbox, Path=Text, Mode=TwoWay}"/>
<TextBox x:Name="textbox"/>
 ソース(TextBox.Text)には常に強制前の値が格納される。

こんな感じですか。
まあソースとターゲットが両方依存関係プロパティで、双方の CoearceValueCallback が矛盾していたらと考えると仕方のない面もあるかも。
でも直感的じゃないっすね。
引用返信 編集キー/
■36691 / inTopicNo.19)  Re[16]: CoerceValueCallbackとBinding
□投稿者/ 倉田 有大 (626回)-(2009/06/03(Wed) 20:12:47)
Hongliangさん、お返事ありがとうございます。

まだ、ここらあたりの動作がむずかしいですね。理解できていません。
特にコントロールの例だと、どちらも依存プロパティーになりますのでCoearceValueCallbackがどっちも働いたりすると^^;
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -