WPF에서 역 부울 속성을 바인딩하는 방법은 무엇입니까?


377

내가 가진 것은 IsReadOnly속성 이있는 객체입니다 . 이 속성이 true이면 IsEnabledButton 의 속성 (예 :)을 false 로 설정하고 싶습니다 .

나는 그것을 쉽게 할 수 있다고 생각하고 IsEnabled="{Binding Path=!IsReadOnly}"싶지만 WPF와 함께 비행하지는 않습니다.

모든 스타일 설정을 거쳐야합니까? 하나의 bool을 다른 bool의 역수로 설정하는 것만 큼 단순한 단어로는 너무 장황한 것처럼 보입니다.

<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>


eh ms는 잘하지만 불완전합니다
user1005462

답변:


488

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
    }

8
여기서 고려해야 할 몇 가지 사항이 있습니다.이 질문에 대해 @Paul의 답변을 선택하게 될 것입니다. 나는 코딩 할 때 (현재) 혼자서 있으므로 "I"가 기억할 솔루션을 사용해야합니다. 또한 말이 적을수록 좋은 것이 더 좋다고 생각하고 역 속성을 만드는 것이 매우 명시 적이므로 미래의 개발자 (I Hope, I Hope)뿐만 아니라 내가 기억하는 것을 쉽게 만들 수 있습니다. 그들이 저를 속담 버스 아래로 던질 수있게 해주었습니다.
Russ

17
자신의 주장에 따르면 IMHO 변환기 솔루션은 장기적으로 더 낫습니다. 변환기를 한 번만 작성하면 그 후에는 계속해서 재사용 할 수 있습니다. 새 부동산을 찾으러 가야 할 경우, 필요한 모든 수업에서 다시 작성해야합니다.
Thomas Levesque

51
나는 같은 접근법을 사용하고 있습니다 ...하지만 팬더를 만듭니다 ... = (
Max Galkin

27
에 비해 !, 그것은 오래 걸리는 코드입니다 ... 사람들은 자신이 "코드"라고 느끼는 것을 그 가난한 디자이너들로부터 분리하기 위해 엄청난 노력을 기울입니다. 코더와 디자이너 모두 더 고통 스럽습니다.
Roman Starkov

10
나 자신을 포함한 많은 사람들이 이것을 과도 공학의 대표적인 예라고 생각할 것입니다. 아래의 Paul Alexander 게시물과 같이 거꾸로 된 재산을 사용하는 것이 좋습니다.
Christian Westman

99

IsNotReadOnly부동산 을 고려 했습니까 ? 바인딩되는 객체가 MVVM 도메인의 ViewModel 인 경우 추가 속성이 완벽합니다. 직접 엔터티 모델 인 경우 엔터티의 특수한 ViewModel을 구성하고 양식에 제시 할 수 있습니다.


5
방금이 접근법을 사용하여 동일한 문제를 해결했으며 변환기를 사용하는 것보다 우아하고 유지 관리가 훨씬 쉽다는 데 동의합니다.
alimbada

28
이 접근법이 가치 변환기보다 낫다는 것에 동의하지 않습니다. 또한 여러 NotProperty 인스턴스가 필요한 경우 더 많은 코드를 생성합니다.
Thiru

25
MVVM은 코드를 작성하는 것이 아니라 문제를 선언적으로 해결하는 것입니다. 이를 위해 컨버터 올바른 솔루션입니다.
Jeff

14
이 솔루션의 문제점은 100 개의 개체가있는 경우 모든 100 개의 개체에 IsNotReadOnly 속성을 추가해야한다는 것입니다. 이 속성은 DependencyProperty 여야합니다. 이는 100 개의 객체 또는 1000 줄의 코드에 약 10 줄의 코드를 추가합니다. 변환기는 20 줄의 코드입니다. 1000 라인 또는 20 라인 어느 것을 선택 하시겠습니까?
Rhyous

8
이에 대한 일반적인 말이 있습니다. 한 번만 두 번 한 다음 자동화하십시오. 의심 할 여지없이, 나는이 대답을 프로젝트에 처음 필요할 때 사용하고, 상황이 커지면 받아 들여진 대답을 사용합니다. 그러나 변환기 스 니펫을 사전에 작성하면 사용하기가 덜 어려울 수 있습니다.
heltonbiker

71

표준 바인딩을 사용하면 바람이 거의 부는 것처럼 보이지 않는 변환기를 사용해야합니다. 따라서이 문제와 다른 문제를 해결하기 위해 특별히 개발 된 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}" />

where A, B, C, IsChecked-viewModel의 속성과 제대로 작동합니다


6
QuickConverter가 더 강력하지만 CalcBinding 모드를 읽을 수 있습니다.
xmedeko 2016 년

3
이것은 훌륭한 도구입니다. 5 년 전에 존재했으면 좋겠다!
jugg1es

훌륭한 도구이지만 스타일이 다릅니다. <Setter.Value><cb:Binding Path="!IsReadOnly" /></Setter.Value>'Setter.Value'컴파일 시간 오류에 대해 'Binding'이 유효하지 않습니다.
mcalex

21

https://quickconverter.codeplex.com/을 사용하는 것이 좋습니다.

부울 반전은 다음과 같이 간단합니다. <Button IsEnabled="{qc:Binding '!$P', P={Binding IsReadOnly}}" />

