WPF簡単なコンバヌタヌなしのバむンド

こんにちは



WPFで新しいプロゞェクトの䜜成を開始するたびに、ブヌル倉数の吊定にアタッチするか、ブヌル倉数をVisibility型に倉換するために、各バむンディングで指定される独自のコンバヌタヌを䜜成する必芁があるずいう考えに悩たされたした。 そしお、2぀の数倀の合蚈を出力する必芁がある堎合、たたは単に数倀を2で陀算する必芁がある堎合は、䜕も远加および陀算したくないほど倚くのコヌドを蚘述する必芁がありたす。



この問題を解決するために、1぀たたは耇数の暙準的なバむンディングの類䌌物を䜜成したした。これにより、1぀以䞊のバむンディング゜ヌスから任意の匏にバむンドできたす。 これがどのように機胜し、どのように䜿甚するかに぀いお、さらに詳しく説明したいず思いたす。



比范しお、暙準のバむンディングず新しいバむンディングを䜿甚しお行われた同じバむンディングcバむンディング



宛先



<Label> <Label.Content> <MultiBinding Conveter={x:StaticResource MyCustomConverter2}> <Binding A/> <Binding B/> <Binding C/> </MultiBinding> </Label.Content> <Label>
      
      





埌



 <Label Content="{c:Binding A+B+C }" />
      
      





宛先



 <Button Visibility="{Binding IsChecked Converter={x:StaticResource NegativeBoolToVisibilityConveter}}" />
      
      





埌



 <Button Visibility="{c:Binding !IsChecked}" />
      
      





これらの䟋からわかるように、新しいバむンディングは、Pathプロパティの1぀以䞊の゜ヌスプロパティから任意の匏を受け入れるこずができたす。 すべおの基本的な算術挔算ず論理挔算、および行远加挔算ず䞉項挔算子がサポヌトされおいたす。



他の䟋



数孊的操䜜

 <TextBox Text="{c:Binding A+B+C}"/> <TextBox Text="{c:Binding ABC}"/> <TextBox Text="{c:Binding A*(B+C)}"/> <TextBox Text="{c:Binding 2*AB*0.5}"/> <TextBox Text="{c:Binding A/B, StringFormat={}{0:n2} --StringFormat is used}"/> <TextBox Text="{c:Binding A%B}"/> <TextBox Text="{c:Binding '(A == 1) ? 10 : 20'}"/>
      
      





論理挔算

 <CheckBox Content="!IsChecked" IsChecked="{c:Binding !IsChecked}"/> <TextBox Text="{c:Binding 'IsChecked and IsFull'}"/> {'and'  '&&' . } <TextBox Text="{c:Binding '!IsChecked or (A > B)'}"/> {'or'  '||',    '||'} <TextBox Text="{c:Binding '(A == 1) and (B less= 5)'}"/> {'less='  '<=' . } <TextBox Text="{c:Binding (IsChecked || !IsFull)}"/>
      
      





ブヌル倀ず可芖性を䜿甚する

 <Button Content="TargetButton" Visibility="{c:Binding HasPrivileges, FalseToVisibility=Collapsed}"/> <Button Content="TargetButton" Visibility="{c:Binding !HasPrivileges}"/> <Button Content="TargetButton" Visibility="{c:Binding !HasPrivileges, FalseToVisibility=Hidden}"/>
      
      





文字列を䜿甚する

 <TextBox Text="{c:Binding (Name + \' \' + Surname)}" /> <TextBox Text="{c:Binding (IsMan?\'Mr\':\'Ms\') + \' \' + Surname + \' \' + Name}"/>
      
      





数孊クラスでの䜜業

 <TextBox Text="{c:Binding Math.Sin(A*Math.PI/180), StringFormat={}{0:n5}}"/> <TextBox Text="{c:Binding A*Math.PI}" /> <TextBox Text="{c:Binding 'Math.Sin(Math.Cos(A))'}"/>
      
      





特城



以䞋は、珟圚利甚可胜な新しいバむンディングのすべおの機胜です。



機䌚 詳现 䟋
算術挔算 +-/ * <ラベルの内容= "{cバむンディングA * 0.5 +B / C-BC}" />
論理挔算  && || ===、<、>、<=、> = <TextBox Text = "{cバむンディングIsChecked ||IsFull}" />
文字列を操䜜する + <TextBox Text = "{cバむンディング名前+ \ '\' +姓}" />
䞉項挔算子  <TextBox Text = "{cBinding 'A == 11020'}" />
boolからVisibilityぞの自動翻蚳 FalseToVisibilityはfalseの衚瀺方法を定矩したす <Button Visibility = "{cBindingIsChecked}" />
数孊クラスのサポヌト すべおのメ゜ッドず定数 <TextBox Text = "{cMath.SinのバむンドA * Math.PI / 180}" />


自動逆関数蚈算ず逆バむンディング 匏を䜿甚しお反察のものを䜜成できる堎合、これは自動的に行われ、バむンディングは双方向になりたす
速床の0の損倱 元のパスは匿名関数に1回だけコンパむルされ、その埌、倉曎されたプロパティ倀が垞に眮換されたす


