2

I have some controls which I need to hide or disable based on results of some calculations. I'd like to bind IsEnabled or IsVisible property to a result of some method or property get of parent form class. Something like this:

<TabItem Name="MyTab" Header="This should be enabled when result is 2" IsEnabled="{Binding MyMethod}">
    <!--Some other stuff-->
</TabItem>

and in the code behind:

public bool MyMethod()
{
    return _valueA + _valueB == 2;
}

Can you help me find a proper way to achieve this, please?

Thx, JiKra

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
JiKra
  • 1,618
  • 3
  • 29
  • 45
  • Where do _valueA and _valueB come from and when should they be recalculated? – Steve Danner Jun 06 '12 at 13:42
  • They can be global variables of the current class, or there can be some external calculator class assigned - it doesn't matter. I just need to bind IsEnabled property to a method like this or to a class property. – JiKra Jun 06 '12 at 13:45

3 Answers3

3

You may need to use a MultiBinding:

<TabItem Name="MyTab" Header="This should be enabled when result is 2">
  <TabItem.IsEnabled>
     <MultiBinding Converter={StaticResource MyAddConverter}>
         <Binding Path=ValueA UpdateSourceTrigger=PropertyChanged />
         <Binding Path=ValueB UpdateSourceTrigger=PropertyChanged />
     </MultiBinding>
  </TabItem.IsEnabled>
    <!--Some other stuff-->
</TabItem>

In your ViewModel, you should have the following (assuming your ViewModel implements INotifyPropertyChanged ):

public double ValueA
{
  get { return _valueA; }
  set 
  {
    _valueA = value;
    OnPropertyChanged("ValueA");
  }
}

And same for ValueB, which would allow WPF to update the Binding every time either ValueA or ValueB changes

Your converter should look like this:

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
  double valueA = (double)values[0];
  double valueB = (double)values[1];
  return valueA + valueB == 2;
}

This would allow you to have one external method defined in the Converter, which will be called again every time ValueA or ValueB would change.

I'd say that's all you need =)

Damascus
  • 6,553
  • 5
  • 39
  • 53
  • OK, this is realy nice. I know about converters. But the point of my question was whether or not is possible to bind IsEnabled (or any) property of components to a local method or a class property. valueA and valueB are irrelevant, it was just an example. I'm a newbie to a WPF, don't blame me, please. So can you show me a most simpliest way how to bind IsEnabled to a local method or class property, e.g. really dummy prop like: public bool IsItEnabled() { return true; } ? – JiKra Jun 06 '12 at 15:05
  • You can usually bind to properties. What you can do is the following: `public bool IsIsEnabled { get { return true; } }` and it'd easily fit what you need. The good practice in WPF to bind to methods is to use a converter (or the workaround just above). I believe there are a few ways to do it but I haven't looked at it since converters do what I need and are easier to maintain – Damascus Jun 06 '12 at 15:41
  • Some workarounds are listed here : http://stackoverflow.com/questions/502250/bind-to-a-method-in-wpf if you really need to bind to a method – Damascus Jun 06 '12 at 15:42
2

You need to create a new property that represents the value you are trying to achieve here. This is the entire purpose of a view model. I strongly advise you to avoid using a converter here, even though it will work. Converters should be used to handle view-only concerns, whereas this is a view state concern.

A potential view model would look like this: (I am using my BindableBase)

class AddingViewModel : BindableBase {
    private int _valueA;
    public int ValueA {
        get { return _valueA; }
        set { SetProperty(ref _valueA, value, "ValueA", OnValueAChanged); }
    }

    private void OnValueAChanged() { UpdateIsTabEnabled(); }

    private int _valueB;
    public int ValueB {
        get { return _valueB; }
        set { SetProperty(ref _valueB, value, "ValueB", OnValueBChanged); }
    }

    private void OnValueBChanged() { UpdateIsTabEnabled(); }

    private bool _isTabeEnabled;
    public bool IsTabEnabled {
        get { return _isTabEnabled; }
        private set { SetProperty(ref _isTabEnabled, value, "IsTabEnabled"); }
    }

    private void UpdateIsTabEnabled() {
        IsTabEnabled = _valueA + _valueB == 2;
    }
}

This may seem a bit verbose, but I'd like to highlight a few reasons for this:

  • As requirements change, it's easy to find and change UpdateIsTabsEnabled.
  • As ValueA and ValueB become components to other features, it's easy to add hooks into their respected OnChanged methods.
  • It's easy to bind IsTabEnabled to either IsEnabled or Visibility as desired.
Daniel Moore
  • 1,116
  • 1
  • 9
  • 16
1

You can't bind to a method directly. It will need to be a property. With that said there are some other tricks to bind to a method shown in this question Bind to a method in WPF?.

Back to your question, what I would do is to make MyMethod a property.

public double SumAB
{
    get{ return _valueA + _valueB;}
}

Then add a converter for your binding:

<TabItem Name="MyTab" Header="This should be enabled when result is 2" IsEnabled="{Binding SumAB, Converter={StaticResource SumValueToBoolConverter}}">

Your converter code would look like this:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    double sumValue = (double)value;
    if(sumValue==2)
    {
        return true;
    }
    return false;
}
Community
  • 1
  • 1
Hoang Dang
  • 298
  • 2
  • 9