C# WPF Get Selected Combobox Binding Fields - c#

I have a combo box that has a data template with 3 fields bound from a data table.
The problem I have is I want to find out which item I have selected in the combobox and get access to one of the bound fields.
The SelectedIndex gives me the position but I want the id so I can pass that directly to the Insert method.
You can see below I have 3 fields on for each combo box item.
I would like to identify the primary key for the selected item, "uid"
<ComboBox Name="cboCombo" Width="300" Height="42" TabIndex="3"
ItemTemplate="{StaticResource ComboBoxKey}"
ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True"
SelectedValuePath="uid"
FontSize="12"/>
<DataTemplate x:Key="ComboBoxKey}"">
<Grid Height="35" Width="300" ShowGridLines="false">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0"></ColumnDefinition>
<ColumnDefinition Width="200"></ColumnDefinition>
<ColumnDefinition Width="75"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding uid
Style="{StaticResource txtStyle}"></TextBlock>
<TextBlock Grid.Column="1" Text="{Binding field_1}"
Style="{StaticResource txtStyle}"
TextWrapping="Wrap"></TextBlock>
<TextBlock Grid.Column="2" Text="{Binding field_2}"
Style="{StaticResource txtStyle}"></TextBlock>
</Grid>
</DataTemplate>

I think i've got it:
DataRowView dr = (DataRowView)cboComboBox.SelectedItem;

Related

how to access TextBox inside ListBox itemsSource which is Datatemplate?

I have a ListBox and its ItemsSource is linked with a ComboBox SelectedItem. Its template is associated with a DataTemplate. Everything is fine but how to access each TextBox inside ListBoxItems. I have 5 labels and 2 TextBoxes inside each ListItem. I want to access each and every TextBox and labels inside ListBoxItem. I need some idea how to access each TextBox inside each Item. For example, there is "wbprofileDesc" TextBox in first ListBoxItem. So I need to access this TextBox and write some functionality to it like keypress event. It need to work for each and every TextBox inside all the ListBoxItems individually. Assume there are 5 ListBoxItems. Also I need to fetch other controls also like wbselect(ComboBox), wbdepth, wbwidthvalue and etc. I am using MVVM model for this.
<Window.Resources>
<local:wbItemViewModel x:Key="wbItem"/>
<DataTemplate x:Key="wbObjectsDataTemplate">
<Grid Grid.ColumnSpan="1" Grid.RowSpan="1" Height="Auto" Width="642" Margin="0,0,0,-14">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Width="697" Margin="10,0,0,0" Height="54" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="49*"/>
<ColumnDefinition Width="91*"/>
<ColumnDefinition Width="309*"/>
<ColumnDefinition Width="306*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition/>
<RowDefinition Height="auto" MinHeight="5"/>
</Grid.RowDefinitions>
<Label Content="{Binding WBName_lbl}" Margin="0,3,0,5" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2"/>
<ComboBox x:Name="wbselect" Margin="5,0,10,1" Grid.Column="1" Grid.ColumnSpan="1" Grid.Row="0">
<ComboBoxItem x:Name="wbstraight" IsSelected="True" Content="straight"/>
<ComboBoxItem x:Name="wbtapered" Content="tapered"/>
</ComboBox>
<!--KeyDown="{Binding Path=profileDesc}"-->
<!-- KeyDown="profileDesc_KeyDown" -->
<TextBox x:Name="wbprofileDesc" Margin="18,0,20,1" Grid.Column="2" Grid.Row="0" GotFocus="wbprofileDesc_GotFocus"/>
<TextBox x:Name="wbdepth" Text="{Binding ElementName=wbwidthvalue, Path=Content, Mode=OneWay}" Margin="10,0,73,1" Grid.Column="3" Grid.Row="0"/>
<Label x:Name="wbwidthvalue" Margin="10,0,190,5" Grid.Column="2" FontSize="8" Grid.Row="1"/>
<Label x:Name="wbthicknessvalue" Margin="118,0,82,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wblengthvalue" Margin="208,0,0,5" FontSize="8" Grid.Row="1" Grid.Column="2"/>
<Label x:Name="wbnexwidthvalue" Margin="10,0,178,5" FontSize="8" Grid.Row="1" Grid.Column="3"/>
<Label x:Name="wbdepthvalue" Grid.Row="1" Grid.Column="3" FontSize="8" Margin="132,0,31,5"/>
<!--<Label x:Name="totalvalue" Margin="30,10,24,16" Grid.Row="3" Grid.Column="3"/>-->
</Grid>
</Grid>
</DataTemplate>
</Window.Resources>
<ListBox x:Name="wbListDataTemplate"
ItemsSource="{Binding wbVisibleItems}"
ItemTemplate="{DynamicResource wbObjectsDataTemplate}"
DataContext="{DynamicResource wbItem}"
Background="{x:Null}"
SelectedItem="{Binding wbSelectedItem, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
IsSynchronizedWithCurrentItem="True"
Canvas.Top="51" Height="222" Width="686"/>
Here is an example of you could find the controls in the DataTemplate inside the event handler:
private void wbprofileDesc_GotFocus(object sender, RoutedEventArgs e)
{
TextBox wbprofileDesc = sender as TextBox;
Grid parentGrid = wbprofileDesc.Parent as Grid;
ComboBox wbselect = parentGrid.Children.OfType<ComboBox>().FirstOrDefault(x => x.Name == "wbselect");
Label wbwidthvalue = parentGrid.Children.OfType<Label>().FirstOrDefault(x => x.Name == "wbwidthvalue");
}

