【ReactiveProperty】ReactiveCommandでCanExecuteがtrueにならない
Q&A
Closed
お世話になっております。
解決したいこと
C# + WPFでベクターグラフィックスドローイングツールを開発しています。
※下にソースコードへの案内を記載しております。よろしければそちらを参照ください。
発生している問題・エラー
このツールに設定画面を実装しているところです。設定画面ではキャンパスの幅や高さ、ポイントにスナップするかどうかを設定できます。
その設定画面のSettingViewModel.csでReactivePropertyを使っております。OKボタンを押下できる条件は「キャンパスの幅と高さが乗算して0より大きくなったらOKボタンを押せるようにする」としたいのですが、ReactiveCommandの正しい書き方がわからず、立ち尽くしております。
ソースコード
boiler's Graphics
https://github.com/dhq-boiler/boiler-s-Graphics
gitリポジトリ
https://github.com/dhq-boiler/boiler-s-Graphics.git
ブランチ:develop
コミット:577fa7b
自分で試したこと
CombineLatest()でEditTargetのWidthとHeightを乗算して合体させてから、Select()で0より大きい時trueを返すように書きましたが、下記のGIF画像のように、OKボタンのCanExecuteがfalseになってしまっているようです。
class SettingViewModel : BindableBase, IDialogAware, IDisposable
{
private bool disposedValue;
private CompositeDisposable _disposables = new CompositeDisposable();
public ReactiveCommand OkCommand { get; set; }
public ReactiveCommand CancelCommand { get; set; }
public ReactiveProperty<Models.Setting> EditTarget { get; set; } = new ReactiveProperty<Setting>();
public SettingViewModel()
{
EditTarget.Value = new Setting();
CancelCommand = new ReactiveCommand();
OkCommand = EditTarget.Value
.Width
.CombineLatest(EditTarget.Value.Height, (x, y) => x * y)
.Select(x => x > 0)
.ToReactiveCommand();
OkCommand.Subscribe(_ =>
{
var parameters = new DialogParameters() { { "Setting", EditTarget.Value } };
var ret = new DialogResult(ButtonResult.OK, parameters);
RequestClose.Invoke(ret);
})
.AddTo(_disposables);
CancelCommand.Subscribe(_ =>
{
var ret = new DialogResult(ButtonResult.Cancel, null);
RequestClose.Invoke(ret);
})
.AddTo(_disposables);
}
public string Title => "設定";
public event Action<IDialogResult> RequestClose;
public bool CanCloseDialog()
{
return true;
}
public void OnDialogClosed()
{
}
public void OnDialogOpened(IDialogParameters parameters)
{
EditTarget.Value = parameters.GetValue<Models.Setting>("Setting");
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
_disposables.Dispose();
}
_disposables = null;
disposedValue = true;
}
}
public void Dispose()
{
// このコードを変更しないでください。クリーンアップ コードを 'Dispose(bool disposing)' メソッドに記述します
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
<UserControl x:Class="boilersGraphics.Views.Setting"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:boilersGraphics.Views"
xmlns:converter="clr-namespace:boilersGraphics.Converters"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<converter:IntToStringConverter x:Key="IntToStringConverter" />
</UserControl.Resources>
<DockPanel>
<StackPanel DockPanel.Dock="Bottom"
HorizontalAlignment="Right"
Orientation="Horizontal">
<Button Command="{Binding OkCommand}"
Width="100"
Height="25"
Margin="5">OK</Button>
<Button Command="{Binding CancelCommand}"
Width="100"
Height="25"
Margin="5">キャンセル</Button>
</StackPanel>
<StackPanel Orientation="Vertical">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Grid.Column="0">キャンパスの幅</Label>
<TextBox Grid.Row="0"
Grid.Column="1"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Right"
Text="{Binding EditTarget.Value.Width.Value, Converter={StaticResource IntToStringConverter}}" />
<Label Grid.Row="1"
Grid.Column="0">キャンパスの高さ</Label>
<TextBox Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Right"
Text="{Binding EditTarget.Value.Height.Value, Converter={StaticResource IntToStringConverter}}" />
<CheckBox Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="2"
x:Name="enablePointSnap"
Margin="5"
IsChecked="{Binding EditTarget.Value.EnablePointSnap.Value}">ポイントにスナップする</CheckBox>
<Label Grid.Row="3"
Grid.Column="0">ポイントにスナップする範囲</Label>
<TextBox Grid.Row="3"
Grid.Column="1"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Right"
Text="{Binding EditTarget.Value.SnapPower.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=enablePointSnap, Path=IsChecked}" Value="True">
<Setter Property="IsReadOnly" Value="False" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=enablePointSnap, Path=IsChecked}" Value="False">
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="Foreground" Value="Gray" />
<Setter Property="BorderBrush" Value="Gray" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
<StackPanel Orientation="Horizontal">
</StackPanel>
<StackPanel Orientation="Horizontal">
</StackPanel>
</StackPanel>
</DockPanel>
</UserControl>
何か私の見落とし、致命的な勘違いなど気づいたところがあれば、回答していただけると助かります。よろしくお願いいたします。