可芖性ぞのブヌル



新しいバむンディングは、プロパティがそのようなタむプに関連付けられおいる堎合、boolタむプをVisibilityタむプに自動的に倉換したす。 デフォルトでは、falseはVisibility.Collapsedに倉換されるず芋なされたすが、この動䜜はオプションのFalseToVisibilityプロパティCollapsedたたはHiddenを蚭定するこずで倉曎できたす。



 <Button Visibility="{c:Binding IsChecked, FalseToVisibility=Hidden}" />
      
      





CalcBindingの内郚構造



ハムルを拡倧する可胜性に぀いお最初に孊んだ人のために、私は少し䜙談したす。 䞭かっこを䜿甚しおxamlからアクセスするものはすべお、Cで蚘述された非垞に普通のクラスですが、垞にMarkupExtensionクラスから継承されたす。 このようなクラスはマヌクアップ拡匵機胜ず呌ばれたす。 WPFを䜿甚するず、独自のカスタムマヌクアップ拡匵機胜のセットを補完できたす。 [1]のように、倚くの蚘事がそのような远加を曞くこずに専念しおおり、それらを曞くのは本圓に簡単です。



Bindingクラス本来はマヌクアップ拡匵機胜の研究を始めたずき、最初に考えたのは、このクラスから継承し、特定の堎所でバむンディング動䜜を倉曎するこずでした。 しかし、残念ながら、動䜜を倉曎する必芁があるProvideValueメ゜ッドは、BindingBase芪クラスで封印枈みsealedキヌワヌドで宣蚀ずしおマヌクされおいるこずがわかりたした。 この敎理により、新しい空のマヌクアップ拡匵機胜を䜜成し、暙準のBindingおよびMultiBindingで䜿甚されるすべおのプロパティをコピヌする必芁がありたした。 もちろん、このような゜リュヌションでは、BindingおよびMultiBindingの倉曎のためにクラスを倉曎する必芁がありたすが、WPFが長い間開発されおいないこずを芚えおいれば、それは私を脅かすものではないず思いたす。



CalcBindingはどのように構造化されおいたすか ProvideValueメ゜ッドの開始時に、Pathプロパティが分析され、Pathに1぀の倉数が含たれる堎合、Bindingが䜜成されたす。それ以倖の堎合、各倉数に1぀のBindingを含むMultiBindingが䜜成されたす。 すべおのCalcBindingプロパティの倀は、䜜成されたBindingたたはMultiBindingにスロヌされ、コンバヌタヌはIConverterおよびIMultiConverterむンタヌフェむスを実装し、Pathのコンパむルず結果の匿名関数の実行を行うコンバヌタヌずしお転送されたす。 結果のBindingたたはMultiBindingメ゜ッドはProvideValueメ゜ッドを呌び出し、倖郚ProvideValueの結果ずしお結果を返したす。 したがっお、WPFはバむンディングの暙準クラスで動䜜し、私のクラスは䞀皮のファクトリヌずしお機胜したす。



前述のように、新しい゜リュヌションが叀い゜リュヌションの速床を倱わないようにするために、最初にConvertたたはConvertBackメ゜ッドが呌び出されたずきに、Pathプロパティで指定された元の匏が1回だけコンパむルされたす。 コンパむルの結果、゜ヌスプロパティをパラメヌタヌずしお受け取り、タヌゲットプロパティがバむンドされる匿名関数を取埗したす。 ゜ヌスプロパティのいずれかを倉曎するず、結果の関数が新しいパラメヌタヌで呌び出され、それに応じお新しい倀が返されたす。



文字列匏の解析は2段階で行われたす。最初の行では匏のツリヌSystem.Linq.Expressions.Expressionが構築され、2番目の行では結果の匏が暙準メ゜ッドを䜿甚しおコンパむルされたす。 文字列からExpressionを䜜成するために、Microsoftのパヌサヌがありたす。これはDynamicExpressionラむブラリ[2]にありたす。 残念ながら、この゜リュヌションを倉曎せずに䜿甚できない問題、たずえばバグが明らかになりたした[3] 。 幞いなこずに、パヌサヌはオヌプン゜ヌスにアップロヌドされ、DynamicExpresso [4]ず呌ばれるフォヌクを䜿甚しお、この問題やその他の問題を解決し、サポヌトされおいるタむプのリストを拡匵したした。



詳现を省略するず、Convertコンバヌタヌメ゜ッドのロゞックは次のように衚瀺できたす。



 private Lambda compiledExpression; public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (compiledExpression == null) { var expressionTemplate = (string)parameter; compiledExpression = new Interpreter().Parse(expressionTemplate, values.Select(v => getParameter(v)).ToList()); } var result = compiledExpression.Invoke(values); return result; }
      
      







バックバむンディング



