Data Binding Label Content to Array - c#

I am somewhat new to WPF and Data Binding, it seems very powerful. I'm wondering if there's a way to have a set of labels, and have there Content property all binded to a different index in array of strings. So then as the array is updated, the labels automatically change too.
The xaml syntax is still a bit foreign to me and I haven't been able to get it to work.

If this is a dynamic set of labels, then you may be better off using an ItemsControl, and changing its ItemTemplate to display a label for each item in the collection that it is bound to (a collection of strings in your case).
Something like:
<ItemsControl ItemsSource="{Binding MyLabelStrings}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Label Content="{Binding}" ... />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
As Bojin mentions, if you wish your UI to update if strings are added/removed from the collection, then use an ObservableCollection for the MyLabelStrings property.

Related

Creating controls dynamically using xaml

I have a list of objects in my application using which I want to create Wrappanels dynamically. One way is to write control adding in code behind as below.
WrapPanel RuleInternalCond = new WrapPanel();
// Create operator combo box and fill all operators
ComboBox operatorCb = new ComboBox();
operatorCb.Items.Add("OR");
operatorCb.Items.Add("AND");
RuleInternalCond.Children.Add(operatorCb);
But is there a better way to create a template of the wrap panel, bind it to my properties and use my collection in xaml to create list of wrap panel templates automatically?
To explain in detail.
I want to create an wrap panel with controls in xaml which bind to properties. But the problem comes if I want a list of these wrap panels to be created dynamically depending on my collection. For eg my collect is
List = new List
where MyRules is
String Name;
String Condition;
I want the List Item to be in WrapPanel with TextBox of Name and Condition
just a code sample for using an ItemsControl. I am assuming you use an object that has those 2 properties and you need to use an ObservableCollection like #XAMIMAX wrote in the comment (ObservableCollection<MyObject> MyList ).
<ItemsControl ItemsSource="{Binding MyList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<WrapPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Condition}"/>
</WrapPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

WPF:Difference between TabControl.ItemTemplate and TabItem.ContentTemplate

I'm confused on this for a long time,these both seem to affect the tabitems' presentation in the tabcontrol.
Is it designed for best control of the presentation of the tabcontrol?
Or if there is something I dont't understand.
There's some very long answers here for what is actually a very simple question. To avoid confusion:
ItemTemplate is the template used to format each item in the ItemsSource to create the headers (the controls that appear in the tab bar) and ContentTemplate is the template used to format each item in the ItemsSource to create the content of the tabs (the controls that appear when you click on the header).
The ItemsControl.ItemTemplate Property is used to define what each item in the data bound collection should look like... from the ItemsControl.ItemTemplate Property page on MSDN:
Gets or sets the DataTemplate used to display each item.
As you can see, it is of type DataTemplate, which is customary for a template that displays data... its DataContext will automatically be set to an item from the collection and so controls declared in that DataTemplate will automatically have access to the items properties. Please see the Data Templating Overview page on MSDN for further help with this.
Similarly, from MSDN, the ContentControl.ContentTemplate Property:
Gets or sets the data template used to display the content of the ContentControl.
Again, its DataContext will automatically be set to the object that is set as the Content property. Please note that the ContentControl only has a ContentTemplate Property and no ItemTemplate Property, which is used for collection items... from the Data Templating Overview page on MSDN:
Because myTaskTemplate is a resource, you can now use it on other controls that have a property that takes a DataTemplate type. As shown above, for ItemsControl objects, such as the ListBox, it is the ItemTemplate property. For ContentControl objects, it is the ContentTemplate property.
UPDATE >>>
To clarify this situation further, think of this simple rule:
Use the ContentTemplate property to define how an object that is set as the Content property of a ContentControl should look.
Use the ItemTemplate property to define how the items of a collection control should look.
That the difference at its simplest. However, I'd like to point out that as these properties are both of type DataTemplate, their values are interchangeable.
For example, let's say that you have a Person class and you display a collection of Person objects in a ListBox. You can declare a DataTemplate to set as the ListBox.ItemTemplate property to define how each Person in the collection should look. However, if you just wanted to display a single Person, then you could use a ContentControl with the Content set to an instance of the Person class, and still use the same DataTemplate, but set as the ContentTemplate instead:
Multiple objects:
<ListBox ItemsSource="{Binding People}" ItemTemplate="{StaticResource Template}" ... />
...
Single object:
<ContentControl Content="{Binding Person}"
ContentTemplate="{StaticResource Template}" ... />
Setting the TabControl.ItemTemplate you specify a template to use for all TabItems in the Items collection of the TabControl, unless you override the TabItem.ContentTemplate for a specific TabItem.
So, while they do the same, TabControl.ItemTemplate is a more generic template for all the TabItems in the TabControl and TabItem.ContentTemplate is specific for the TabItem it is used in.
The above is not quite true, as TabControl has an ItemTemplate property and a ContentTemplate property, to make it more confusing.
ItemTemplate is used as template for the header (the tab thingy) of all TabItems added through databinding on the ItemsSource or through Xaml without making the the added item a TabItem:
<TabControl ItemsSource="{Binding ListOfItems}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Blue"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This will create a TabControl with red text in the header/tab and blue text for content.
Now, if we do the following:
<TabControl>
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Red"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" Foreground="Blue"/>
</DataTemplate>
</TabControl.ContentTemplate>
<TabItem Header="One" Content="One"/>
<TabItem Header="Two" Content="Two"/>
<TabItem Header="Three" Content="Three"/>
</TabControl>
We'll have a TabControl with three tabs, and the header text is black, content is still blue. And a DataError informing us that the ItemTemplate and ItemTemplateSelector properties are ignored for items already of the ItemsControl's container type, in this case TabItem. In this case, we need to specify TabItem.HeaderTemplate to change the appearance of the header.
So TabControl.ItemTemplate and TabItem.ContentTemplate don't do the same, but my previous explanation still holds for TabControl.ContentTemplate and TabItem.ContentTemplate.

