wpf checked list box question - wpf

I am creating checked list box with the following template:
<Style x:Key="CheckBoxListStyle" TargetType="{x:Type ListBox}">
<Setter Property="SelectionMode" Value="Multiple"></Setter>
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="Margin" Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<CheckBox IsChecked="{Binding Path=xxxxxxxxxxx,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay}"> <ContentPresenter></ContentPresenter>
</CheckBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
</Style>
<ListBox Style="{StaticResource CheckBoxListStyle}" ItemsSource="{Binding Path=Configuration.ProductTypes}" DisplayMemberPath="ProductName" />
my problem is, i am getting all the product types from Database and binding it to the list box itemssource. i have a product class which contains a list of product types it belongs to. i need to set the IsChecked property of check boxes based on Product's product type list. Typically i need to set one or more check boxes IsChecked property. product may belong to 1 or more product types. and selection mode is multiselect. if user checks the additional product type check boxes ..i need to get the total checked list boxes and save them to the database... this is a MVVM WPF application ... any ideas on how to solve this scenario...
in the controltemplate what will be the path is IsChecked?
Thanks
Rey
Let me simplyfy my question: I need a list box with checkbox and textblock. textblock data context is different and check box data context is different. i mean they get their data from different objects. no idea how to achieve this...

Let me simplyfy my question: I need a
list box with checkbox and textblock.
textblock data context is different
and check box data context is
different. i mean they get their data
from different objects. no idea how to
achieve this...
Create a new class (a ViewModel) which contains the two data contexts (Model1 and Model2) and data bind to it, also known as the MVVM pattern.

The ProductType class that you're binding to the ListBox should have a read/write property called IsSelected or IsChecked that you can bind to. Then instead of using a ControlTemplate, use a DataTemplate on the ListBox.ItemTemplate and bind the CheckBox's IsChecked property to that property.

Related

How to redraw a ListViewItem when something other than the bound item changes?

I've got a ListView that's bound to a collection of Item objects. I don't own the code for Item, so I can't add properties to it for my special binding needs.
I need to color rows in the list based on attributes that I know about each bound item, and since I can't modify the Item code, I've accomplished this with a Style trigger and custom converter; the converter transforms each item like so:
<DataTrigger Binding="{Binding Converter={StaticResource ItemConverter}}" Value="2">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border Name="Border" BorderBrush="Red" BorderThickness="1" Background="{StaticResource MyBrush}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
The ItemConverter transforms the bound item into a return code, and I do my special style based on that code.
This works fine, except that the code changes when the user does things, and I need to refresh the view. The only way I can find to do this is to refresh the ItemSource, and this is very slow.
What I'd really like is to notify the ListView to redraw in such a way that only the visible rows are repainted, without touching the underlying collection, which doesn't need to change. This will affect only a handful of rows, rather than ALL of them, and I suspect this will handle my performance issue. But how to do this?

ComboBoxItem, IsEnabled, Binding to table value

I have a dropdownlist control and its ItemsSource is a collection of items which of type T_LookupTable, which is a table in the db, and one of it's columns is 'isEnabled'.
How do I bind the IsEnabled property of the ComboBoxItem in the XAML to this value in the collection?
Further, I have numerous drop-downs in the application which employ this same method, so I would like to somehow make this a global feature if possible, through a static resource, is something like that possible? I found this piece of XAML, which will work, but I want the items to be greyed out in the drop-down, and this method only disables them where you can't click them, but there is no visual indicator which says the item is disabled:
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<ContentPresenter x:Name="ContentPresenter" IsHitTestVisible="{Binding Path=isEnabled}" />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
I had similar problem with TreeViewItems...
Basically, you have to inherit ComboBox class, override GetContainerForItemOverride method like this:
protected override DependencyObject GetContainerForItemOverride()
{
var result = new ComboBoxItem();
result.SetBinding(Control.IsEnabledProperty, new Binding("IsEnabled"));
return result;
}
It hard codes data binding to IsEnabled property of your data object.

Custom panel with alternate background

