WPF buttons are outside the datacontext and could not be bound
I have 3 Buttons add,delete,open as RelayCommands in my DocumentViewModel. Below you see how I have bound them. Of course those binding does not work, because the data is set to the ItemsSource of the ListBox and the buttons are outside of that...
What I tried then is to set the DataContext at the first StackPanel you see in my code snippet.
like this: <StackPanel DataContext="{Binding DocumentViewModelList}" >
BUT then a new problem arised... now the documents are NOT visible/listed anymore in the ListBox :/
How can I make BOTH working?
<StackPanel Orientation="Vertical" >
<ListBox
Height="100"
Width="Auto"
Focusable="True"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.VerticalScrollBarVisibility="Auto"
Grid.Row="1"
Name="itemListBox"
BorderThickness="1"
ItemsSource="{Binding DocumentViewModelList}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<!-- xxx -->
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Mode=TwoWay, Path=IsSelected}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Stretch">
<Button Command="{Binding DeleteDocumentCommand}" HorizontalContentAlignment="Stretch" HorizontalAlignment="Stretch" Content="Delete" />
<Button Command="{Binding AddDocumentCommand}" HorizontalAlignment="Stretch" Content="Add" />
<Button Command="{Binding OpenDocumentCommand}" HorizontalAlignment="Stretch" Content="Open" />
</StackPanel>
</StackPanel>
UPDATE:
I tried this:
<Button Command="{Binding Path=DeleteDocumentCommand, RelativeSource={RelativeSource AncestorType={x:Type DocumentViewModel}}}"
and got this: The type reference cannot find a public type named 'DocumentViewModel'
I would like to stick with the StackPanel DataContext solution and make somehow the ListBox.ItemsSource grabbing the DocumentViewModelList via RelativeSource binding with FindAncestor. I tried some things but no luck, maybe someone can post a nice snippet :)
OK I found the solution: <ListBox ItemsSource="{Binding}" ..
.
this is binding to the current DataContext that is "DocumentViewModelList" cool!
UPDATE 2:
ok there is still another problem, maybe if someone can provide a solution on this I mark this thread as a solution then. Do not want to open a new thread, because the whole text+code snippet is the same... Problem now is =>Selecting The 1st Document activates the Button. Selecting any other Button does not activate a Button, WHY? What is wrong with the binding of my IsSelected property ?
DocumentViewModel.cs:
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
if (_isSelected == value)
return;
_isSelected = value;
this.RaisePropertyChanged("IsSelected");
}
}
UPDATE 2:
This is the code for enabling the buttons: What do I wrong? I get no binding errors in the output console!?
private void DeleteDocument()
{
throw new NotImplementedException();
}
private bool CanDeleteDocument()
{
return (IsSelected == true);
}
private void AddDocument()
{
}
private void OpenDocument()
{
}
public Rel开发者_StackOverflow中文版ayCommand DeleteDocumentCommand
{
get { return _deleteDocumentCommand ?? (_deleteDocumentCommand = new RelayCommand(() => DeleteDocument(), () => CanDeleteDocument())); }
}
public RelayCommand AddDocumentCommand
{
get { return _addDocumentCommand ?? (_addDocumentCommand = new RelayCommand(() => AddDocument())); }
}
public RelayCommand OpenDocumentCommand
{
get { return _openDocumentCommand ?? (_openDocumentCommand = new RelayCommand(() => OpenDocument())); }
}
Is the DocumentViewModelList
a property of your DocumentViewModel
?
Typically, what I would have is a ViewModel for that window which would expose an ObservableCollection<T>
where T
is what you want displayed in the list. Then, you can assign the Window/Page/etc.'s DataContext
to the ViewModel, and then bind the ItemsSource
of the ListBox
to that ObservableCollection<T>
property.
For example, here would be a snippet of my ViewModel.
public class SomeViewModel
{
public ObservableCollection<SingleDocumentViewModel> Docs {get; private set; }
// other properties can go here
}
In the code-behind for the XAML, (I usually do it in the constructor), you can set its DataContext
to a new instance of your ViewModel
public AwesomeDocumentList()
{
this.DataContext = new SomeViewModel();
// the rest of the constructor
}
With the Window's DataContext set, you can bind the ItemsSource
to the exposed property (I called it Docs
)
<ListBox ItemsSource="{Binding Docs}" ... />
Hope that helps.
Update
In the RelayCommand
for the button, do you have something specified for the CanExecute
predicate? If not, then I believe the RelayCommand
will default to always enabled. But if you have a predicate specified, take a look in there.
The code you posted for the IsSelected
property looks fine. Looks like the problem lies elsewhere.
精彩评论