Read Text From TextBox in DataGrid MVVM (wpf databinding)

I have a datagrid of rows which contain data read from a web server and values I want to write into a webserver. I write the values in getting the user to input a number into the appropriate column and click an adjacent text box;
<DataGrid x:Name="datagridDERControl" HorizontalAlignment="Center" VerticalAlignment="Center" Background="#FF322D2D" Height="382" Margin="10,78,10,10" Width="972" ItemsSource="{Binding Path=NFDataSource, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Columns>
<DataGridTemplateColumn Width="100" Header="Write Set Point">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Width="100" Text="{Binding Path=WriteSetPoint, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Width="100" Header="Global Trip">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Name="buttonGlobalTrip" Width="100" Click="buttonGlobalTrip_Click"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid
How do I extract the specific textbox string per row to use in my view model.
It's always difficult to answer a question where the relevant details have been omitted by the question author. However, I shall try!
You have data bound (presumably) a collection property named NFDataSource to your DataGrid.ItemsSource property. That is the collection that represents the data in your DataGrid, so to 'extract' a specific value, you need to look into your data items in your collection.
One handy property in the DataGrid class is the SelectedItem property. this enables you to data bind an object (of the same type as those in your NFDataSource collection) to this property, which accesses the data object behind the row that is currently selected in the UI:
<DataGrid ItemsSource="{Binding NFDataSource}" SelectedItem="{Binding SelectedItem}" />
Now you can utilise your SelectedItem property to access the values from the selected row in the DataGrid:
string someValue = SelectedItem.SomeProperty;
As you tagged this with MVVM and databinding, I'll assume you're using these and have just got muddled.
"I have a datagrid of rows which contain data read from a web server
and values I want to write into a webserver."
So your viewmodel has a property, which is a collection of a custom class, that represents data fetched from a webservers.
"I write the values in getting the user to input a number into the
appropriate column and click an adjacent text box"
So this VM property is two-way bound to a datagrid, so that each item in the collection represents 'one row', and the properties on those items represent your 'columns'. The user can make changes to the UI displayed values, and because of the two way databinding the VM property is also updated.
"How do I extract the specific textbox string per row to use in my
view model."
Why do you need the specific textbox string, if it is databound to a property (or rather to a property on a class contained in a collection) in your VM anyway? If you've set up your VM this way, and are using databinding, you rarely need to worry about UI specific things such as which row in a datagrid is clicked.
As Sheridan points out though, you can also bind to properties on the datagrid such as SelectedItem so that you can perform additional operations beyond just reading/writing data. SelectedItem for your datagrid will be of the type that populates your VM collection, so will have the appropriate properties.
For example, if your VM collection is an IQueryable<Person> and that is bound to the ItemsSource of the datagrid then the SelectedItem will be of type Person. You could then have a VM property called SelectedPerson which is bound to that SelectedItem, and access things like SelectedPerson.Name etc.

