I have a listview with two columns, one contains a textbox and the other a checkbox. These are bound to an ObservableCollection of a custom object containing a string for the textbox and a boolean for the checkbox.
All was working well until I tried having the check event of the checkbox highlight it's the row in the listview as in this article.
My problem is that checkbox no longer binds to the ObservableCollection. The textbox binds okay, but changing the checbox declaration from:
<CheckBox IsChecked="{Binding RestrictedEdit}"/>
to this:
<CheckBox IsChecked="{Binding RestrictedEdit, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListViewItem}}}"/>
stops the checkbox binding and the listview is displayed with the checkboxes all unchecked irrespectivate of status of the boolean. What am I doing wrong?
You are trying to bind to RestrictedEdit property, which ListViewItem doesn't have. This property is declared in view model, which is stored in DataContext, so this should work:
<CheckBox IsChecked="{Binding DataContext.RestrictedEdit,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type ListViewItem}}}"/>
However, I don't see any reason to use this code instead of simple IsChecked="{Binding RestrictedEdit}". CheckBox inherits DataContext from ListViewItem, so there is no reason to use relative source.
Let the binding as it is (no RelativeSource) and use rather a style or a DataTemplate having your custom object class as TargetType, and with a DataTrigger set on RestrictedEdit.
example with style :
<Style x:Key="MyStyle" TargetType="MyClass">
<Setter Property="BackGround" Value="White" />
<Style.Trigger>
<DataTrigger Binding="{Binding RestrictedEdit}" Value="False">
<Setter Property="BackGround" Value="Gray" />
</DataTrigger>
</Style.Trigger>
</Style>
Define this style, say, in your application resources (in App.xaml).
Then in your listview, use :
ItemContainerStyle="{StaticResource MyStyle}"
Related
I've a combobox like this:
<ComboBox x:Name="CountryMenuComboBox"
ItemsSource="{Binding Countries}">
<ComboBox.ItemContainerStyle>
<Style>
<Setter Property="IsEnabled" Value="{Binding IsRemoving}" />
</Style>
</ComboBox.ItemContainerStyle>
what I need to do is enable or disable the items inside the combobox using the property IsRemoving, but this property isn't located inside the itemsource Countries, so I need to access outside the itemsource. How can I do this for a style?
Is IsRemoving a property of the parent viewmodel that owns the Countries property? If so, try <Setter Property=“IsEnabled” Value=“{Binding DataContext.IsRemoving, RelativeSource={RelativeSource AncestorType=ComboBox}}” />
I have a check box which I plan to implement a 'Select All' feature on.
I figured the easiest implementation was to modify my DataTemplate with a DataTrigger to change the IsChecked property to true/false.
<UserControl.Resources>
<DataTemplate x:Key="MyTemplate">
<Grid>
<CheckBox x:Name="Selection" IsChecked="{Binding Selected}" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding ElementName=SelectAll, Path=IsChecked}" Value="true">
<Setter TargetName="Selection" Property="DataContext.Selected" Value="true" />
</DataTrigger>
<DataTrigger Binding="{Binding ElementName=SelectAll, Path=IsChecked}" Value="false">
<Setter TargetName="Selection" Property="IsChecked" Value="false" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</UserControl.Resources>
<Grid>
<CheckBox Name="SelectAll />
<ListView Name="lvSteps" ItemTemplate="{StaticResource MyTemplate}" ItemsSource="{Binding MyList}" />
</Grid>
However, this overwrites the binding of the CheckBox which is set to the DataContext property 'Selected' to just the bool values set in the DataTrigger.
Which thinking about it makes perfect sense.
So my question is, can I change the value of DataContext property within a DataTrigger via Setter?
So I can keep my CheckBox bound to 'Selected', and change the 'Selected' value within the Setter of the DataTrigger?
you maybe think about it in the wrong way.
SelectAll is surly part of your container Element (lets say ListVM) which intern holds your objects (ListItemVM) which contains Selected so if you check SelectAll you can and should iterate over your Elements and set Selected to true and this items use there INotifyPropertyChanged to inform your CheckBox
Edit for Comment
there is no need to hook up the event of SelectAll just bind to it and do your thing in the Set-Part
public bool SelectAll
{
get { return _selectAll;}
set
{
_selectAll = value;
RaisPropertyChanged();
foreach( var item in MyList)
{
item.Select = _selectAll;
}
}
}
Also why would you like to do this in xaml?
Because you could use interfaces and factor it out in a way that you can us it at many places without code redundancy also you will be able to do it in code from where ever you are able to access the "ListVM"
I have a nested context menu like this:
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Thing Count" ItemsSource="{Binding ThingsProvider}">
NB the Thing Count parent MenuItem with children from ThingsProvider.
ThingsProvider provides a List of ThingViewModel which contains properties Thing and IsChecked. I want to be able to control IsChecked from my main view model and from the user via the MenuItem but I have hit a problem; If I use an ItemContainerStyle like this.
<MenuItem.ItemContainerStyle>
<Style TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Path=Thing, Mode=OneWay}"/>
<Setter Property="IsChecked" Value="{Binding Path=IsChecked, UpdateSourceTrigger=PropertyChanged}"/>
</Style>
</MenuItem.ItemContainerStyle>
then (predictably I suppose as it's a style) it will observe the ViewModel's IsChecked but will not set it.
If I use an ItemTemplate like so
<MenuItem.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Thing, Mode=OneWay}"/>
</DataTemplate>
</MenuItem.ItemTemplate>
I can't get to the MenuItem's IsChecked property as I've only got the TextBlock. If I put a MenuItem in the ItemTemplate then I end up with nested MenuItems in my UI and it looks bad.
There must be a way to do this but I'm stumped at the moment, can anyone help?
Cheers
Rich
I have implemented a datagrid in my WPF application using the MVVM design pattern.
Each row of the datagrid has a combobox and a another control based on the selection of the combobox and everything works fine.
The problem is that the NewItemPlaceholder (the row that enables me to add new objects to my ObservableCollection) by default displays DataGrid.NewItemPlaceholder. As I have read here the problem is that I must create a datatemplate for that row. And in that link it is described how to do it programatically. Is there a way to do it directly in XAML?
Thank you in advance.
Try this out:
<DataGrid.RowHeaderTemplate>
<DataTemplate>
<buttons:CloseButton x:Name="CloseButton"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type DataGridRow}},
Path=IsNewItem}" Value="True">
<Setter TargetName="CloseButton" Property="Visibility" Value="Collapsed"></Setter>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGrid.RowHeaderTemplate>
I use a trigger to hide the button, only on the New Item row. With a little ingenuity I ought to be able to swap out entire templates, like use a content presenter and change its template or something similar.
I would like to avoid having to build a menu manually in XAML or code, by binding to a list of ICommand-derived objects. However, I'm experiencing a bit of a problem where the resulting menu has two levels of menu-items (i.e. each MenuItem is contained in a MenuItem):
My guess is that this is happening because WPF is automatically generating a MenuItem for my binding, but the "viewer" I'm using actually already is a MenuItem (it's derived from MenuItem):
<ContextMenu
x:Name="selectionContextMenu"
ItemsSource="{Binding Source={x:Static OrangeNote:Note.MultiCommands}}"
ItemContainerStyleSelector="{StaticResource separatorStyleSelector}">
<ContextMenu.ItemTemplate>
<DataTemplate>
<Viewers:NoteCommandMenuItemViewer
CommandParameter="{Binding Source={x:Static OrangeNote:App.Screen}, Path=SelectedNotes}" />
</DataTemplate>
</ContextMenu.ItemTemplate>
</ContextMenu>
(The ItemContainerStyleSelector is from http://bea.stollnitz.com/blog/?p=23, which allows me to have Separator elements inside my bound source.)
So, the menu is bound to a collection of ICommands, and each item's CommandParameter is set to the same global target (which happens to be a collection, but that's not important).
My question is, is there any way I can bind this such that WPF doesn't automatically wrap each item in a MenuItem?
Unfortunately, the best way I've found to work around this issue is to use a style for the MenuItems, rather than an ItemTemplate. Then each property in the style can be bound to properties on your object. Something like this, for example:
<Style x:Key="SelectionContextMenuStyle" TargetType="MenuItem">
<Setter Property="Header" Value="{Binding Path=Text}" />
<Setter Property="Command" Value="{Binding Path=Command}" />
<Setter Property="CommandParameter" Value="{Binding Path=Parameter}" />
</Style>
It really seems like an ItemTemplate should work, and it would be the better way to go, but this is the only way I've found that actually works properly.
I would be inclined to subclass ContextMenu and override GetContainerForItemOverride:
public class ContextMenuWithNoteCommands : ContextMenu
{
protected virtual DependencyObject GetContainerForItemOverride()
{
return new NoteCommandMenuItemViewer();
}
}
Then set the CommandParameter binding in the NoteCommandMenuItemViewer style, or in ContextMenu.ItemContainerStyle, whichever is more appropriate.
This presumes you can't simply use ItemContainerStyle on a regular MenuItem to get the effect you want:
<ContextMenu ...>
<ContextMenu.ItemContainerStyle>
<Style>
...
</Style>
</ContextMenu.ItemContainerStyle>
</ContextMenu>