tags:

views:

1364

answers:

3

Hi everybody!

Using MVVM style i succefully bound an ObservableCollection to a listbox, showing up the values as radiobuttons. The control behaves exactly as expected.

Now i have an issue regarding some textboxes bound to this listbox: i want whenever the SelectedItem in the listbox is equal to a specific value (e.g. 'ValueForEnabled') the textboxes to be enabled otherwise they should be disabled.

I know i have to bind to SeletedItem of the listbox (named lbSource) but how exactly is this done?

I want something like this (Pseudo code):

<TextBox  ...

                      IsEnabled="{Binding ElementName=lbSource , Path=SelectedItem='ValueForEnabled' , Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" 
                      ...

/>

Thanks in advance

A: 

One way to skin this cat would be by converting the string (in the listbox) into a bool to pass into the IsEnabledProperty...

First, create a class that implements the IValueConverter interface, like:

public class StringToBoolConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return false;

        string keyword = value.ToString();
        if (keyword.Equals(parameter.ToString(), StringComparison.CurrentCultureIgnoreCase))
            return true;
        return false;
    }

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

    #endregion
}

Notice how you don't need to implement the ConvertBack method? That's because you only need to turn strings into bools, not vice-versa...

So you can declare an instance of your converter in the xaml, like

<Window
    ...
    xmlns:local="clr-namespace:WpfApplication1">

    <Window.Resources>
        <local:StringToBoolConverter x:Key="stringToBoolConverter" />
    </Window.Resources>

And finally, you can bind the TextBox to the ListBox's SelectedValue, like:

<TextBox Grid.Row="0" Width="90" Height="30" 
         IsEnabled="{Binding ElementName=lbSource, Path=SelectedValue, Converter={StaticResource stringToBoolConverter}, ConverterParameter=ValueForEnabled}">
</TextBox>

Note: This will only work if the ListBox contains strings, and you can be sure that the SelectedValue property is a string...

IanR
Interesting approach!I would like to avoid using Converters (it might sound silly but i feel my code is somehow ... scattered around - but i would of course use them if it couldn't be done else-how).Plus point for answering that quickly!!Thanks very much!
Savvas Sopiadis
+1  A: 

OK! Solved it (in another way) myself! For anyone who wants to know:

<TextBox 
...
usual property definitions
...
                      >
                <TextBox.Style>
                    <Style>
                        <Setter Property="TextBox.IsEnabled" Value="False"/>
                        <Style.Triggers>                              
                            <DataTrigger Binding="{Binding ElementName=lbSource , Path=SelectedItem}" Value="ValueForEnabled">
                                <Setter  Property="TextBox.IsEnabled" Value="true"/>
                            </DataTrigger>                           
                        </Style.Triggers>                       
                    </Style>                   
                </TextBox.Style>
            </TextBox>
Savvas Sopiadis
+1  A: 

Personally I think that if you're using MVVM then you should have the code remain in your ViewModel. so if your VM is like this:

public class MyViewModel
{
  public ObservableCollection<string> myColl {get;set;}
  public string SelectedString {get;set;}

  public bool IsEnabled
  {
     get { return SelectedString == "Desired string value";}
  }
}

You then would just bind the textboxes IsEnabled property to your IsEnabled property on your ViewModel

The reason I say this is your requirements may change as to when to have the textboxes enabled and if you do it this way you don't have to touch your view(where code/logic should not reside)

So now you do this in your view and thats it

<TextBox IsEnabled={Binding IsEnabled} Text={Binding SelectedString}/>

Hope I understand your problem and that this helps

Jose
First i thought "why do it this way"?? because you suggest don't put any "logic" (like i'm doing) in XAML but in the VM. The enabling (or not) of a textbox is tightly coupled to XAML (i mean if i want to "adjust" a property of a UI-element, i will do it in XAML, so i will see that there is something set (or not)). So (as i understand) you 're transferring the solution to another place in the same arena!The only thing i don't like is to let the VM-code "clutter" around.Thanks Jose!
Savvas Sopiadis
Your VM should have all the code, your view should translate that to some visible representation(sometimes using converters). That could be disabling, making invisible, popping some kind of notification. Your VM shouldn't care what that is, but it should know that there is a specific state. The View then binds to that property. The closest to code that should be in the view is Converters because this decouples your View from your VM. E.g. a boolean to visibility converter allows your VM to have a boolean property while the View translates that boolean to 'Collapsed' or 'Visible'21
Jose
Your view is basically just a visual translator. It translates lists into a combobox,listbox, or listview. A string,int,long,DateTime into a textbox. Of course your View and VM are "coupled" but only in the sense that your view needs to know what it's translating. Your View needs to know the ViewModel, but the ViewModel should never know about your View, when that happens the separation of concerns which MVVM brings in is severely compromised. I should be able to pop a VM into a Winforms app and it should not require any code change, just rebinding to the new desired View, but WPF is easier :)
Jose
But, there is no ONE right way, many ways solve the problem, just some are more maintainable than others. :)
Jose