Updating UWP binding programmatically - c#

I've got an issue where if an item is selected in a list I want it to update my items in my grid. The binding is done by:
<ScrollViewer Grid.Row="1">
<ItemsControl x:Name="RightGridItemsControl" ItemsSource="{Binding News}" ItemTemplate="{StaticResource RightGridTemplate}"/>
</ScrollViewer>
When an item, e.g. Planet is selected, I want to update the ItemsSource binding to a new list. This is specified in my DataModel.
How can I update this programmatically? I've tried something like this, but it requires a DependencyObject and can't find out what it means. This also looks like WPF rather than UWP.
`var myBinding = new Binding
{
Source = Planets,
Mode = BindingMode.OneWay,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
};
BindingOperations.SetBinding(new , ItemsControl.ItemsSourceProperty, myBinding);`
What should I put as the first item for the contstructor for 'SetBinding'?

You can set the Binding like this:
BindingOperations.SetBinding(
RightGridItemsControl, ItemsControl.ItemsSourceProperty, myBinding);
or like this:
RightGridItemsControl.SetBinding(ItemsControl.ItemsSourceProperty, myBinding);
Note also that currently there is no property path present in your Binding. If there is a News property as in your XAML, the Binding should probably look like shown below, without Mode = BindingMode.OneWay, which is the default, and without UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, which has no effect in a one-way binding.
var myBinding = new Binding
{
Source = Planets,
Path = new PropertyPath("News")
};

Related

UWP Swipeitem won't see any bindings

For some reason I can't use any binding with a UWP Xaml SwipeItem Control. I've tried it in many different ways and with different SwipeItem properties but every time it is null. What's even stranger is any type of x:Bind to any property and it will crash.
if anyone marks this:
SwipeItem XAML Binding ignored
as a duplicate question it isn't so don't do it or I'll freak out. That question wasn't even answered.
<SwipeControl>
<SwipeControl.LeftItems>
<SwipeItems Mode="Execute">
<SwipeItem Text="{Binding}" Background="{StaticResource MIIGreen}" BehaviorOnInvoked="Close"/>
</SwipeItems>
</SwipeControl.LeftItems>
<SwipeControl.RightItems>
<SwipeItems Mode="Execute">
<SwipeItem Background="{StaticResource MIIRed}" BehaviorOnInvoked="Close" Command="{StaticResource CommandEnclosureNotInstalled}" CommandParameter="{Binding}"/>
</SwipeItems>
</SwipeControl.RightItems>
</SwipeControl>
the DataContext is just a simple DataModel and all other controls are binding fine. the command is from a staticresource and the command is firing just fine. in this example any combination of Binding or x:Bind either does nothing or crashes when trying to bind ANYTHING to Text or CommandParamter properties. There has to be something wrong with SwipItem controls, I need a way to pass the DataContext through the CommandParameter.
SwipeControl is not a standard itemControl, it does not have a dataTemplate, so SwipeItem can't find the DataContext of the parent view, so you can't directly use Binding directly in xaml. It seems you can only use Binding in code.(Below I give example of LeftItems).
in xaml:
<SwipeControl Margin="50" LeftItems="{Binding leftItems}">
</SwipeControl>
in cs:
public SwipeItems leftItems { get; set; }
public MainPage()
{
this.InitializeComponent();
SwipeItem leftItem = new SwipeItem();
Binding myBinding = new Binding();
myBinding.Source = viewmodel;
myBinding.Path = new PropertyPath("MyText"); //the property in viewmodel
BindingOperations.SetBinding(leftItem, SwipeItem.CommandParameterProperty, myBinding);
BindingOperations.SetBinding(leftItem, SwipeItem.TextProperty, myBinding);
Binding commandBinding = new Binding();
commandBinding.Source = new FavoriteCommand(); //command class
BindingOperations.SetBinding(leftItem, SwipeItem.CommandProperty, commandBinding);
leftItems = new SwipeItems() {
leftItem
};
this.DataContext = this;
}

Set binding code behind for the DataTemplate does not work in WPF

I have to bind dynamic the Text property for the TextBlock in the WPF application in the runtime.
Here is the code:
In xaml file
<DataTemplate x:Key="Double_View_Template">
<TextBlock
x:Name="txtDoubleViewTemplate"
HorizontalAlignment="Left"
VerticalAlignment="Center"
/>
</DataTemplate>
In C#
DataTemplate data = FindResource("Double_View_Template") as DataTemplate;
TextBlock ui = data.LoadContent() as TextBlock;
Binding binding = new Binding();
binding.Path = new PropertyPath("Mass");
BindingOperations.SetBinding(ui, TextBlock.TextProperty, binding);
DataGridTemplateColumn column = new DataGridTemplateColumn();
column.CellTemplate = data;
instrumentDataGrid.Columns.Add(column);
When run the application I see only blank lines, and the values are not shown in the Datagrid. The ItemsSource and the DataContext is correctly set.
If I set
Text="{Binding Path=Mass}"
in the xaml the data is displayed.
Any idea why in the runtime the binding is not set?

C# WPF Datacontext Binding dynamic Elements