ListBox of anonymous UIElements

I want to create a ListBox and fill it with anonymous UIElement. In other words, the DataTemplate of the ItemTemplate will contain only one element, and afterwords during the runtime, afterwards I will create in the code behind different UIElements (TextBlocks, Grids ...) and populate the list with it.
So how am I going to write the DataTemplate of the ListBox? And how am I intend to use an ObservableCollection for the ItemSource? So should use an ObsevableCollection of UIElement?
First Question: No DataTemplate. Since your items are already UIElements, you don't need a DataTemplate.
And if you're creating a changeable collection, then yes, ObservableCollection<UIElement> is the way to go.
Now, why would you be doing this? You may want to ask yourself if this is the best way of doing things. Why isn't your data and your presentation separated? If you need more than one type of element in the list, will DataTemplateSelector allow you to have a real ViewModel?
<ListBox x:Name="name" ItemsSource="{Binding source}">
<ListBox.ItemTemplate>
<DataTemplate>
<textbox x:Name="name"></ToggleButton> //or any tool
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

WPF implicit datatemplate with observablecollection

I'm new to WPF and using MVVM. I have a view in which I want to display different content according to what a user selects on a menu. One of those things is another user control Temp which has a view model (TempVM) so I am doing this:
<ContentControl Content="{Binding Path=TempVM}"/>
and TempVM (of type TempViewModel)is null until the user clicks a button. Its data template is this
<DataTemplate DataType="{x:Type vm:TempViewModel}">
<view:Temp />
</DataTemplate>
That's fine, but the other thing I want to do is show a listbox when a user clicks a different menu item. So I am trying to do
<ContentControl Content="{Binding Path=Missions}"/>
(Missions is an observable collection of MissionData) and trying to template it like this:
<DataTemplate DataType="{x:Type ObservableCollection(MissionData)}">
<StackPanel>
<ListBox ItemsSource="{Binding}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
<Button Content="Go"/>
</StackPanel>
</DataTemplate>
But the compiler doesn't like the type reference. If I try doing it by giving the template a key and specifying that key in the ContentControl it works but obviously I see the ListBox and button when there's no Missions. Obviously I could make a user control and viewmodel and follow the same pattern as I did for the TempVM but it seems over the top. Am I going the right way about this and what do I need to do?
From what i see is that you try to use a Collection as a dataobject which is in my opinion bad practice. Having a DataTemplate for a collection is also problematic, like you already have witnessed. I would advice you to use a ViewModel for your missions collection.
class MissionsSelectionViewModel
{
public ObservableCollection<Mission> Misssions;
public MissionData SelectedMission;
public ICommand MissionSelected;
}
and modify your datatemplate to
<DataTemplate DataType="{x:Type MissionsSelectionViewModel}">
<StackPanel>
<ListBox ItemsSource="{Binding Missions}" SelectedItem="{Binding Path=MissionData, Mode=TwoWay}" DisplayMemberPath="MissionName" SelectedValuePath="MissionId" />
<Button Content="Go" Command="{Binding MissionSelected}/>
</StackPanel>
</DataTemplate>
If I were to follow your pattern of implicit templates, I would derive a custom non-generic collection MissionDataCollection from ObservableCollection<MissionData> and use it to keep MissionData items. Then I would simply reference that collection in DataType. This solution gives other advantages like events aggregation over the collection that are useful.
However, it seems to me that the best solution is the following.
Add a IsMissionsListVisible property to your VM.
Bind the Visibility property of the ContentControl showing the list to the IsMissionsListVisible property.
Use a keyed DataTemplate resource.
Implement the logic that determines if IsMissionsListVisible. Supposedly it should be true when there is at least one mission in the selected item. But the logic may be more complex.
I would do it this way. In fact, I do it this way usually, and it gives several benefits. The most important is that I can explicitly control the logic of content visibility in various situations (e.g. async content refresh).

Categories