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.
Related
I have a UserControl MyParentControl which has another control inside (TreeView). I expose this control as a dep property say TreeView MyChildControl.
Then in XAML which uses MyParentConrol I want to access all the TreeView properties, for example Style.
I want to write something like:
<my:MyParentControl>
<my:MyParentControl.MyChildControl.Style>
<Style />
</my:MyParentControl.MyChildControl.Style>
</my:MyParentControl>
Is there a way to achieve that?
By exposing the DependencyProperty for your inner control you have solved half of the problem - ie you can set individual properties in xaml.
The next step is to have those property setters affect the child control.
There are two options to achieve that.
In your control template, define your child control and use Bindings on each property you want to set.
Define a container element in your parent control template and set it's content to your child whenever the dependency property changes.
Although both of these methods could work, you may find that the solution involving the least amount of code, and the greatest amount of flexibility, is to expose a Style property for your child control and apply that in the control template.
public class ParentControl : Control
{
public Style ChildControlStyle
{
get { return (Style)GetValue(ChildControlStyleProperty); }
set { SetValue(ChildControlStyleProperty, value); }
}
public static readonly DependencyProperty ChildControlStyleProperty =
DependencyProperty.Register("ChildControlStyle",
typeof(Style),
typeof(ParentControl),
new PropertyMetadata(null));
}
<Style TargetType="ParentControl">
<Setter Property="ChildControlStyle">
<Setter.Value>
<Style TargetType="ChildControl">
<!-- setters -->
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ParentControl">
<Grid>
<ChildControl Style="{TemplateBinding ChildControlStyle}" />
<!-- other stuff -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
You would get that effect by writing XAML like this:
<my:MyParentControl>
<my:MyParentControl.Resources>
<Style TargetType="my:MyChildControl">
<Setter Property="Background" Value="Red"/>
</Style>
</my:MyParentControl.Resources>
<my:MyParentControl>
In this example, this XAML creates a MyParentControl in which all the children of type MyChildControl have red backgrounds.
I have a panel with a custom ListView. The ListView's items contains a GroupBox. The GroupBox contains a ListView. This ListView's items contains a GroupBox and so on.
All of the controls above have custom templates and styles
There are ToggleButtons in the Controls VisualTree lowest nodes.
When these buttons are checked I need to disable all the panel except of the button was clicked.
I would like to avoid event chaining through the parents in viewModel classes.
I'm using mvvm pattern and I would like to solve it in the xaml side if its possible.
EDIT: Here is a screenshot and the Pick button should disable the panel
Any suggestions are warmly welcomed.
you need to implement the relative source binding something like below.
IsEnabled="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}},Path=IsEnabled}"
Just have a read-only property in your ViewModel that is the negation of the property that your ToggleButton is bound to.
ViewModel:
private Boolean mSourceIsPicked;
public Boolean SourceIsPicked
{
get { return mSourceIsPicked; }
set
{
SetProperty("SourceIsPicked", ref mSourceIsPicked, value);
NotifyPropertyChanged("IsSourceChangeable");
}
}
public Boolean IsSourceChangeable
{
get { return ! this.SourceIsPicked; }
}
Then, in your View, just bind the IsEnabled property of the other controls to that new property.
<ComboBox ItemsSource="{Binding SourceTypes}"
IsEnabled={Binding IsSourceChangeable}" />
The advantage of binding to a property is that you can add/remove controls in your view and just bind to this property without changing additional XAML. You can also change the behavior of any control by not binding to this property.
If you really want a XAML-only solution, you can name each of the controls in the panel, and use a DataTrigger using TargetName on the "SourceIsPicked" property to disable the others:
<ComboBox x:Name="cboSourceTypes" ... />
<ComboBox x:Name="cboSourceNames" ... />
<ToggleButton>
<ToggleButton.Style>
<Style TargetType="{x:Type ToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding SourceIsPicked}" Value="True">
<Setter TargetName="cboSourceTypes"
Property="IsEnabled"
Value="False" />
<Setter TargetName="cboSourceNames"
Property="IsEnabled"
Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
</ToggleButton>
Note that this is all freehand, so you may need to adjust it a bit, but it gives you the idea.
I am having problems getting a databound radiobutton listbox in WPF to respond to user input and reflect changes to the data it's bound to (i.e., to making changes in the code). The user input side works fine (i.e., I can select a radiobutton and the list behaves as expected). But every attempt to change the selection in code fails. Silently (i.e., no exception).
Here's the relevant section of the XAML (I think):
<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}">
<Border Name="theBorder" Background="Transparent">
<RadioButton Focusable="False" IsHitTestVisible="False"
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" >
<ContentPresenter />
</RadioButton>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
I bind the listbox to a List of SchoolInfo objects. SchoolInfo contains a property called IsSelected:
public bool IsSelected
{
get { return isSelected; }
set
{
if( value != isSelected )
{
isSelected = value;
this.OnPropertyChanged("IsSelected");
}
}
}
The OnPropertyChanged() stuff was something I put in during my experimentation. It doesn't solve the problem.
Things like the following fail:
((SchoolInfo) lbxSchool.Items[1]).IsSelected = true;
lbxSchool.SelectedIndex = 1;
They fail silently -- no exception is thrown, but the UI doesn't show the item being selected.
The RadioButton is binding to the ListBoxItem IsSelected property, not to your SchoolInfo IsSelected property.
(It is confusing because ListBoxItem has an "IsSelected" property, and so also does your SchoolInfo object, which is why there were no binding errors).
To fix, ListBoxItem.IsSelected needs to be bound to your SchoolInfo IsSelected property.
i.e. You need an extra setter for the ListBoxItem to bind to SchoolInfo.IsSelected, and then the list box item will work as it should, and also the RadioButton can bind correctly to ListBoxItem.IsSelected.
<Style TargetType="{x:Type ListBoxItem}" >
<Setter Property="IsSelected" Value="{Binding Path=IsSelected}" />
I would enable NotifyOnSourceUpdated in your RadioButton binding. Even though you are allowing a two-way binding (which is the default), notifications won't be picked up from code-behind changes unless you are explicitly listening for them.
<RadioButton Focusable="False" IsHitTestVisible="False"
IsChecked="{Binding Path=IsSelected, RelativeSource={RelativeSource TemplatedParent}, NotifyOnSourceUpdated=True}" >
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.
I working on a WPF project where I've over-ridden the CheckBox control for some special operations. That is working correctly.
My problem is that the ControlTemplate that was applied from the theme (shinyred.xaml from codeplex), is not applied to my over-ridden control. Is there a way to inherit the CheckBox ControlTemplate for use by my new control?
All the samples the I can find are focused on inheriting the style for the CheckBox, but nothing about the ControlTemplate.
No, as you said it is possible to 'inherit' a style by using the BasedOn property, but it's not possible to directly 'inherit' a template. This is understandable though, what would be the semantics of template inheritance? How would the derived template be able to somehow add or change elements in the base template?
With styles it's entirely possible, since you can simply add Setters, Triggers, etc. The only thing that would conceivably be possible with template inheritance is adding Triggers to the base template. However, in that case you'd have to have intimate knowledge of the element names in the base template, and an element name change in the base template could break your derived one. Not to mention an issue with readability, where you refer to a name in your derived template, which is defined somewhere else entirely.
Belated Addition Having said all that, it is possible to resolve your particular problem (although I doubt by now it is still yours, or even a problem). You simply define a style for your control with a setter for the Template property thus:
<Style TargetType="<your type>">
<Setter Property="Template" Value="{StaticResource <existing template resource name>}"/>
</Style>
Keeping in mind what said by #Aviad, the following is a work around:
say you have a Button that define a template that you want to ihnerit, define your CustomButton as Custom Control like this:
public class CustomButton : Button
{
static CustomButton()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomButton), new FrameworkPropertyMetadata(typeof(CustomButton)));
}
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text",
typeof(string), typeof(CustomButton), new UIPropertyMetadata(null));
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
}
Then go to your Generic.xaml and define the following:
<Style
x:Key="CustomButtonStyle" TargetType="{x:Type local:CustomButton}">
<Setter Property="FontSize" Value="18" /> <!--Override the font size -->
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomButton}">
<Button Style="{StaticResource ButtonStyleBase}"
Height="{TemplateBinding Height}"
Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type local:CustomButton}}, Path=Command}"
CommandParameter="{Binding}"
Width="{TemplateBinding Width}">
<Grid>
<StackPanel>
<Image Source="Image/icon.jpg" />
<TextBlock Text="{TemplateBinding Text}"></TextBlock>
</StackPanel>
</Grid>
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Note that the button we want to inherit the template is wrapped inside my new template, and the style is set to the existing button. go the same way with the checkbox and organize the checkbox and label for instance vertically inside the new ControlTemplate of the CustomCheckBox