TabItem DataTemplate with binding

I have a TabControl in my app. I'd like to have as many TabItems as many entries are in my dictionary.
Here's my dictionary:
public Dictionary<string , ObservableCollection<PerformanceCounter>> Counters
{
get { return _Counters; }
}
Dictionary<string, ObservableCollection<PerformanceCounter>> _Counters = new Dictionary<string , ObservableCollection<PerformanceCounter>>();
Every entry has a string key and ObservableCollection of PerformanceCounter objects. Important thing is the fact that every PerformanceCounter object has properties: CounterName and InstanceName - I'll need these two to display them.
Now, to my XAML:
<TabItem Header="Memory">
<Grid Name="RAMGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Name="RAMListBox" Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" ItemsSource="{Binding Memory, Mode=OneWay}" SelectionMode="Multiple" BorderThickness="1" BorderBrush="#FF8B8B8B" SelectionChanged="RAMListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding CounterName, Mode=OneWay}" />
<Run Text="{Binding InstanceName, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1" Click="RAMSelectAllButton_Click" >
<TextBlock Text="SELECT ALL"/>
</Button>
<Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" Click="RAMUnSelectAllButton_Click" >
<TextBlock Text="UNSELECT ALL"/>
</Button>
</Grid>
</TabItem>
That's what I did and, as you might already know, it does not work. The above code is only for one entry of my dictionary, where the key is "Memory".
In my code I set DataContext:
this.DataContext = appData.Counters;
appData.Counters is that dictionary I presented at the beginning.
Here's what I'd like to achieve:
No matter how many entries there are in my dictionary, my TabControl would display TabItem for each of them.
Each TabItem has a ListBox and 2 buttons. I'll need too be able to access those (in order to clear the list and to have click event for each button).
I really don't know how to do it, I hope you can help me out.
Binding TabControl to items in Dictionary:
<Window.Resources>
<DataTemplate x:Key="templateForTheContent" >
<StackPanel>
<ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
ItemsSource="{Binding Value, Mode=OneWay}"
SelectionMode="Multiple"
BorderThickness="1" BorderBrush="#FF8B8B8B">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding CounterName, Mode=OneWay}" />
<Run Text="{Binding InstanceName, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" >
<TextBlock Text="{Binding Key}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl TabStripPlacement="Left" VerticalAlignment="Stretch" HorizontalContentAlignment="Stretch"
ItemsSource="{Binding Counters}"
ContentTemplate="{StaticResource templateForTheContent}"
ItemTemplate="{StaticResource templateForTheHeader}">
</TabControl>
</Grid>
Now, Dictionary is not observable so if items will be added/removed during runtime, you may consider using something like ObservableDictionary instead
Create a ViewModel-class containing:
your Dictionary
two ICommand-Implementations for your Buttons
then
set the ViewModel-class as DataContext of the TabControl
set Counters as the ItemSource of the TabControl
reuse your XAML-Code defined within the TabItem and use it as
the Tabcontrol.ContentTemplate
Bind .Command of your Buttons to the ICommands in your ViewModel using RelativeSource
see for samples:
ContentTemplate: https://wpf.2000things.com/tag/tabcontrol/
ICommand https://stackoverflow.com/a/1468830/4919708
RelativeSource: https://stackoverflow.com/a/84317/4919708
As i said in one of the comments above I changed my Dictionary to this:
//list of all counters
public ObservableCollection<ObservableCollection<PerformanceCounter>> Counters
{
get { return _Counters; }
}
ObservableCollection<ObservableCollection<PerformanceCounter>> _Counters = new ObservableCollection<ObservableCollection<PerformanceCounter>>();
i used #Arie's solution to write this XAML:
<DataTemplate x:Key="templateForTheContent" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0"
ItemsSource="{Binding}"
SelectionMode="Multiple"
BorderThickness="1" BorderBrush="#FF8B8B8B">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Run Text="{Binding CounterName, Mode=OneWay}" />
<Run Text="{Binding InstanceName, Mode=OneWay}" />
</TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="RAMSelectAllButton" Margin="0,10,0,0" Grid.Column="0" Grid.Row="1" >
<TextBlock Text="SELECT ALL"/>
</Button>
<Button Name="RAMUnSelectAllButton" Margin="0,10,0,0" Grid.Column="1" Grid.Row="1" >
<TextBlock Text="UNSELECT ALL"/>
</Button>
</Grid>
</DataTemplate>
<DataTemplate x:Key="templateForTheHeader" >
<TextBlock Text="{Binding CategoryName}"/>
</DataTemplate>
</Window.Resources>
It displays correctly as many Tabs as I add entries to my Class ObservableCollection in the code behind.
Now i have a new problem: I don't know how to access each listBox from each Tab. i need to be able to read the list of selected objects.