I have a stackpanel that is filled with dynamic editors. The values inside the editors (TextBoxes, DatePickers, etc) are based on a item from a listbox. I create these editors based on the class and its properties bound to the listbox.
The "rendered" XAML code would something like this:
<StackPanel Name="LeftEditorStack">
<StackPanel Name="OuterPanelFirstname">
<RadioButton Name="FirstnameEnabled"></RadioButton>
<!--or any other possible FrameWorkElement-->
<TextBox></TextBox>
</StackPanel>
</StackPanel>
The TextBox has a databinding that is bound in code behind.
editorBinding = new Binding();
editorBinding.Path = new PropertyPath(String.Format("DataContext.{0}", properties[i].Name));
editorBinding.RelativeSource = new RelativeSource() { Mode = RelativeSourceMode.FindAncestor, AncestorType = typeof(StackPanel), AncestorLevel = 1 };
//editorAttribute is a custom Attribute that contains some information about the type of the Editor, BindingProperty, Position, Size and other stuff
editor.SetBinding(editorAttribute.BindingProperty, editorBinding);
This means the Datacontext of the LeftEditorStack is the real source for the binding of the TextBox. This works fine, but when I change the DataContext of the LeftEditorStack the TextBox does not get the update. The Update is occurs inside of a SelectionChanged Event:
private void lb_left_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.LeftEditorStack.DataContext = null;
this.LeftEditorStack.DataContext = this.lb_left.SelectedItem;
}
How can I get the TextBox to change its value when the DataContext is updated? I can not use UpdateTarget from the BindingExpression because the usercontrol that contains my editors has no direct access to the dynamic editors.
Also setting the BindingMode or the UpdateSourceTrigger did not change this behaviour.
Update
As Grx70 pointed out my AncestorLevel was wrong. After I set the AncestorLevel to 2 it works fine.

Create bindings of ListView items programmatically

I have the following wpf control added to xaml:
<ListView Margin="22,80,271,12" Name="listView1" ItemsSource="{Binding}" />
I know how to create a ListView object programmatically. The only thing that I am missing is how could I add the property
ItemsSource="{Binding}"
with code to that object. I have already managed to add the columns and gridview with c#. The only thing that I am missing is to add that property ItemsSource="{Binding}"
I have tried looking for an answer here.
Shortest should be this (literal translation of XAML):
listView1.SetBinding(ListView.ItemsSourceProperty, new Binding());
listView1.ItemsSource = listView1.DataContext as IEnumerable;
Is this what you are looking for?
Binding myBinding = new Binding();
myBinding.ElementName = "item-you-are-binding-to";
myBinding.Path = new System.Windows.PropertyPath("property-you-are-binding-to");
listView1.SetBinding(ContentProperty, myBinding);
All you need to do is this:
var binding = new Binding("DataContext");
binding.Source = listView1;
listView1.SetBinding(ListView.ItemsSourceProperty, binding);

WPF Binding: Where a property contains the path to the value

I've got an expander with a couple of TextBlocks in the top bar which i'm using to give a title and a piece of key information.
Ideally i want to set the path to key piece of information, but i can't work out how to bind the path of the binding to another path (i apologise if i'm not making much sense!)
In the following xaml the first bit works, the second bit is what i'm struggling with.
<TextBlock Text="{Binding Path=Header.Title}"/>
<TextBlock Text="{Binding Path={Binding Path=Header.KeyValuePath}}"/>
KeyValuePath might contain something like "Vehicle.Registration" or "Supplier.Name" depending on the Model.
Can anyone point me in the right direction please? Any help gratefully received!
I don't think it can be done in pure XAML... Path is not a DependencyProperty (and anyway Binding is not a DependencyObject), so it can't be the target of a binding
You could modify the binding in code-behind instead
I haven't found a way to do this in XAML but I did this in code behind. Here is the approach I took.
Firstly, I wanted to do this for all items in an ItemsControl. So I had XAML like this:
<ListBox x:Name="_events" ItemsSource="{Binding Path=Events}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type Events:EventViewModel}">
<TextBlock Name="ActualText" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Then, in code behind construction I subscribe to the ItemContainerGenerator:
InitializeComponent();
_events.ItemContainerGenerator.StatusChanged
+= OnItemContainerGeneratorStatusChanged;
This method looks like:
private void OnItemContainerGeneratorStatusChanged(object sender, EventArgs e)
{
if (_events.ItemContainerGenerator.Status!=GeneratorStatus.ContainersGenerated)
return;
for (int i = 0; i < _viewModel.Events.Count; i++)
{
// Get the container that wraps the item from ItemsSource
var item = (ListBoxItem)_events.ItemContainerGenerator.ContainerFromIndex(i);
// May be null if filtered
if (item == null)
continue;
// Find the target
var textBlock = item.FindByName("ActualText");
// Find the data item to which the data template was applied
var eventViewModel = (EventViewModel)textBlock.DataContext;
// This is the path I want to bind to
var path = eventViewModel.BindingPath;
// Create a binding
var binding = new Binding(path) { Source = eventViewModel };
textBlock.SetBinding(TextBlock.TextProperty, binding);
}
}
If you only have a single item to set the binding upon, then the code would be quite a bit simpler.
<TextBlock x:Name="_text" Name="ActualText" />
And in code behind:
var binding = new Binding(path) { Source = bindingSourceObject };
_text.SetBinding(TextBlock.TextProperty, binding);
Hope that helps someone.

Categories