Patrick Ryan Patrick Ryan - 1 year ago 109
C# Question

WPF DataBinding interaction with ItemsSource

In my ListBox I have controls that need to bind to properties in my ItemsSource as well as in my Viewmodel. The buttons as you can see need to do both. The only way I seem to be able to do this is quite ugly (see the IsEnabled property binding to the view's view model). I was wondering what the best way to do this was.

EDIT: To clarify I want to bind the IsEnabled property to CanRemove.

<Button IsEnabled="{Binding CanRemove}"></Button>


This does not work

Thanks

XAML

<ListBox x:Name="songListBox" ItemsSource="{Binding SongList, Mode=TwoWay}" SelectedItem="{Binding SelectedSongAndNumber, Mode=TwoWay}" SelectionChanged="songListBox_SelectionChanged" Tag="{Binding OperationState, Mode=TwoWay}">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>

.......

<Label Grid.Column="1" Width="200" Height="40" Content="{Binding Number, Mode=TwoWay}"/>

<TextBox Grid.Column="3" Width="200" Height="40" Text="{Binding Name, Mode=TwoWay}"/>

<Button Grid.Column="5" x:Name="btnMerge" Click="btnMerge_Click" Content="{Binding Tag, Converter={StaticResource ButtonConverter}, ElementName=songListBox}" IsEnabled="{Binding DataContext,Converter={StaticResource EnableConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AlbumTrackAssociationView}}}">
<Button.Visibility>
<MultiBinding Converter="{StaticResource B2V}">
<Binding Path="Number"/>
<Binding ElementName="songListBox"/>
</MultiBinding>
</Button.Visibility>
</Button>

<Button Grid.Column="7" x:Name="btnDelete" Click="btnDelete_Click" IsEnabled="{Binding DataContext, Converter={StaticResource EnableConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:AlbumTrackAssociationView}}}">Delete
<Button.Visibility>
<MultiBinding Converter="{StaticResource B2V}">
<Binding Path="Number"/>
<Binding ElementName="songListBox"/>
</MultiBinding>
</Button.Visibility>
</Button>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>


ViewModel

public class AlbumTrackAssociationViewModel : ViewModelBase
{
public class SongAndNumber : ViewModelBase
{

private string number;

public string Number
{
get { return number; }
set {
number = value;
RaisePropertyChanged("Number");
}
}

private string name;

public string Name
{
get { return name; }
set
{
name = value;
RaisePropertyChanged("Name");
}
}
}

private int _numberOfSongs { get; set; }

public bool CanRemove
{
get { return SongList != null && (SongList.Count <= _numberOfSongs ? false : true); }
}

public ObservableCollection<SongAndNumber> SongList { get; set; }
}


Converter

public class ItemButtonConverter : IValueConverter
{
public object Convert(object value, Type TargetType, object parameter, CultureInfo culture)
{
AlbumTrackAssociationViewModel vm = (AlbumTrackAssociationViewModel)value;
return vm.CanRemove;
}

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

Answer Source

You don't need converter at all when you can access ViewModel directly using RelativeSource markup extension. This should work:

<Button IsEnabled="{Binding DataContext.CanRemove,
              RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}}"/>

Since DataContext of ListBox points to viewModel instance, above posted code will work.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download