web-dev-qa-db-ja.com

WPFで逆ブール値プロパティをバインドする方法

私が持っているのはIsReadOnlyプロパティを持つオブジェクトです。このプロパティがtrueの場合、ButtonのIsEnabledプロパティを(たとえば)falseに設定します。

私はIsEnabled="{Binding Path=!IsReadOnly}"と同じくらい簡単にそれができると信じたいのですが、それはWPFで飛ぶわけではありません。

私はすべてのスタイル設定を通過しなければならなかったことに追いやられましたか?あるブールを別のブールの逆に設定するのと同じくらい単純なことには、あまりにも表現が複雑すぎるようです。

<Button.Style>
    <Style TargetType="{x:Type Button}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding Path=IsReadOnly}" Value="True">
                <Setter Property="IsEnabled" Value="False" />
            </DataTrigger>
            <DataTrigger Binding="{Binding Path=IsReadOnly}" Value="False">
                <Setter Property="IsEnabled" Value="True" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Button.Style>
335
Russ

あなたはあなたのためにboolプロパティを逆にするValueConverterを使うことができます。

XAML:

IsEnabled="{Binding Path=IsReadOnly, Converter={StaticResource InverseBooleanConverter}}"

コンバータ:

[ValueConversion(typeof(bool), typeof(bool))]
    public class InverseBooleanConverter: IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            if (targetType != typeof(bool))
                throw new InvalidOperationException("The target must be a boolean");

            return !(bool)value;
        }

        public object ConvertBack(object value, Type targetType, object parameter,
            System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException();
        }

        #endregion
    }
436
Chris Nicol

IsNotReadOnlyプロパティを検討しましたか?バインドされているオブジェクトがMVVMドメイン内のViewModelである場合は、追加のプロパティが最適です。それが直接のEntityモデルであれば、あなたは構成し、あなたのエンティティの特殊なViewModelをフォームに提示することを検討するかもしれません。

94
Paul Alexander

標準バインディングでは、少し風が強いようなコンバータを使用する必要があります。だから、私はあなたが私のプロジェクト CalcBinding を見ることを勧めます。これはこの問題と他のいくつかを解決するために特別に開発されました。高度なバインディングを使用すると、xamlで直接多くのソースプロパティを持つ式を書くことができます。たとえば、次のように書くことができます。

<Button IsEnabled="{c:Binding Path=!IsReadOnly}" />

または

<Button Content="{c:Binding ElementName=grid, Path=ActualWidth+Height}"/>

または

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

または

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

ここで、A、B、C、IsChecked - viewModelのプロパティ、それは適切に動作します

がんばろう!

61
Alex141

私は https://quickconverter.codeplex.com/ を使うことをお勧めします

ブール値の反転は、次のように簡単です。<Button IsEnabled="{qc:Binding '!$P', P={Binding IsReadOnly}}" />

これは、コンバータの作成に通常必要な時間を短縮します。

18
Noxxys

私は自分のXAMLをできるだけ洗練された状態に保ちたかったので、私の共有ライブラリの1つに存在するboolをラップするクラスを作成しました。

public class InvertableBool
{
    private bool value = false;

    public bool Value { get { return value; } }
    public bool Invert { get { return !value; } }

    public InvertableBool(bool b)
    {
        value = b;
    }

    public static implicit operator InvertableBool(bool b)
    {
        return new InvertableBool(b);
    }

    public static implicit operator bool(InvertableBool b)
    {
        return b.value;
    }

}

あなたのプロジェクトに必要な唯一の変更はあなたが反転させたいプロパティがboolの代わりにこれを返すようにすることです

    public InvertableBool IsActive 
    { 
        get 
        { 
            return true; 
        } 
    }

そしてXAMLポストフィックスで、ValueまたはInvertのいずれかでバインディングを

IsEnabled="{Binding IsActive.Value}"

IsEnabled="{Binding IsActive.Invert}"
13
jevansio

これはnull許容型のブールにも有効です。

 [ValueConversion(typeof(bool?), typeof(bool))]
public class InverseBooleanConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (targetType != typeof(bool?))
        {
            throw new InvalidOperationException("The target must be a nullable boolean");
        }
        bool? b = (bool?)value;
        return b.HasValue && !b.Value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return !(value as bool?);
    }

    #endregion
}
8
Andreas

