i have class created for data retrieval
I have XAML code with gridview and cs code which connects to SQL webservice and i can get data from SQL :-)
my gridview has
textblock - data from sql table
checkbox
textbox
I would like to have some actions on the checkbox and textboxes. How do I get my textboxes to become visible upon checkbox click?
I have got this code working in other apps without gridviews, but I can't get it to work here. how do I reference the event_handler inside the gridview
XAML example
<GridView x:Name="GreenQuestionGridView" ItemsSource="{Binding}" Background="Green" Margin="0,40,0,0">
<GridView.ItemTemplate>
<DataTemplate>
<Grid Height="40" Width="600" >
<StackPanel Orientation="Horizontal">
<TextBlock Width="200" VerticalAlignment="Bottom" TextWrapping="Wrap" Text="{Binding question_green}" />
<CheckBox x:Name="chkBox" Checked="chkBox_Checked" Unchecked="chkBox_Unchecked" Indeterminate="chkBox_Indeterminate" VerticalAlignment="Bottom" IsThreeState="True" />
<TextBox x:Name="txtBox" Visibility="Collapsed" Width="200" VerticalAlignment="Bottom" />
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
here is code that works in other app, but this needs to reference the gridview
private void chkBox_Checked(object sender, RoutedEventArgs e)
{
if (chkbox.IsChecked == null)
{
txtbox.Visibility = Visibility.Visible;
}
else
{
txtbox.Visibility = Visibility.Collapsed;
}
}
For the CheckBox you need also the event CheckBox_Unchecked to hide it again.
<CheckBox Unchecked="CheckBox_Unchecked" Checked="CheckBox_Checked" ... />
IsChecked is a nullable type you didnt even checked if it's true. Your code will hide the txtbox so long as the IsChecked is not null.
private static void ToggleTextBoxVisibility(object sender) {
if(!(sender is CheckBox)) {
return;
}
CheckBox checkBox = sender as CheckBox;
foreach(var child in ((checkBox.Parent as StackPanel).Children)) {
if(!(child is TextBox)) {
continue;
}
TextBox textBox = child as TextBox;
if(checkBox.IsChecked.HasValue && checkBox.IsChecked.Value) {
textBox.Visibility = Visibility.Visible;
} else {
textBox.Visibility = Visibility.Collapsed;
}
}
}
private void CheckBox_Checked(object sender, RoutedEventArgs e) {
ToggleTextBoxVisibility(sender);
}
private void CheckBox_Unchecked(object sender, RoutedEventArgs e) {
ToggleTextBoxVisibility(sender);
}
A clean solution would be to control it with a binding to a property in your viewmodel.
Related
I have datagrid. One column is with button:
<DataGrid x:Name="WordsDataGrid" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
AutoGenerateColumns="False" CellEditEnding="WordsDataGrid_CellEditEnding">
<DataGrid.Columns>
<DataGridCheckBoxColumn Header="X" Width="10" Binding="{Binding Status}"/>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Visibility="Visible" Height="16" Width="16" Click="Update_Click">
<Button.Content>
<Image x:Name="KeyName" Source="Resources/update.png" />
</Button.Content>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I have other columns with textbox create dynamic in c#.
I want to change image for my button when catch event:
private void WordsDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var column = e.Column.DisplayIndex;
var row = e.Row.GetIndex();
}
I know row and column but I dont know how to take my button from WordsDataGrid to do:
button.Content = new Image
{
Source = new BitmapImage(new Uri(#"/Resources/toupdate.png", UriKind.Relative))
};
Edit:
I add
Source="{Binding ImageSource}" />
public string ImageSource { get; set; } = #"\Resources\update.png";
First to xaml, secound to object, and I change string.
I you want to do this on click of your button,
You can use click event of your button :
private void Update_Click(object sender, EventArgs e)
{
(sender as Button).Content = new Image
{
Source = new BitmapImage(new Uri(#"/Resources/toupdate.png", UriKind.Relative))
};
}
If from another cell of your datagrid :
WPF DataGrid: How do I access a ComboBox in a specific row of a DataGridTemplateColumn?
You should bind the Source property of the Button to a source property of your data object and set this property instead of trying to manipulate the UI elements:
private void WordsDataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
var index = ...;
var itemsSource = WordsDataGrid.ItemsSource as IList<YourClass>;
itemsSource[index].Uri = new Uri(#"/Resources/toupdate.png", UriKind.Relative);
}
XAML:
<Image x:Name="KeyName" Source="{Binding Uri}" />
Make sure that YourClass implements INotifyPropertyChanged and raise change notifications.
I want to make this as, once i select the first item(Student Information) of the first_ComboBox want to appear second_ComboBox.
How can I make this happen
In the cs code
private void first_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
private void second_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
}
in XAML
<StackPanel Margin="97,47,171,499" Orientation="Horizontal" Grid.Row="1">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Where You want to Control" VerticalAlignment="Top" Height="82" Width="463" FontSize="36"/>
<ComboBox x:Name="first_ComboBox" HorizontalAlignment="Left" VerticalAlignment="Top" Width="560" Height="42" SelectionChanged="first_ComboBox_SelectionChanged">
<x:String>Student Information</x:String>
<x:String>Staff Information</x:String>
<x:String>Academic Information</x:String>
</ComboBox>
</StackPanel>
<StackPanel Margin="97,172,171,374" Orientation="Horizontal" Grid.Row="1">
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="Select the Field" VerticalAlignment="Top" Height="82" Width="463" FontSize="36"/>
<ComboBox x:Name="second_ComboBox" HorizontalAlignment="Left" VerticalAlignment="Top" Width="560" Height="42" SelectionChanged="second_ComboBox_SelectionChanged">
<x:String>Student Name</x:String>
<x:String>Student Address</x:String>
</ComboBox>
</StackPanel>
On your Form main, you can set the visibility of Second Combobox to be false, and then on the first combobox selection changed set it to true, Something like this
public MainWindow()
{
InitializeComponent();
second_ComboBox.Visibility = Visibility.Collapsed;
}
private void first_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var selecteditem = first_ComboBox.SelectedItem as string;
if (selecteditem != null)
{
second_ComboBox.Visibility = Visibility.Visible;
}
}
on initialization make second combobox visiblity hidden
public MainWindow()
{
InitializeComponent();
second_ComboBox.Visibility = Visibility.Collapsed;
}
private void first_ComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
first_ComboBox.Visibility = System.Windows.Visibility.Visible;
}
In my wp8 app i have checkbook in list box and i want to be able to tap check-box when is-enabled is false.i mean i want to tap check box but is-checked shouldn't change
<ListBox Name="URLListBox" Height="Auto" Grid.Row="2" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Transparent" Margin="0,0,0,10" >
<CheckBox IsChecked="{Binding file}" x:Name="surename" Tag="{Binding b1Tag}" Grid.Column="0" FontSize="25" Content="{Binding text}" Tap="surename_Tap" VerticalAlignment="Center" HorizontalAlignment="Center"></CheckBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
You could make by declaring that CheckBox inside Listbox and tick the CheckBox on Listbox tap event. Like this,
<ListBox Name="listBox" Tap="listBox_Tap">
<CheckBox Content="sample" IsEnabled="False" Name="checkBox" />
</ListBox>
And tick the CheckBox in ListBox tap event.
private void listBox_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
checkBox.IsChecked = true;
}
If you have several CheckBox inside that ListBox, get a SelectedIndex in ListBox tap event and change that CheckBox Value. In your case you could refer from the following code, In xaml,
<ListBox Grid.Row="1" Tap="RoleslistBox_Tap" Name="RoleslistBox">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsEnabled="False" Content="{Binding RoleTypes}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And in RoleslistBox tap event, you could write,
private void RoleslistBox_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
int i = RoleslistBox.SelectedIndex;
ListBoxItem item = this.RoleslistBox.ItemContainerGenerator.ContainerFromIndex(i) as ListBoxItem;
CheckBox tagregCheckBox = FindFirstElementInVisualTree<CheckBox>(item);
tagregCheckBox.IsChecked = true;
}
private T FindFirstElementInVisualTree<T>(DependencyObject parentElement) where T : DependencyObject
{
var count = VisualTreeHelper.GetChildrenCount(parentElement);
if (count == 0)
return null;
for (int i = 0; i < count; i++)
{
var child = VisualTreeHelper.GetChild(parentElement, i);
if (child != null && child is T)
{
return (T)child;
}
else
{
var result = FindFirstElementInVisualTree<T>(child);
if (result != null)
return result;
}
}
return null;
}
I have a ComboBox that displays strings. How can I add an option to remove some items from the ComboBox list? I tried:
<ComboBox.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Click="MenuItem_OnClick"></MenuItem>
</ContextMenu>
</ComboBox.ContextMenu>
But I don't know how to locate the item the user chose:
private void MenuItem_OnClick(object sender, RoutedEventArgs e) {
/* ... ??? ... */
}
I don't mind putting some icon next to each item, that removes its related item when clicked, but don't know how to do it..
Summary:
This is how I solved it, finally (The credit belongs to Nawed Nabi Zada, who provided the main idea of "climbing" using the VisualTreeHelper.GetParent(...) to get the ComboBoxItem, in the accepted answer, below)
<ComboBox IsEditable="True" Name="RemotePathComboBox" VerticalAlignment="Center"
SelectionChanged="RemotePathComboBoxOnSelectionChanged"
Grid.Column="1" Margin="0,6" KeyUp="HostNameOrIPAddress_OnKeyUp">
<ComboBox.ItemTemplate>
<DataTemplate>
<DockPanel>
<Button Click="RemoveRemotePathItem_Click" Margin="5" DockPanel.Dock="Left">
<Image Source="{Binding Converter={StaticResource iconExtractor}, ConverterParameter=%WinDir%\\System32\\shell32.dll|131}"/>
</Button>
<TextBlock Name="ItemTextBlock" VerticalAlignment="Center" Text="{Binding Path=Path}"></TextBlock>
</DockPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Code-behind:
private void RemoveRemotePathItem_Click(object sender, RoutedEventArgs e) {
var depObj = sender as DependencyObject;
while (!(depObj is ComboBoxItem)) {
if (depObj == null) return;
depObj = VisualTreeHelper.GetParent(depObj);
}
var comboBoxItem = depObj as ComboBoxItem;
var item = comboBoxItem.Content as RemotePathItem;
_remotePathsList.Remove(item);
RemotePathComboBox_SelectIndexWithoutChangingList(0);
}
(The "Icon Extractor" that fetches the icon from the system's DLL is from an old post of mine)
You can also do it this way:
<Window x:Class="RemoveItemsFromComboBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox x:Name="CbxItems" VerticalAlignment="Top" HorizontalAlignment="Left" Width="250">
<ComboBox.ContextMenu>
<ContextMenu>
<MenuItem x:Name="MenuItem" Header="Delete" Click="MenuItem_OnClick"></MenuItem>
</ContextMenu>
</ComboBox.ContextMenu>
<TextBlock Text="Item 1"/>
<TextBlock Text="Item 2"/>
<TextBlock Text="Item 3"/>
<TextBlock Text="Item 4"/>
</ComboBox>
</Grid>
public partial class MainWindow
{
public MainWindow()
{
InitializeComponent();
CbxItems.PreviewMouseRightButtonDown += OnPreviewMouseRightButtonDown;
}
private void OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
var comboBoxItem = VisualUpwardSearch(e.OriginalSource as DependencyObject);
if (comboBoxItem == null) return;
comboBoxItem.IsSelected = true;
e.Handled = true;
}
private ComboBoxItem VisualUpwardSearch(DependencyObject source)
{
while (source != null && !(source is ComboBoxItem))
source = VisualTreeHelper.GetParent(source);
return source as ComboBoxItem;
}
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
{
CbxItems.Items.Remove(CbxItems.SelectedItem);
}
}
Put that ContextMenu for each ComboBoxItem instead of the ComboBox itself :
<ComboBoxItem.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove" Click="MenuItem_OnClick"></MenuItem>
</ContextMenu>
</ComboBoxItem.ContextMenu>
You can also put that in DataTemplate or generate it from code behind, depending on how you populate the ComboBox. Then in menu item's click event handler you can do as follow to get user chosen ComboBoxItem :
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
{
var menuItem = (MenuItem)sender;
var ctxMenu = (ContextMenu)menuItem.Parent;
var comboBoxItem = (ComboBoxItem) ctxMenu.PlacementTarget;
}
For locating the combobox items, you can use checkbox in the item template of the combobox so that user can check the items which he/she wants to delete.
If your combobox is data bound, then you will have to filter the datasource of your combobox i.e. on context menu click you will have to delete the items checked by user from the datasource of your combobox and then re-bind the combobox with datasource.
If you don't have a data bound combobox, then on context menu click simply loop through the combobox items and delete the items which are checked by user.
I want to be able to drag an item from a ListView, and drop it onto the a GridView that represents a list of UserControls.
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListView
ItemsSource="{Binding}"
VerticalAlignment="Stretch" HorizontalAlignment="Left"
CanReorderItems="False" CanDragItems="True"
DragItemsStarting="DragItemsStarting">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Width="280">
<TextBlock Text="{Binding}" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Viewbox Grid.Column="1" Margin="0,20,0,0">
<GridView x:Name="BoardGrid"
Width="600" Height="600">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid MaximumRowsOrColumns="10"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.ItemTemplate>
<DataTemplate x:Name="GameBoardCellWithPieceDataTemplate">
<Grid Background="Green" Width="50" Height="50">
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Viewbox>
</Grid>
In the code behind I create the GridItems, set the AllowDrop property an assign an eventhander to the Drop event.
public MainPage()
{
this.InitializeComponent();
Loaded += MainPage_Loaded;
this.DataContext = new List<string> { "Drag String 1", "Drag String 2" };
}
public void MainPage_Loaded(object sender, RoutedEventArgs e)
{
for (var row = 0; row < 5; row++)
{
for (var column = 0; column < 5; column++)
{
var myUserControl = new MyUserControl { AllowDrop = true };
myUserControl.Drop += PieceDropped;
BoardGrid.Items.Add(myUserControl);
}
}
}
private void DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
var dragItem = (string)e.Items.FirstOrDefault();
if (dragItem == null)
return;
e.Data.Properties.Add("dragItem", dragItem);
}
private void PieceDropped(object sender, DragEventArgs e)
{
object sourceItem;
e.Data.Properties.TryGetValue("dragItem", out sourceItem);
if (sourceItem == null)
return;
[...]
}
The drag behaviour works fine, but when I drop an item of the ListView onto the GridView(Item), the Drop event isnt fired.
When I set the AllowDrop on the GridView itself, the Drop event is fired. Or when I wrap the UserControl in a GridViewItem, and set the AllowDrop on the GridViewItem, also the Drop event is fired, but after that i'm having problems with the DataTemplateSelecdtor I use.
Any clue?
I have created a sample project (http://sdrv.ms/V2OpfE) to demonstrate the problem