views:

3012

answers:

2

I have a button on my form that should only be enabled when an item is selected in a treeview (or the listview in a tabitem).
When an item is selected, it's value is stored in a string member variable. Can I bind the IsEnabled property of the button to the content of the member var? That is, if the member var is not empty, enable the button.
Similarly, when the content of the member var changes (set or cleared), the button's state should change.
Thanks for any insights...

+2  A: 

Since you're probably looking to bind the IsEnabled property of the button based on a string, try making a converter for it.

Ie...


<StackPanel>
<StackPanel.Resources>
<local:SomeStringConverter mystringtoboolconverter />
</StackPanel.Resources>
<Button IsEnabled="{Binding ElementName=mytree, Path=SelectedItem.Header, Converter={StaticResource mystringtoboolconverter}}" />
<StackPanel>

and the converter:


[ValueConversion(typeof(string), typeof(bool))]
    class SomeStringConverter : IValueConverter {
     public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) {
      string myheader = (string)value;
      if(myhead == "something"){
       return true;
      } else {
       return false;
      }
     }

     public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) {
      return null;
     }
    }

EDIT: Since the OP wanted to bind to a variable, something like this needs to be done:


public class SomeClass : INotifyPropertyChanged {
  private string _somestring;

  public string SomeString{
    get{return _somestring;}
    set{ _somestring = value; OnPropertyChanged("SomeString");}
  }

  public event PropertyChangedEventHandler PropertyChanged;
  protected void OnPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

}

Then, change the above binding expression to:

{Binding Path=SomeString, Converter={StaticResource mystringtoboolconverter}}

Note, you MUST implement INotifyPropertyChanged for your UI to be updated.

apandit
Thanks for the reply.I'm getting an error in my xaml on this line:<Grid.Resources> <local:StringToBoolConverter stringToBoolConverter /></Grid.Resources>"The type local:StringToBoolConverter was not found."StringToBoolConverter is the name of my converter class. Do I need to qualify it with a namespace?
Number8
Got it. Namespace issue in the xaml.
Number8
Hmm. I think this is incomplete; it looks like there there needs to be some sort of event raised by the member property that the Button responds to, so when the member property is changed, the button's Enabled state will change.
Number8
basically, yeah. The button's value changes when the SelectedItem changes. If you want to change it based on something else, bind it to that instead. The most important part is that you're binding a string to the button and using a converter to make it a bool.
apandit
You have to add an OnPropertyChanged to the var then. I've got it binded to a selection change in the List right now. If you want something like, var something = somethingnew; and have that reflected in the UI, you're going to have to make that var a property and implement INotifyPropertyChanged... I'll add this to my post.
apandit
Thanks, the OnPropertyChanged() bits seems to be the key.Appears to be working as desired. Note that my app gives the user the option of seeing data in a tree view or tab view. With the button enabled state bound to the var, the button gets updated correctly regardless of whether tab or tree is chosen.Appreciate the help...
Number8
+1  A: 

Do you have a ViewModel holding your string property set as the DataContext of the View where you try to do this Binding?

Then the following will work:

  // Example ViewModel
public class MyClass : INotifyPropertyChanged
{
    private string text;

    public string Text
    {
        get { return text; }
        set 
        { 
            text = value;
            UpdateProperty("Text");
            UpdateProperty("HasContent");
        }
    }

    public bool HasContent
    {
        get { return !string.IsNullOrEmpty(text); }
    }


    public event PropertyChangedEventHandler PropertyChanged;

    protected void UpdateProperty(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
}

Then you should have done something like this in the code behind of the view:

this.DataContext = new MyClass();

And a Xaml example:

 <StackPanel>
        <TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}" />
        <Button IsEnabled="{Binding HasContent}">
            Click Me!
        </Button>
    </StackPanel>
Andrej
The string property is in my main window class.Is there a way to make it work in this case? Right now, the HasContent() method is not getting called; I suspect it has to do with the DataContext not getting set.
Number8
What causes the button to call HasContent() to set its state?Also, I have no control that is getting the value of the string. Does IsEnabled need the UpdateSourceTrigger attribute?
Number8
If the window has those properties, you could set it as its own DataContext like:this.DataContext = thisin the Windows Loaded-Event. However this is very bad practise. You should consider having a ViewModel like the one in my sample set as DataContext.Note HasContent is not a method, its a Property, for only Properties can be bound to the view.Its getter is evaluated each time you raise PropertyChanged with the specific property name.UpdateSourceTrigger is mainly needed for TextBoxes to write their textchanges back to the bound property with each typed key. Else they do this on lost focus
Andrej