これがXAMLに関連しているかどうかはわかりませんが、私の簡単なWindowsアプリで手動でバインディングを作成し、Formatイベントハンドラを追加しました。

public FormMain() {
  InitializeComponent();

  Binding argBinding = new Binding("Enabled", uxCheckBoxArgsNull, "Checked", false, DataSourceUpdateMode.OnPropertyChanged);
  argBinding.Format += new ConvertEventHandler(Binding_Format_BooleanInverse);
  uxTextBoxArgs.DataBindings.Add(argBinding);
}

void Binding_Format_BooleanInverse(object sender, ConvertEventArgs e) {
  bool boolValue = (bool)e.Value;
  e.Value = !boolValue;
}
2
Simon Dobson

私は反転の問題を抱えていましたが、きちんとした解決策を見つけました。

動機は、XAMLデザイナーが空のコントロールを表示することです。 datacontext/no MyValues(itemssource)がなかったとき。

初期コード:hideMyValuesが空の場合に制御します。改善されたコード:showMyValuesがNULLでも空でもない場合の制御。

もちろん、問題は「1つ以上の項目」を表現する方法です。これは0項目の反対です。

<ListBox ItemsSource={Binding MyValues}">
  <ListBox.Style x:Uid="F404D7B2-B7D3-11E7-A5A7-97680265A416">
    <Style TargetType="{x:Type ListBox}">
      <Style.Triggers>
        <DataTrigger Binding="{Binding MyValues.Count}">
          <Setter Property="Visibility" Value="Collapsed"/>
        </DataTrigger>
      </Style.Triggers>
    </Style>
  </ListBox.Style>
</ListBox>

私はそれを追加することによってそれを解決しました:

<DataTrigger Binding="{Binding MyValues.Count, FallbackValue=0, TargetNullValue=0}">

バインディングのデフォルトをErgoに設定します。もちろん、これはすべての種類の逆問題でうまくいくわけではありませんが、きれいなコードで私を助けてくれました。

1
EricG

ビューモデルにもう1つプロパティを追加します。これは逆の値を返します。そしてそれをボタンにバインドします。好きです。

ビューモデル内:

public bool IsNotReadOnly{get{return !IsReadOnly;}}

xAMLで:

IsEnabled="{Binding IsNotReadOnly"}
1
MMM

@ Paulの答えに続いて、私はViewModelに次のように書きました。

public bool ShowAtView { get; set; }
public bool InvShowAtView { get { return !ShowAtView; } }

ここにスニペットがあれば、だれか、おそらく私のように初心者に役立つことを願っています。
そして、間違いがあったら教えてください!

ところで、私も@heltonbikerのコメントに同意します - それは間違いなく正しいアプローチですのみあなたはそれを3回以上使用する必要はありません...

1
Ofaim

私はとてもよく似たことをしました。データの検索が終了した場合にのみコンボボックスを選択できるようにするために、私は自分の所有物を作成しました。私のウィンドウが最初に現れるとき、それは非同期ロードされたコマンドを起動します、しかし私はまだデータをロードしている間、ユーザーにコンボボックスをクリックさせたくありません(空になり、そして移入されます)。そのため、デフォルトではこのプロパティはfalseになっているので、getterにその逆を返します。それから検索しているときに、プロパティをtrueに設定し、完了したらfalseに戻します。

private bool _isSearching;
public bool IsSearching
{
    get { return !_isSearching; }
    set
    {
        if(_isSearching != value)
        {
            _isSearching = value;
            OnPropertyChanged("IsSearching");
        }
    }
}

public CityViewModel()
{
    LoadedCommand = new DelegateCommandAsync(LoadCity, LoadCanExecute);
}

private async Task LoadCity(object pArg)
{
    IsSearching = true;

    //**Do your searching task here**

    IsSearching = false;
}

private bool LoadCanExecute(object pArg)
{
    return IsSearching;
}

それからコンボボックスの場合は、IsSearchingに直接バインドできます。

<ComboBox ItemsSource="{Binding Cities}" IsEnabled="{Binding IsSearching}" DisplayMemberPath="City" />
1
GregN