WPF - Selected value of combo box inside user control is not binding - wpf

I have reusable user control that contains a textblock and a combo box as shown below:
<UserControl ....>
<TextBlock DockPanel.Dock="Left" x:Name="label">Title:/TextBlock>
<ComboBox x:Name="comboBox" ></ComboBox>
</UserControl>
I have created the following dependency properties in the code behind of this control.
public partial class ctlCombobox : UserControl
{
public static readonly DependencyProperty DisplayMemberPathProperty = DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(ctlCombobox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ctlCombobox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
public static readonly DependencyProperty SelectedIndexProperty = DependencyProperty.Register("SelectedIndex", typeof(int), typeof(ctlCombobox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(ctlCombobox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
public static readonly DependencyProperty SelectedValuePathProperty = DependencyProperty.Register("SelectedValuePath", typeof(string), typeof(ctlCombobox), new FrameworkPropertyMetadata() { BindsTwoWayByDefault = true });
public static readonly DependencyProperty SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(object), typeof(ctlCombobox), new FrameworkPropertyMetadata(OnSelectedValueChanged) { BindsTwoWayByDefault = true });
public ctlCombobox()
{
InitializeComponent();
Binding selectedIndexBinding = new Binding("SelectedIndex") { Source = this, Mode = BindingMode.TwoWay };
Binding itemsSourceItemBinding = new Binding("ItemsSource") { Source = this, Mode = BindingMode.TwoWay };
Binding displayMemberPathBinding = new Binding("DisplayMemberPath") { Source = this, Mode = BindingMode.OneWay };
Binding selectedItemBinding = new Binding("SelectedItem") { Source = this, Mode = BindingMode.TwoWay };
Binding selectedValueBinding = new Binding("SelectedValue") { Source = this, Mode = BindingMode.TwoWay };
Binding selectedValuePathBinding = new Binding("SelectedValuePath") { Source = this, Mode = BindingMode.TwoWay };
comboBox.SetBinding(ComboBox.SelectedIndexProperty, selectedIndexBinding);
comboBox.SetBinding(ComboBox.ItemsSourceProperty, itemsSourceItemBinding);
comboBox.SetBinding(ComboBox.DisplayMemberPathProperty, displayMemberPathBinding);
comboBox.SetBinding(ComboBox.SelectedItemProperty, selectedItemBinding);
comboBox.SetBinding(ComboBox.SelectedValueProperty, selectedValueBinding);
comboBox.SetBinding(ComboBox.SelectedValuePathProperty, selectedValuePathBinding);
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
[Browsable(true)]
public int SelectedIndex
{
get { return (int)GetValue(SelectedIndexProperty); }
set { SetValue(SelectedIndexProperty, value); }
}
[Browsable(true)]
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
[Browsable(true)]
public object SelectedValue
{
get { return (object)GetValue(SelectedValueProperty); }
set { SetValue(SelectedValueProperty, value); }
}
[Browsable(true)]
public string SelectedValuePath
{
get { return (string)GetValue(SelectedValuePathProperty); }
set { SetValue(SelectedValuePathProperty, value); }
}
}
I make reference to the control above in my main control as shown below:
<UserControl Name="mainControl" ...>
<DataGrid Name="lvEmployee" ItemsSource="{Binding Path=Employees, Mode=TwoWay}"
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<cc:ctlCombobox x:Name="cmbEmployeeType"
ItemsSource="{Binding Source={x:Reference mainControl}, Path=DataContext.EmployeeTypes}"
DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding
Path=EmployeeTypeId}" ">
</cc:ctlCombobox>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
I am using the MVVM pattern. I am trying to achieve cmbEmployeeType to be a look up of all possible employee types. Also when an employee is displayed then I want the the cmbEmployeeType to have the appropriate employee type selected. Currently, when load the main Control, the cmbEmployeeType combo box is populated but the nothing is selected in the combo box. I have bounded the combo box to the Employee's employee type id. The user control that contains textboxes that display employee first and last name works fine. There is no binding error in the output. Additionally, there is no issue when I use a plain combo box rather than using my combo box inside user control. Thanks for the response.

I had problems figuring this one out but a solution can be found here

Related

Disable custom WPF control when binding is oneway

I have a custom WPF control (using UserControl as base) that exposes a bindable properties (using DependencyProperty). I want to disable editing in this control when one of the properties is a oneway binding.
public partial class OnOffControl : UserControl
{
...
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(
"IsChecked",
typeof(bool?),
typeof(OnOffControl),
...
public bool? IsChecked
{
get
{
return (bool?)GetValue(IsCheckedProperty);
}
set
{
SetValue(IsCheckedProperty, value);
}
}
Usage point
<DataGridTemplateColumn Width="40" Header="State">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<UIUtil:OnOffControl
IndicatorType="SwitchIndicator"
IsChecked="{Binding Value, Mode=OneWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
So when IsChecked is a oneway binding I want to disable editing in OnOffControl. How does one go about detecting the property binding is OneWay inside of the control and then disable editing?
You may check if there is a Binding and get the Binding's properties in a PropertyChangedCallback:
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register(
nameof(IsChecked),
typeof(bool?),
typeof(OnOffControl),
new PropertyMetadata(IsCheckedPropertyChanged));
public bool? IsChecked
{
get { return (bool?)GetValue(IsCheckedProperty); }
set { SetValue(IsCheckedProperty, value); }
}
private static void IsCheckedPropertyChanged(
DependencyObject o, DependencyPropertyChangedEventArgs e)
{
var control = (OnOffControl)o;
var binding = control.GetBindingExpression(IsCheckedProperty)?.ParentBinding;
var enabled = false;
if (binding != null)
{
enabled = binding.Mode == BindingMode.TwoWay
|| binding.Mode == BindingMode.OneWayToSource;
}
control.IsEnabled = enabled;
}

Cannot update combobox selected index from the view to the viewmodel

Using the MVVM pattern, I've bound the SelectedIndex property of a combo box to a variable in my view model. I can change the combo box selection programmatically from the view model; however, when the user makes a selection from the interface (view), the view model variable is not updated.
Here is the XAML (snipet):
<ComboBox Width="100"
HorizontalContentAlignment="Center"
SelectedIndex="{Binding GroupSortIndex,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ComboBoxItem Content="Appearance"/>
<ComboBoxItem Content="Created"/>
<ComboBoxItem Content="Name"/>
</ComboBox>
Here is a portion of the view model:
public int GroupSortIndex
{
get { return (int)GetValue(GroupSortIndexProperty); }
set { SetValue(GroupSortIndexProperty, value); }
}
public static readonly DependencyProperty GroupSortIndexProperty =
DependencyProperty.Register("GroupSortIndex", typeof(int),
typeof(MainWindowViewModel), new UIPropertyMetadata(-1));
What do I need to do to have GroupSortIndex updated when the user makes a selection from the IU?
yes, The SelectedIndex property looks has a bug. i was this problem and i solved it by changing the SelectedIndex to SelectedItem.
Change XAML SelectedIndex to SelectedItem:
<ComboBox ItemsSource="{Binding Path=YourOptionsList}"
SelectedItem="{Binding SelectedOption}" />
Somewhere you must set the DataContext of your Window to reference the collection from your XAML.
and in your ViewModel write this:
public List<String> YourOptionsList { get { return (int)GetValue(YourOptionsListProperty); } set { SetValue(YourOptionsListProperty, value); } }
public static readonly DependencyProperty YourOptionsListProperty = DependencyProperty.Register("YourOptionsList", typeof(List<String>), typeof(MainWindowViewModel), new UIPropertyMetadata(new List<String>()));
public string SelectedOption { get { return (int)GetValue(SelectedOptionProperty); } set { SetValue(SelectedOptionProperty, value); } }
public static readonly DependencyProperty SelectedOptionProperty = DependencyProperty.Register("SelectedOption", typeof(String), typeof(MainWindowViewModel), new UIPropertyMetadata("none");
public MainWindowViewModel()
{
YourOptionsList =new List<String>();
YourOptionsList.Add("Appearance");
YourOptionsList.Add("Created");
YourOptionsList.Add("Name");
}

Adding a dependency property to a text box

How can I Add a dependency property to a text box and bind the dependency property to a Boolean property in silver light. my Boolean property is in my view model.
ImageSearchIsFocused is the property which allows me to set the focus on a text box.
<TextBox Text="{Binding ImgSearch, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<i:Interaction.Behaviors>
<common:FocusBehavior HasInitialFocus="True" IsFocused="{Binding ImageSearchIsFocused, Mode=TwoWay}" ></common:FocusBehavior>
</i:Interaction.Behaviors>
</TextBox>
ImageIsFocused Property
bool _ImageSearchIsFocused;
public bool ImageSearchIsFocused
{
get { return _ImageSearchIsFocused; }
set
{
_ImageSearchIsFocused = value;
NotifyPropertyChanged("ImageSearchIsFocused");
}
}
If you want to add a dependency property, you're going to have the subclass the TextBox and add the dependency property to your subclass. Then you can bind that to whatever you like:
public class MyTextBox : TextBox
{
public static readonly DependencyProperty MyBooleanValueProperty = DependencyProperty.Register(
"MyBooleanValue", typeof(bool), typeof(MyTextBox),
new PropertyMetadata(new PropertyChangedCallback(MyBooleanValueChanged)));
public bool MyBooleanValue
{
get { return (bool)GetValue(MyBooleanValueProperty); }
set { SetValue(MyBooleanValueProperty, value); }
}
private static void MyBooleanValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var propValue = (bool)e.NewValue;
var control = d as MyTextBox;
// do something useful
}
}

Why can't i bind a DataGrid SelectedItem to a DependencyProperty Inside a usercontrol?

i want to bind a DataGrid SelectedItem inside a user control to a DependencyProperty
and this is my code:
in the user control(DataGridControl):
public static readonly DependencyProperty DataGridSelectedItemProperty
= DependencyProperty.Register(
"DataGridSelectedItem"
, typeof(object)
, typeof(DataGridSelectorControl)
, new UIPropertyMetadata(null));
public object DataGridSelectedItem
{
get { return (object)GetValue(DataGridSelectedItemProperty); }
set { SetValue(DataGridSelectedItemProperty, value); }
}
<DataGrid ItemsSource="{Binding Source={StaticResource theSource}}"
SelectedItem="{Binding ElementName=DataGridControl,Path=DataGridSelectedItem,UpdateSourceTrigger=PropertyChanged}" />
and in the viewmodel:
object projectSelectedItem;
public object ProjectSelectedItem
{
get
{
return projectSelectedItem;
}
set
{
projectSelectedItem = value;
RaisePropertyChanged("ProjectSelectedItem");
}
}
and in view:
<MvvmCommonControl:DataGridControl DataGridSelectedItem="{Binding ProjectSelectedItem}" DataGridDataCollection="{Binding DataCollection}"/>
but it dosen't work!!
You have the following in your user control:
SelectedItem="{Binding ElementName=DataGridControl,
But is you user control named DataGridControl?
<UserControl
...
x:Name="DataGridControl">
In Xaml use the below code
<DataGrid ItemsSource="{Binding Path=Person,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="False" SelectedItem="{Binding Path=SelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
In ViewModel Create property for selected item.Here Customer is class which is having properties like Address,Name,OrderID.
private Customer selectedItem = new Customer();
public Customer SelectedItem
{
get
{ return selectedItem; }
set
{
selectedItem = value;
InvokePropertyChanged("SelectedItem");
}
}
Create one class to define dependency property
class DataGridSelectedItemBehaviour:DependencyObject
{
public static readonly DependencyProperty SelectedItemProperty
= DependencyProperty.Register(
"SelectedItem"
, typeof(object)
, typeof(CustomerViewModel)
, new UIPropertyMetadata(null));
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
}

Setting XAML property value into user control from a consumer view

I have a custom UserControl that contains a grid ...I wish to set the ItemsSource property of that grid by xaml code of of a data template in a resource dictionary...
then I have used dependency property... this is my implementation...
public partial class MyControlGrid : UserControl
{
// Dependency Property
public static readonly DependencyProperty MyItemSourceProperty =
DependencyProperty.Register("MyItemSource", typeof(ICollectionView),
typeof(MyControlGrid), new FrameworkPropertyMetadata(null, OnMyItemSourcePropertyChanged));
IDictionary<string, string> _columns = new Dictionary<string, string>();
private static void OnMyItemSourcePropertyChanged(DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
// When the color changes, set the icon color PlayButton
MyControlGrid muc = (MyControlGrid)obj;
ICollectionView value = (ICollectionView)args.NewValue;
if (value != null)
{
muc.MyGridControl.ItemsSource = value;
}
}
public ICollectionView MyItemSource
{
get
{
return (ICollectionView)GetValue(MyItemSourceProperty);
}
set
{
SetValue(MyItemSourceProperty, value);
//OnTargetPowerChanged(this, new DependencyPropertyChangedEventArgs(TargetPowerProperty, value, value));
// Old value irrelevant.
}
}
public MyControlGrid()
{
InitializeComponent();
}
}
this is the user control xaml code
<UserControl x:Class="GUI.Design.Templates.MyControlGrid"
Name="MyListControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:WpfTkit="http://schemas.microsoft.com/wpf/2008/toolkit"
xmlns:Templates="clr-namespace:Emule.GUI.Design.Templates">
<StackPanel>
<WpfTkit:DataGrid ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Templates:MyControlGrid}}, Path=MyItemSource}"
x:Name="MyGridControl"
<StackPanel>
this is the binding path expression I use
<basic:MyControlGrid MyItemSource="{Binding MyDataContextVisibleCollection}"/>
this dont work and wpf output window dont show me any errors
note that, naturally, if I bind this directly in the user controls work fine
<WpfTkit:DataGrid ItemsSource="{Binding MyDataContextVisibleCollection}"
Waths I wrong?
thanks
p.s. sorry for my english
this
answer show me the way
use of PropertyChangedCallback work fine with my code:
public static readonly DependencyProperty MyItemSourceProperty =
DependencyProperty.Register("MyItemSource", typeof(IEnumerable),
typeof(MyControlGrid), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MyControlGrid.OnItemsSourceChanged)));
alternatively I have to remove comment on OnTargetPowerChanged and fire the property changed event
set
{
SetValue(MyItemSourceProperty, value);
//OnTargetPowerChanged(this, new DependencyPropertyChangedEventArgs(TargetPowerProperty, value, value));
// Old value irrelevant.
}
correct with
public ICollectionView MyItemSource
{
get
{
return (ICollectionView)GetValue(MyItemSourceProperty);
}
set
{
SetValue(MyItemSourceProperty, value);
OnItemsSourceChanged(this, new DependencyPropertyChangedEventArgs(MyItemSourceProperty, value, value));
}
}

Resources