UserControl's DataContext update WPF - wpf

I have my own usercontrol named FlashControl in the mainwindow. I set the DataContext by following code in the mainwondow
(FlashControl.Content as FrameworkElement).DataContext = null;
(FlashControl.Content as FrameworkElement).DataContext = this.DataContext;
FlashControl.DataContext = this.DataContext;
My problem is whenever my datacontext change I need to call the above code to reset usercontrol's datacontext. Why Usercontrol's DataContext not updated automatically when main DataContext change? How to do automatic update? Am I missing something?

If you want automatic update dont set DataContext directly but Bind it to the value you want.
You should bind in xaml but if you want to do in code behind then you can do:
Binding myBinding = new Binding("DataContext");
myBinding.Source = this;
BindingOperations.SetBinding(FlashControl, FrameworkElement.DataContextProperty, myBinding);

Related

Update data binding by Enter Key in code behind WPF

I have a FrameworkElementFactory works like a textbox created in the code, so there is no xaml code, and also I set this textbox with data binding in code. Now I want to update this textbox databinding by Enter key pressed. I have read one way for attached behavior in this Link, but it seems working with xaml code. Is there any way to set attached behavior in code behind?
ListBox DDF_List = new ListBox();
FrameworkElementFactory Editable_TextBox = new FrameworkElementFactory(typeof(TextBox));
Binding text_binding = new Binding("Value");
Editable_TextBox.SetBinding(TextBox.TextProperty, text_binding);
DataTemplate Text_Layout = new DataTemplate();
Text_Layout.VisualTree = Editable_TextBox;
DDF_List.ItemTemplate = Text_Layout;
You should almost certainly be doing this with a DataTemplate in XAML. What you've got is a prefect case for doing everything in XAML. But if you're committed to doing it the hard way, here's how.
With your FrameworkElementFactory, you can set it like any other dependency property on a FrameworkElementFactory:
Editable_TextBox.SetValue(
InputBindingsManager.UpdatePropertySourceWhenEnterPressedProperty,
TextBox.TextProperty);
More generally, here's now to apply that attached property to a TextBox in C#, where itemNameTextBox is the TextBox:
InputBindingsManager.SetUpdatePropertySourceWhenEnterPressed(itemNameTextBox,
TextBox.TextProperty);
With attached properties, this C#:
var itemNameTextBox = new TextBox { Name = "itemNameTextBox" };
var binding = new Binding("ItemName")
{
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
itemNameTextBox.SetBinding(TextBox.TextProperty, binding);
// This is the line you're asking for:
InputBindingsManager.SetUpdatePropertySourceWhenEnterPressed(itemNameTextBox,
TextBox.TextProperty);
Is an exact equivalent of this XAML:
<TextBox
Name="itemNameTextBox"
Text="{Binding Path=ItemName, UpdateSourceTrigger=PropertyChanged}"
b:InputBindingsManager.UpdatePropertySourceWhenEnterPressed="TextBox.Text"
/>

WPF: Avoid CustomCombobox to fire SelectedItem Binding when changing ItemsSource to CompositeCollection

I have a Custom Control derived from a ComboBox where I use a CompositeCollection to "merge" the original ItemsSource with additional Objects.
The problem is, that
CompositeCollection comp = new CompositeCollection();
SomeLogic();
ItemsSource = comp;
Setting the ItemsSource to the composed Collection is setting SelectedItem to null and invoke the Binding TwoWay Binding to the ViewModel. The SelectedItem bound property in my ViewModel will then be 'null'.
I am currently workarounding this by restoring the SelectedItem after assigning the ItemsSource:
Object priorSelectedItem = SelectedItem;
ItemsSource = comp;
SelectedItem = priorSelectedItem;
However this just fixes the value of SelectedItem in my ViewModel, a nasty sideeffect is that the when the Object changes some logic is run in the Setter. E.G. setting a
_dataHasChanged = true;
Flag.
So if there is any way I can
a) Prevent the SelectedItem to get reset whilst changing the ItemsSource
or
b) Prevent the SelectedItem-Binding to be Invoked whilst changing the ItemsSource
from within the Custom Control (Don't want to take care of 20 ViewModels because there is a flaw in the Control) I would greatly appreciate any input on how to do so :-)
I've managed to prevent this behavior by saving the SelectedItem-Binding in a private variable in OnApplyTemplate(), then clearing it and Set it back to the variable value after the new ItemsSource has been applied.
private Binding _selectedItemBinding;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_selectedItemBinding = BindingOperations.GetBinding(this, ComboBox.SelectedItemProperty);
BindingOperations.ClearBinding(this, ComboBox.SelectedItemProperty);
if (BindingOperations.IsDataBound(this, ComboBox.SelectedItemProperty))
this.SetBinding(ComboBox.SelectedItemProperty, "dummy");
...
}
private void AdaptItemSource()
{
Object priorSelectedItem = SelectedItem;
ItemsSource = comp;
SelectedItem = priorSelectedItem;
BindingOperations.SetBinding(this, ComboBox.SelectedItemProperty, _selectedItemBinding);
}
This did the Trick for me

Databind Combobox in WPF