I'd like to create a simple custom panel to layout children in a business form fashion. Ideally I'd like my markup to look like this:
<Panels:FormPanel>
<TextBlock Text="Name:"/>
<TextBox />
<TextBlock Text="Address"/>
<TextBlock Text="Unknown"/>
<TextBlock Text="City"/>
<TextBox HorizontalAlignment="Stretch"/>
<TextBlock Text="State"/>
<ComboBox/>
<TextBlock Text="Country"/>
<StackPanel>...</StackPanel>
</Panels:FormPanel>
The panel will layout controls in two columns labels on the left side and values on the right.
I have no problem laying out my controls. The problem is that I also need to alternate background for the rows to create stripes for easier reading.
Any ideas how can this be done?
This doesn't directly answer your question, but you could consider this as another solution to the underlying problem.
Take a look at http://wpg.codeplex.com/. I used a similar property-grid-like control in Windows Forms that was modified to understand custom attributes on my business objects.
Now, in WPF, I would think something similar would work really well if you follow the MVVM pattern and you decorate your ViewModel with attributes that such a property grid understands. Then you don't need to explicitly define the fields like you show above.
You could have a ViewModel:
class PersonViewModel
{
[DisplayName("Name")] // The property Grid uses this the Textblock text
[IsRequired] // The property grid could do validation on the field
[Visible]
public string Name { get; set; }
public long InvisibleSystemField { get; set; } // Not shown
}
And then you'd only have Views (Xaml files) like this:
<myCommon:PropertyGrid DataContext={Binding}/>
It could simply use it's DataContext as the starting point for reflection.
OK I'll stop there for now :)
I'm working on a WPF powered LOB application and I'll possibly build something like this in future.
Implementing a custom panel is not actually that difficult. You have to override two methods, Measure and Arrange. Google for "wpf custom panel" to get some articles about that.
What I would suggest you do to get the behavior exactly as you required in the question is extend Windows.Controls.Grid. Your custom grid could then have two columns by default that you initialize in the constructor and you can programmatically set the Grid.Column and Grid.Row properties on the child controls.
Also worth looking at could be the ItemsControl. It does have support for alternatively colored rows. This example (from MSDN) shows how to use it:
<Grid>
<Grid.Resources>
<Style x:Key="alternatingWithTriggers" TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Blue"/>
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="ListBox.AlternationIndex" Value="1">
<Setter Property="Background" Value="CornflowerBlue"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="ListBox.AlternationIndex" Value="2">
<Setter Property="Background" Value="LightBlue"/>
<Setter Property="Foreground" Value="Navy"/>
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>
<ListBox AlternationCount="3" ItemsSource="{StaticResource data}"
ItemContainerStyle="{StaticResource alternatingWithTriggers}">
</ListBox>
</Grid>
You could then specify a template for the items that includes a Label and a TextBox, but getting this to work could be fiddly.
Here's one final thing I'll suggest:
XAML Powertoys include features that allow you to generate business forms from ViewModels, ViewModels from Models and much more. You might need to modify the source to get alternating row colors though.
Good luck!

How can the ViewModel drive a ControlTemplate?

I have the problem that parts of the TreeView Controltemplate need to change depending on the state of the bound (ItemsSource) ViewModels. For example the little expander icon needs to be exchanged with a different drawing based on each items ViewModel state. Additonally based on the state of each ViewModel the child items need to be arranged horizontally instead of the default vertically.
It sounds like you have to customize ItemsContainerStyle, not ControlTemplate. For example, if you want to mark TreeViewItem as selected whenever underlying ViewModel is selected, you can use the following style:
<TreeView ItemsSource="{Binding ...}
...>
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<!-- IsSelected is a property on ViewModel item -->
<Setter Property="IsSelected" Value="{Binding IsSelected}"/>
<Setter .../>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
If Binding doesn't suit you, you can use Converters, Triggers in Style or ControlTemplate. Furthermore, you can also use triggers in DataTemplates.
PS: Wrote the code from head. May have a typo.

How do I access ListViewItem?

The Items collection of a ListView contains the actual business objects. How do I obtain the corresponding ListViewItem given a business object (SelectedItem)?
If you really need to, use the ListView's ItemsContainerGenerator property. However, you can often get away with not setting an ItemContainerStyle with Bindings:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="IsSelected" Value="{Binding IsSpecial}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
In the above XAML, the ListViewItems will be selected if the underlying bound object's IsSpecial property is true. Selecting/deselecting will update the IsSpecial property.

Resources