あまり必要性はないと思うけど、実際のXamlコードをアクティブに参照してみたいなぁと思ったのでやってみる。
今回はButtonの実際のXamlコードを取得してみます。
まずはButtonを2つ設置し、CommandParameterに表示したいButtonを渡します。
コードビハインドで書けばClickイベントでsenderとして飛んでくるわけですが、MVVMで書くためにひと手間かけています。
<Window.Resources>
<Style TargetType="Button" x:Key="fuga">
<Setter Property="Background" Value="Beige"/>
</Style>
</Window.Resources>
<DockPane>
<Button Name="hoge" Content="hoge" Width="100" Height="50" Style="{StaticResource fuga}" />
<Button Command="{Binding TestCommand}" CommandParameter="{Binding ElementName=hoge}" Content="Write" Width="100" Height="50" />
</DockPane>
なぜ表示するためのボタンと表示されるボタンを分けたのかというと、
1つはReactiveCommandがシリアライズできないため。
もう1つは、CommandParameter=”{Binding RelactiveSrouce={RelativeSource Self} }”と書いてしまうと、循環参照となりStackOverflowExceptionが出てしまうからです。
ViewModelはこれだけです。
ReactiveCommandを使っているのでTestButtonClickをsubscribeしています。
public MainWindowViewModel()
{
this.TestCommand = new ReactiveCommand<object>().WithSubscribe(WriteButtonClick);
}
public void WriteButtonClick(object sender)
{
var button = (System.Windows.Controls.Button)sender;
var xamlString = XamlWriter.Save(button);
MessageBox.Show("XAML code:" + "\n\n" + xamlString);
}
実際に実行すると出てきたコードがこちら。
このままだと1行で書かれているため非常に読みにくいです。
XDocumentを使って成形します。
使い方は簡単で、Stringを一旦XDocument型に変換してstringに再変換するだけです。
using System.Xml.Linq;
public void WriteButtonClick(object sender)
{
var button= (System.Windows.Controls.Button)sender;
var xamlString = XamlWriter.Save(button);
xamlString = FormatXml(xamlString);
MessageBox.Show("XAML code:" + "\n\n" + xamlString);
}
private string FormatXml(String xml)
{
try
{
XDocument x = XDocument.Parse(xml);
return x.ToString();
}
catch (Exception)
{
return xml;
}
}
自作したコントロールのXaml辞書的に使えないかなぁと思ってやってみたのですが、
実際に出力されるxamlがソース上のコードとかけ離れているのでこれをそのまま使うのは辛い。
直接sourceファイルにアクセスした方が綺麗で速い気がしてきた。
コメント