I'm trying to databind a combobox in WPF for the first time and I can't get it to happen.
The image below shows my code, can you please tell me what I am missing? I only want graphic stuff in the xaml.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Patient p = new Patient();
this.cbPatient.DataContext = p.SelfListAll();
this.cbPatient.DisplayMemberPath = "Name";
this.cbPatient.SelectedValuePath = "PatientIDInternal";
}
...
Short explanation: Just make the following change to your XAML:
<ComboBox ItemsSource="{Binding Path=patientList}" />
Then, in your Window_Loaded event handler, just add
this.DataContext = this
Then make a new member called patientList of type ObservableCollection<Patient>.
Long explanation:
You don't have a binding set up. You need to create one through XAML like this:
<ComboBox ItemsSource="{Binding Path=patientList}" />
Then, the combobox will look for a member or property called "patientList" on the object that is set as its DataContext. I'd recommend using an ObservableCollection for patientList.
Alternatively, to create one in code, you can follow the examples here:
http://msdn.microsoft.com/en-us/library/ms752347.aspx#specifying_the_binding_source
Binding myBinding = new Binding("patientList");
myBinding.DataContext = someObject; //whatever object has 'patientList' as a member
mycombobox.SetBinding(ComboBox.ItemsSourceProperty, myBinding);
This will set a binding on the mycombobox ComboBox with a path of patientList and a DataContext of someObject. In other words, mycombobox will show the contents of someObject.patientList (which would ideally be some ObservableCollection, so that updates to the collection notify the binding to update).
You need to actually add the binding, e.g.:
Binding binding = new Binding();
binding.Source = MySourceObject;
binding.Path = new PropertyPath("MyPropertyPath");
binding.Mode = BindingMode.OneWay;
BindingOperations.SetBinding(cbPatient, SomeDependencyProperty, binding);
Ok, here is the answer to how to populate a combobox in WPF. First, thanks to everyone above who made suggestions. The part I was missing was that I was not populating the ItemsSource property but the DataContext property. Again, thanks to everyone for their help.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Patient p = new Patient();
this.cbPatient.ItemsSource = p.SelfListAll();
this.cbPatient.DisplayMemberPath = "Name";
this.cbPatient.SelectedValuePath = "PatientIDInternal";
this.cbPatient.SelectedIndex = 0;
}
You need to set the ItemsSource property relative to the DataContext:
cbPatient.SetBinding(ItemsSourceProperty, new Binding());
EDIT
The ItemsSource property of the ComboBox is the property that should point to the collection of items to be shown.
The collection you are interested in, is in the DataContext.
The Binding is an object that keeps track of changes of the collection and reports them to the ComboBox and its Path is relative to the object in the DataContext.
Because the Binding also needs to know the ComboBox you use the static SetBinding method that ties the connection between ComboBox and the Binding.
As in your code the collection itself is in the DataContext, the Path is empty.
The ItemsSource property should point to the collection of Patients. Because the collection of Patients is already in the DataContext, the Binding's Path property is empty.
Suppose an class named Hospital has two properties: Patients and Docters (and perhaps more: Rooms, Appointments, ...) and you set the DataContext of the ComboBox to an instance of Hospital. Then you would have to set the Binding's Path Property to "Patients"
Now the ComboBox will display each item (Patient) in the collection. To specify how a single Patient should be displayed you need to set the ItemTemplate property of the ComboBox.

Silverlight Behavior: DataContext of AssociatedObject changes

I've written an Interactivity Behavior (from Blend SDK) , which can be attached to a DataGrid, and does some magic with the DataGrid's columns based on the ViewModel in the DataContext of the DataGrid.
Since the DataContext can be set later, I have to listen for DataContext changes in the behavior. So, I've bound a DependencyProperty to the Associated DataGrid's DataContext, like this:
BindingOperations.SetBinding(this, SourceProperty, new Binding("DataContext") { Source = AssociatedObject });
This line is hit, so the binding does happen.
Now the tricky part:
if I call
datagrid.DataContext = new MyViewModel();
everything works perfectly. But, if the datagrid is contained in some UserControl (not necessarily its immediate child) and I want to call
this.DataContext = new MyViewModel();
the callback of the Source property DOESN'T fire. I debugged it, the datagrid.DataContext is set, so the DataContext is inherited through the visual tree, as it should be, if I manually call update on the behavior, it does see the DataContext, but nothing happens automatically.
I don't want to name the DataGrid instance, I don't want to name the behavior, since there can be any number of those in one UserControl, I want to set the UserControl's DataContext and let the DependencyProperty system work its magic.
What am I doing wrong?
Have you tried something simpler:-
BindingOperations.SetBinding(this, SourceProperty, new Binding());
This should give you the DataContext object. A binding without a Path returns the source object. A binding without an explicit Source returns the current DataContext.
The question is does does the DataContext of this (the behaviour) aquire its value from the DataGrid to which its attached? I think it probably does.

Update all bindings in UserControl at once

I need to update all the bindings on my UserControl when its visibility changes to Visible. Pretty much all my bindings are bound to the DataContext property of the user control so I'm trying to update the target of that binding:
BindingOperations.GetBindingExpressionBase(this, UserControl.DataContextProperty).UpdateTarget();
But I get null as the result of GetBindingExpression(..) method and I'm wondering if I'm using this wrong.
Also, is there any other good way to refresh all bindings on the control (which use DataContext as the source).
Well, you could just re-assign the DataContext:
var dataContext = DataContext;
DataContext = null;
DataContext = dataContext;
FYI, resetting the property to its value (i.e.DataContext = DataContext) won't work.
You're using the BindingOperations.GetBindingExpressionBase method on the wrong property. You have to use it on the properties which are binding to the DataContext property, not the DataContext property itself.

Resources