이는 일반적으로 변환기를 작성하는 데 필요한 시간을 단축시킵니다.


18
누군가에게 -1을 줄 때 이유를 설명하는 것이 좋을 것입니다.
Noxxys

16

XAML을 가능한 한 우아하게 유지하고 싶었으므로 공유 라이브러리 중 하나에있는 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}"

1
단점은 코드를 비교하거나 다른 bool유형 표현식 / 변수에 할당 한 모든 코드를 역 값을 참조하지 않아도 변경해야한다는 것입니다 . 대신 "Not"확장 메소드를에 추가합니다 Boolean Struct.
Tom

1
도! 신경 쓰지 마. 해야했다 분실 PropertyMethodBinding. 나의 "하향"진술이 여전히 적용됩니다. Btw, 'Boolean' "Not"확장 방법은 여전히 ​​"!"를 피하는 데 유용합니다. 흔하게 보이는 문자 (즉, 하나 이상의 "("와 "l"와 "I")) 옆에 내장되어있을 때 쉽게 놓칠 수있는 연산자
Tom

10

이것은 nullable bool에도 적용됩니다.

 [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
}

4

뷰 모델에 속성을 하나 더 추가하면 역값이 반환됩니다. 그리고 버튼에 바인딩하십시오. 처럼;

뷰 모델에서 :

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

xaml에서 :

IsEnabled="{Binding IsNotReadOnly"}

1
좋은 대답입니다. 추가해야 할 사항은 IsReadOnly 속성의 setter에서 IsNotReadOnly에 대한 PropertyChanged 이벤트를 더 잘 발생시키는 것입니다. 이를 통해 UI가 올바르게 업데이트됩니다.
Muhannad

가장 단순하기 때문에 이것이 정답입니다.
gabnaim

2

이것이 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;
}

1
컨버터 방식과 거의 동일합니다. FormatParse윈폼 바인딩 이벤트는 WPF 컨버터의 거의 동일합니다.
Alejandro

2

나는 반전 문제가 있었지만 깔끔한 해결책이있었습니다.

동기는 XAML 디자이너가 예를 들어 datacontext / no MyValues(itemssource) 가 없을 때 빈 컨트롤을 표시한다는 것 입니다.

초기 코드 : 비어 있을 때 컨트롤 숨기기 MyValues개선 된 코드 : null 또는 비어 있지 않은 경우 제어 표시MyValues .

물론 문제는 '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 바인딩의 기본값을 설정합니다. 물론 이것은 모든 종류의 역 문제에는 적용되지 않지만 깨끗한 코드로 도움이되었습니다.


2

💡 .Net 핵심 솔루션 💡

null 상황을 처리하고 예외를 발생시키지 않지만 true값이 없으면 반환 합니다. 그렇지 않으면 입력 된 부울을 가져 와서 반대로합니다.

public class BooleanToReverseConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
     => !(bool?) value ?? true;

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
     => !(value as bool?);
}

Xaml

IsEnabled="{Binding IsSuccess Converter={StaticResource BooleanToReverseConverter}}"

App.Xaml 모든 변환기 정적을 app.xaml 파일에 넣고 싶습니다. 따라서 프로젝트의 창 / 페이지 / 컨트롤 전체에서 이들을 다시 선언하지 않아도됩니다.

<Application.Resources>
    <converters:BooleanToReverseConverter x:Key="BooleanToReverseConverter"/>
    <local:FauxVM x:Key="VM" />
</Application.Resources>

분명한 converters:것은 실제 클래스 구현에 대한 네임 스페이스입니다 ( xmlns:converters="clr-namespace:ProvingGround.Converters").


1

@Paul의 대답에 따라 ViewModel에 다음을 작성했습니다.

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

나는 발췌 문장이 누군가를 도울 것입니다. 아마도 초보자입니다.
실수가 있으면 알려주세요!

BTW, @heltonbiker 의견에 동의합니다 .3 번 이상 사용할 필요가없는 경우에만 올바른 접근 방식입니다 ...


2
전체 속성이 아니며 "OnPropertyChanged"가 없으면 작동하지 않습니다. 사례에 따라 첫 번째 또는 두 번째 답변이 사용중인 것입니다. frameowkr이 "추천 된"속성을 업데이트 할시기를 알고있는 Prism과 같은 프레임 워크를 사용하지 않는 한. 그렇다면 그것은 당신이 제안한 것과 같은 것을 사용하는 것과 (전체 재산으로) 답하는 것 사이에 토스입니다. 1
Oyiwai

1

나는 매우 비슷한 것을했습니다. 데이터 검색이 완료된 경우에만 콤보 박스를 선택할 수 있도록 씬 뒤에 내 속성을 만들었습니다. 내 창이 처음 나타나면 비동기로드 명령이 시작되지만 여전히 데이터를로드하는 동안 사용자가 콤보 상자를 클릭하지 않기를 원합니다 (비어있을 때 채워짐). 따라서 기본적으로 속성은 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" />

0

@Ofaim과 비슷한 접근법을 사용합니다.

private bool jobSaved = true;
private bool JobSaved    
{ 
    get => jobSaved; 
    set
    {
        if (value == jobSaved) return;
        jobSaved = value;

        OnPropertyChanged();
        OnPropertyChanged("EnableSaveButton");
    }
}

public bool EnableSaveButton => !jobSaved;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.