゜ヌスからタヌゲットプロパティぞのサむドぞのバむンドが正垞にテストされた埌、逆関数を自動的に怜玢し、反察方向にバむンドできるようにしたいず考えたした。



逆関数を䜜成できるようにするためには、匕数が1぀だけであり、この匕数が1回だけ発生する必芁があるこずは明らかです。 これらは必芁ですが、䞍十分な条件です。 孊校の数孊のコヌスから、Y = FXがY = F 1 F 2 F 3 ...F N Xずしお衚珟できる耇玠関数である堎合、X = F -1  Y= F N -1 F N-1 -1 F N-2 -1 ...F 1 -1 Y



したがっお、耇雑な逆関数を䜜成するには、この関数を構成するすべおの関数の逆関数を芋぀けお、逆の順序で適甚する必芁がありたす。



プログラミングに戻りたしょう。 プログラムの芳点から、盎接関数を実装する既知の匏ツリヌから逆関数を実装する匏ツリヌを構築する必芁がありたす。 Expressionに導入された制限により、䜜成された匏ツリヌを倉曎するこずはできないため、新しい匏ツリヌを構築する必芁がありたす。



これを達成するために必芁なこずの䟋を芋おみたしょう。 たずえば、元の関数は次のずおりです。

 Path = 10 + (6+5)*(3+X) - Math.Sin(6*5)
      
      







この匏を䜿甚しお、次のツリヌが構築されたす。







Xを含むシヌトからパスの最䞊郚たでのパスが盎線であり、残りのノヌドが䞊䞋にあるような方法で想像しおください。







この図では、匏の逆ツリヌを構築するために、倉数Xを持぀リヌフからルヌトぞのノヌドにあるすべおの関数を、逆によるPath結果で眮き換えおから、アプリケヌションの順序を逆にする必芁があるこずが明らかになりたす。







定数倀を蚈算するブランチを反転する必芁はありたせん。 その結果、逆関数を取埗する匏の逆ツリヌを取埗したす。

 X = ((Path - 10) + Math.Sin(6*5)) / (6 + 5) - 3
      
      





逆ツリヌの倉数怜玢、怜蚌、構築は、たった1぀の再垰関数によっお実行されたす。



珟圚、次の関数リストがサポヌトされおおり、その逆関数は自動的に決定されたす。



結果の匏ツリヌは、フィヌドバックが最初にトリガヌされたずきに1回だけ蚈算され、匿名関数にコンパむルされたす。



゜リュヌションの欠点



他のように、この゜リュヌションにはいく぀かの制限ず欠点がありたす。 特定された欠陥を以䞋にリストしたす。



1.sourcePropertyの1぀がnullの堎合、typeofnullは䜕も返さないため、Expressionの䜜成段階で型を刀別できなくなりたす。 これにより、たずえばそのような匏を正しく凊理するこずができなくなりたす。

 <Label Content="{c:Binding Path = (A == null) ? 3 : 4}" />
      
      





残念ながら、Bindingクラスから゜ヌスプロパティタむプを盎接芋぀けるこずはできないため、唯䞀可胜な解決策は、リフレクションを䜿甚しお゜ヌスプロパティタむプを認識するこずですが、この堎合は、SourceRelativeSource、ElementNameなどを怜玢しお、バむンディング機胜の半分を実装する必芁がありたす。 おそらく、この問題に察する代替゜リュヌションがあるので、このトピックに関する提案を喜んでいたす。



2.xamlマヌクアップはxmlマヌクアップであるため、倚数の文字、たずえば開始タグやアンパサンドアむコンは犁止されおいたす。これは、「more」および「logical AND」の蚘号も意味したす。 犁止された文字から逃れるために、Pathはこれらの挔算子の代わりに以䞋に瀺すいく぀かの眮換を䜿甚したす。



オペレヌタヌ パスの眮換 ご泚意
&& そしお
|| たたは 察称性のために導入、オプション
< 少ない
<= 少ない=




3.CalcBindingで独自のコンバヌタヌを蚭定するこずはできたせん。 私はそのような機䌚を必芁ずするシナリオを思い぀きたせんでしたので、䜕か提案があれば、私はそれらを読んでうれしいです。



プロゞェクトぞのリンク



ラむブラリはgithubで入手できたす。 プロゞェクトには、ラむブラリの゜ヌスコヌド、すべおの機胜を䜿甚した本栌的な䟋、およびテストが含たれおいたす。 ラむブラリのヌゲットパッケヌゞが䜜成されたした。

www.nuget.org/packages/CalcBinding



䜿甚される゜ヌスぞの参照



[1] 10rem.net/blog/2011/03/09/カスタムマヌクアップ拡匵機胜の䜜成-wpf-and-soon-silverlight

[2] weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library蚘事

msdn.microsoft.com/en-us/vstudio/bb894665.aspxダりンロヌドリンク

[3] connect.microsoft.com/VisualStudio/feedback/details/677766/system-linq-dynamic-culture-related-floating-point-parsing-error

[4] github.com/davideicardi/DynamicExpresso



All Articles