Checkbox in ItemTemplate

I have a <Checkbox/> in my <GridView.ItemTemplate>. How do I handle the <Checkbox/> as to the element in which it is?
For example, I want to delete item when checkbox checked.
I think should write here. But what?
private void CheckBox_Checked_1(object sender, RoutedEventArgs e)
{
}
Here's My XAML:
<GridView Margin="0,10,0,0"
RelativePanel.AlignHorizontalCenterWithPanel="True"
x:Name="GridColections"
IsItemClickEnabled="True"
SelectionMode="None"
ItemsSource="{x:Bind DS.AllRem, Mode=OneWay}"
ItemClick="GridColections_ItemClick" >
<GridView.ItemTemplate>
<DataTemplate x:DataType="local:GetRem" >
<Grid Margin="-2,0,-6,0" BorderBrush="LightGray" BorderThickness="1" HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="40" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Stretch" TextWrapping="Wrap" Text="{x:Bind ReminderName}" Margin="5,5,0,0" FontSize="20"/>
<TextBlock TextTrimming="CharacterEllipsis" Grid.Column="0" Grid.Row="1" Width="600" TextWrapping="Wrap" Text="{x:Bind ReminderDescription}" Margin="5,5,0,0" FontSize="12"/>
<CheckBox Grid.Column="2" Grid.Row="0" Grid.RowSpan="2" VerticalAlignment="Center" Checked="CheckBox_Checked_1"/>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
The problem is that you almost certainly want to be able to use the DataContext in your click handler but you won't get that easily by just having a reference to the CheckBox which will be the sender argument in your callback. Normally what you would do here is create a Command on your item's view model and bind to that and any additional information that you would want to pass in you would pass in through the CheckBox's CommandParameter.
Once you do this you are now operating in your view model with a reference to whatever piece of information that you need through the command parameter (for instance you could set CommandParameter = "{Binding}" to pick up the entire data context which would be the item's view model and that would be accessible from your Command as an argument to it). You should be able to solve your issue this way.

TargetUpdated does not work

I have a ListBox that is defined like this
<ListBox ItemsSource="{Binding List, ElementName=UI}" x:Name="listBox" SelectionChanged="listBox_SelectionChanged" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="grid1" Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding ItemId}"/>
<TextBlock Grid.Column="1" Text="{Binding Message, NotifyOnTargetUpdated=True}" TargetUpdated="TextBlock_TargetUpdated"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The app has a search feature, that allows the user to search for certain text (also a substring) in the list (in column 1, which is bound to 'Message').
The matched substring shall be highlighted as bold or italic.
I'm planning to use the inline feature of the TextBlock. Therefore I want to use the TargetUpdated callback to parse the contend of the TextBlock to insert e.g. Bold() or Italic().
My problem is, that the CallBack function TextBlock_TargetUpdated is not called.
Any idea why?
I realized, that I was missing a NotifyPropertyChanged("Message"); in the class that represents the data in the attached list.

How to Add dynamic control instead of static control?

I have a collection with fields cityname, statename and countryname and I bind that collection to my wpf form. I want to display the cityname in a Textbox, the statename in a combobox and the countryname in a combobox. All the textboxes and comboboxes should come dynamically. How can I do this job?
Any one suggest me how to design this form dynamically in wpf using MVVM I am trying to do this code but not get result properly. Either I get everything as textbox or combobox, but what i need is textbox and combobox as specified.
<Border Margin="3.5">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="125" />
<ColumnDefinition Width="*" MinWidth="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Name="tbFieldTag" Cursor="Hand" VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" Margin="10,0,0,0" Text="{Binding Path=CardField.FieldTag}" />
<TextBox Margin="10,0,0,0" x:Name="txtFieldData" Grid.Column="1" MaxLength="{Binding Path=CardField.MaximumLength}" Text="{Binding Path=CardField.FieldData, Mode=TwoWay}" />
<!--<ComboBox Margin="10,0,0,0" x:Name="comboFieldData" Grid.Column="1" Text="{Binding Path=CardField.FieldTag}"/>-->
</Grid>
</Border>
The key to your problem are DataTemplates. These allow you to bind your view to a collection of custom objects.
You should have a ViewModel that is exposing an ObservableCollection<TLocation> where TLocation is a class that is exposing public properties Cityname, Statename and Countryname.
In your View you need to show a ContentControl, say a ListBox, having it's ItemSource property bound to the ObservableCollection.
Then you set the DataTemplate for the Listbox to something like:
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding Path=CityName}" />
<ComboBox Text="{Binding Path=StateName}" />
<ComboBox Text="{Binding Path=CountryName}" />
</StackPanel>
</DataTemplate>
Another approach is to use a DataGrid. See this article

Categories