Disable particular item in the ListBox - c#

I bind list of objects to my ListBox in WindowsPhone application. This business object has one boolean property. Based on the Boolean property i need to set the IsEnabled property in the ListBoxItem.
Is there any way to achieve this in WindowsPhone ListBox ?

There're few ways to achieve this:
You can add the ListBoxItem by C# code and set the property properly.
In Xaml, inside the list box, place the following:
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="{Binding Content.IsEnabled, RelativeSource={RelativeSource Self}}"/>
</Style>
</ListBox.Resources>
Here I assume that the property name in your model object is IsEnabled, change it according to its real name.

Related

Binding style property outside itemsource?

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}}” />

How do I use a Trigger to synchronize ListBox selections?

I have two list boxes which are bound to same observable collection. Basically one list box is a document tray where I drag & drop documents and other is a regular list box where I give the option to edit the file name. I want to highlight the items in both the listboxes. For example when the user selects a document in one listbox (tray) I want the list item with textbox in the other to be highlighted and likewise when I click on the text box in the other list box I want the item in the tray to be selected. I have my code as below.
In the Document Tray list box I have code as below.
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
</Style>
</ListBox.ItemContainerStyle>
Similarly in the other list box I have the style like this
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />
<Style.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="IsSelected" Value="True"></Setter>
</Trigger>
</Style.Triggers>
</Style>
</ListBox.ItemContainerStyle>
When I select an item in the document tray the item is getting selected in the other list box. When I click on the text box or select an item in other list box the item is not getting selected in the tray list box. Also I noticed if I comment the focus trigger the items are getting selected appropriately. I want the selection to be propagated on focus also.
I am assuming you are binding your ListBox to data in code-behind (view model or otherwise) via a property, e.g. YourItems:
<ListBox ItemsSource="{Binding YourItems}">
<ListBox.ItemContainerStyle>
...
</ListBox.ItemContainerStyle>
</ListBox>
Create another property of the type that's within the collection in your code-behind, also (e.g. called YourSelectedItem. Then just add the following line inside BOTH of your Listbox definitions:
<ListBox ItemsSource="{Binding YourItems}"
SelectedItem="{Binding YourSelectedItem, Mode=TwoWay}">
As long as both are bound two-way, then they should stay in-sync with each other.
I would not use setters in the style to set IsSelected (discard the lines <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" />). The ListBoxes themselves have properties to handle that if you can bind to a common item in code-behind as shown above. I'd need to try it, but then hopefully your trigger would work also since you won't have competing IsSelected triggers/styling.
I think the key thing here is that I've found that sometimes you cannot set something via trigger IF you've also set the same property via a style, so use SelectedItem on the ListBox parents, instead of an IsSelected style on each item.

Dynamically set UserControl as Listbox DataTemplate body

I have the following setup:
<ListBox ItemSource="{Binding Targets}">
<ListBox.ItemTemplate>
<DataTemplate>
<view:ViewName />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What I am trying to accomplish is to dynamically decide which view to use at runtime, based on a property within the DataContext of the ListBox. In simple terms, I want to replace <view:ViewName> with a data binding that returns the proper view.
I use MEF to provide plug-ins for my app that may need to provide a custom view to display the items when appropriate. At design time I won't know all the possible view types (they may be dynamically loaded from a DLL) so a simple DataTemplateSelector won't do.
I have researched solutions but have come up empty.
Since you want to change templates based on a bound value, you can use a DataTrigger to determine the ContentTemplate of the ListBoxItem
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate" Value="{StaticResource DefaultTemplate}"/>
<Style.Triggers>
<DataTrigger Property="{Binding SomeProperty}" Value="A">
<Setter Property="ContentTemplate" Value="{StaticResource TemplateA}"/>
</DataTrigger>
</Style.Triggers>
</Style>
I find this better than using a DataTemplateSelector because it gets re-evaluated if the bound property changes, while a DataTemplateSelector does not.
If you want to change templates based on an object type, you can use Implicit DataTemplates. These are DataTemplates that define a DataType, but no x:Key, and they will be used anytime WPF tries to draw an object of the specified type.
For example, if you had this template defined in your <X.Resources> somewhere
<DataTemplate DataType="{x:Type models:ActionA}">
<views:ActionAView />
</DataTemplate>
you could then insert your Model object directly into the UI and WPF would draw it using the template you specified
<ContentControl Content="{Binding SomeIActionObject}" />
<ItemsControl ItemsSource="{Binding CollectionOfIActionObjects}" />
Update
You mentioned that you would be allowing users to create modules with additional Templates that get imported using MEF, so in that case you would probably be better off using an IValueConverter that look up the matching template within Application.Resources
For example, if the bound value equals "A", then the converter might search Application.Resources for a template named "TemplateA" and return it to the binding
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate"
Value="{Binding SomeProperty,
Converter={StaticResource MyTemplateConverter}}"/>
</Style>
Using the DataTemplateManager from this post You can do something like:
DataTemplateManager.RegisterDataTemplate<ViewModelType1, ViewType1>();
DataTemplateManager.RegisterDataTemplate<ViewModelType2, ViewType2>();
DataTemplateManager.RegisterDataTemplate<ViewModelType3, ViewType3>();
then you would remove the ItemTemplate from the ListBox:
<ListBox ItemSource="{Binding Targets}"/>
and in the ListBox ViewModel you could:
public void AddTargets()
{
Targets.Add(new ViewModelType1());
Targets.Add(new ViewModelType2());
Targets.Add(new ViewModelType3());
}
Then, each DataTemplate will be automatically used by WPF to render each corresponding ViewModel.
Also note that you can call DataTemplateManager.RegisterDataTemplate() at any time before showing the ListBox, so you can theoretically do that when loading the MEF parts.
Edit:
Based on your comment, you could create a single DataTemplate with a ContentPresenter to display the selected View according to a property in the ViewModel:
<DataTemplate DataType="{x:Type local:TargetViewModel}">
<ContentPresenter x:Name="MainContentPresenter" Content="{Binding}" ContentTemplate="{Binding YourProperty, Converter=SomeConverter}"/>
and inside the SomeConverter you should use the same technique as demonstrated in the post, to dynamically generate a DataTemplate.

WPF Listview & Checkboxes - Binding issue when using relative source

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}"

Trouble binding WPF Menu to ItemsSource

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>

Categories