Dynamically add textbox in WPF - c#

I am creating a textbox dynamically. I have 2 columns in my grid. I want to add new textbox to the row if the other textbox value="tea". I want to create new textbox to corresponding row textbox value change. I am unable to use Tag to get selected row here. because I have already used Tag for some purpose. I don't have much idea about Tag. Anyhow, how can I add new textbox to the column1 to the corresponding row?
This is my code..
public int count = 1;
public TextBox txt1;
private void btn_addnew_Click(object sender, RoutedEventArgs e)
{
//Creating Rows..
RowDefinition row0 = new RowDefinition();
row0.Height = new GridLength(40);
grid1.RowDefinitions.Add(row0);
//Creating columns..
ColumnDefinition col0 = new ColumnDefinition();
ColumnDefinition col1 = new ColumnDefinition();
col0.Width = new GridLength(150);
col1.Width = new GridLength(250);
grid1.ColumnDefinitions.Add(col0);
grid1.ColumnDefinitions.Add(col1);
int i = count;
//1st Column TextBox
txt1 = new TextBox();
txt1.Margin = new Thickness(10, 10, 0, 0);
Grid.SetRow(txt1, i);
Grid.SetColumn(txt1, 0);
txt1.Tag = txt1;
txt1.MouseEnter+=txt1_MouseEnter;
txt1.TextChanged += txt1_TextChanged;
grid1.Children.Add(txt1);
count++;
}
private void txt1_MouseEnter(object sender, MouseEventArgs e)
{
txt1 = ((TextBox)sender).Tag as TextBox;
popup.IsOpen = true;
}
public TextBox txt2;
private void txt1_TextChanged(object sender, TextChangedEventArgs e)
{
if (txt1.Text.ToString() == "Tea")
{
txt2 = new TextBox();
//How to set row here?
Grid.SetRow(txt2, ??);
Grid.SetColumn(txt2, 1);
txt2.Margin = new Thickness(10, 10, 0, 0);
grid1.Children.Add(txt2);
}
else
{
grid1.Children.Remove(txt2);
}
}

If you just want to achieve this, then more elegant way will be to add the user control to your application like below:
<UserControl x:Class="WpfApplication4.TestUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBox Name="TextBox1"/>
<TextBox Grid.Column="1">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=TextBox1, UpdateSourceTrigger=PropertyChanged}" Value="tea">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</Grid>
</UserControl>
then in your btn_addnew_Click() method, you just need to add this usercontrol to user Grid and assign row and column to it. Showing/Hiding of textbox will be taken care of by teh user control itself.
var userControl = new MyUserControl();
userControl .Margin = new Thickness(10, 10, 0, 0);
Grid.SetRow(userControl , i);
grid1.Children.Add(userControl );
OR
if you want to have value of Grid.Row for textbox1 you can get it directly as:
if (textbox1 != null)
{
int row = (int)textbox1.GetValue(Grid.RowProperty);
Grid.SetRow(txt2, row);
}

Attached properties can be used to store such information so define an attached property in the class
public static int GetGridRow(DependencyObject obj)
{
return (int)obj.GetValue(GridRowProperty);
}
public static void SetGridRow(DependencyObject obj, int value)
{
obj.SetValue(GridRowProperty, value);
}
// Using a DependencyProperty as the backing store for GridRow. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GridRowProperty =
DependencyProperty.RegisterAttached("GridRow", typeof(int), typeof(ViewModel), new PropertyMetadata(0));
then use it to store the value of the row
private void btn_addnew_Click(object sender, RoutedEventArgs e)
{
//1st Column TextBox
txt1 = new TextBox();
Grid.SetRow(txt1, i);
SetGridRow(text1, i);
...
grid1.Children.Add(txt1);
count++;
}
then use it when u need it
//How to set row here?
Grid.SetRow(txt2, GetGridRow(txt1));
Grid.SetColumn(txt2, 1);

Related

Trying to create a WPF window that behaves like the VS editor window

I've used the CodeBox project from CodeProject and it works very well except for the fact that I can't disable text wrapping. In a normal TextBox, simply setting the TextWrapping property to NoWrap does the trick, but not with CodeBox (which inherits from TextBox in code-behind). I've tried adding a horizontal scrollbar but that doesn't help. The scrollbar is visible and it changes the size of the drag button to show that it sees that the unwrapped text is wider than the viewing area, but since the text has already been wrapped, dragging it doesn't make any difference.
I've tracked the problem to a line in OnRender:
"formattedText.MaxTextWidth = this.ViewportWidth; // space for scrollbar"
I'm fairly new to WPF and there's much to it that is still mysterious to me, so the solution may be obvious to someone with more experience with it.
I'd appreciate any suggestions. This is the code-behind C#, lengthy, but it has been trimmed down to only enough to show what's going on. The rest (that has been reomved) is just code that does more text-coloring.
public partial class CodeBox : TextBox
{
bool m_bScrollingEventEnabled;
SolidColorBrush m_brRed = new SolidColorBrush (Colors.Red);
SolidColorBrush m_brOrange = new SolidColorBrush (Colors.Orange);
SolidColorBrush m_brBlack = new SolidColorBrush (Colors.Black);
public CodeBox ()
{
this.TextChanged += new TextChangedEventHandler (txtTest_TextChanged);
this.Foreground = new SolidColorBrush (Colors.Transparent);
this.Background = new SolidColorBrush (Colors.Transparent);
this.TextWrapping = System.Windows.TextWrapping.NoWrap;
base.TextWrapping = System.Windows.TextWrapping.NoWrap;
InitializeComponent ();
}
public static DependencyProperty BaseForegroundProperty = DependencyProperty.Register ("BaseForeground", typeof (Brush), typeof (CodeBox),
new FrameworkPropertyMetadata (new SolidColorBrush (Colors.Black), FrameworkPropertyMetadataOptions.AffectsRender));
public Brush BaseForeground
{
get { return (Brush)GetValue (BaseForegroundProperty); }
set { SetValue (BaseForegroundProperty, value); }
}
public static DependencyProperty BaseBackgroundProperty = DependencyProperty.Register ("BaseBackground", typeof (Brush), typeof (CodeBox),
new FrameworkPropertyMetadata (new SolidColorBrush (Colors.Black), FrameworkPropertyMetadataOptions.AffectsRender));
public Brush BaseBackground
{
get { return (Brush)GetValue (BaseBackgroundProperty); }
set { SetValue (BaseBackgroundProperty, value); }
}
void txtTest_TextChanged (object sender, TextChangedEventArgs e)
{
this.InvalidateVisual ();
}
protected override void OnRender (System.Windows.Media.DrawingContext drawingContext)
{
//base.OnRender(drawingContext);
if (this.Text.Length > 0)
{
EnsureScrolling ();
FormattedText formattedText = new FormattedText (
this.Text,
CultureInfo.GetCultureInfo ("en-us"),
FlowDirection.LeftToRight,
new Typeface (this.FontFamily.Source),
this.FontSize,
BaseForeground); //Text that matches the textbox's
double leftMargin = 4.0 + this.BorderThickness.Left;
double topMargin = 2 + this.BorderThickness.Top;
***formattedText.MaxTextWidth = this.ViewportWidth; // space for scrollbar***
formattedText.MaxTextHeight = Math.Max (this.ActualHeight + this.VerticalOffset, 0); //Adjust for scrolling
drawingContext.PushClip (new RectangleGeometry (new Rect (0, 0, this.ActualWidth, this.ActualHeight)));//restrict text to textbox
int iStartVisibleLine = GetFirstVisibleLineIndex ();
int iEndVisibleLine = GetLastVisibleLineIndex ();
for (int iIdx = iStartVisibleLine; iIdx <= iEndVisibleLine - 1; ++iIdx)
{
// Text coloring
int iOffset = GetCharacterIndexFromLineIndex (iIdx);
int iOffsetNext = GetCharacterIndexFromLineIndex (iIdx + 1);
string strLine = Text.Substring (iOffset, iOffsetNext - iOffset);
}
drawingContext.DrawText (formattedText, new Point (leftMargin, topMargin - this.VerticalOffset));
}
}
private void EnsureScrolling ()
{
if (!m_bScrollingEventEnabled)
{
DependencyObject dp = VisualTreeHelper.GetChild (this, 0);
ScrollViewer sv = VisualTreeHelper.GetChild (dp, 0) as ScrollViewer;
sv.ScrollChanged += new ScrollChangedEventHandler (ScrollChanged);
m_bScrollingEventEnabled = true;
}
}
private void ScrollChanged (object sender, ScrollChangedEventArgs e)
{
this.InvalidateVisual ();
}
}
The xaml from the project:
<TextBox x:Class="CodeBoxControl.CodeBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:CodeBoxControl">
<TextBox.Template>
<ControlTemplate TargetType="c:CodeBox" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Border BorderThickness="{TemplateBinding Border.BorderThickness}" BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}" Name="Bd" SnapsToDevicePixels="True">
<ScrollViewer Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled">
<Setter Property="Panel.Background" TargetName="Bd">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.ControlBrushKey}" />
</Setter.Value>
</Setter>
<Setter Property="TextElement.Foreground">
<Setter.Value>
<DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
</Setter.Value>
</Setter>
<Trigger.Value>
<s:Boolean>False</s:Boolean>
</Trigger.Value>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</TextBox.Template>
Xaml from the parent window that uses the CodeBox code:
<c:CodeBox Name="DisassemblyOutput"
FontFamily="Courier New"
FontSize="20"
VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto"
BaseForeground="Black"
Margin="4,4,4,4"
Background="#CEE9C9"
Foreground="Magenta"
TextWrapping="NoWrap"
AutoWordSelection="False"/>
This is a sample of the code that loads the text into the CodeBox window:
private void OnLoadDASM (object sender, RoutedEventArgs e)
{
DisassemblyOutput.FontSize = 12;
DisassemblyOutput.Clear ();
DisassemblyOutput.m_eWindowData = CodeBox.EWindowData.EDasm;
DisassemblyOutput.Background = new SolidColorBrush (Colors.Transparent);//Color.FromRgb (0xCE, 0xE9, 0xC9));
DisassemblyOutput.Foreground = new SolidColorBrush (Colors.Transparent);
DisassemblyOutput.BaseBackground = new SolidColorBrush (Color.FromRgb (0xCE, 0xE9, 0xC9));
DisassemblyOutput.BaseForeground = new SolidColorBrush (Colors.Transparent);
DisassemblyOutput.TextWrapping = TextWrapping.NoWrap;
DisassemblyOutput.Text += "Loop_02_0A0F 0A0F: SIO F3 10 28 5475 Keyboard Set Error Indicator Restore Data Key " + Environment.NewLine;
DisassemblyOutput.Text += " Disable Interrupt " + Environment.NewLine;
DisassemblyOutput.Text += " 0A12: SNS 70 12 FF,1 0x0B0C 5475 Keyboard 2 sense bytes " + Environment.NewLine;
}
This is what I want:
https://i.stack.imgur.com/M4ts0.png
and what's showing up:
https://i.stack.imgur.com/gdBco.png
I've also noticed that when the text wraps and I use the vertical scrollbar, the text in the top part of the pane disappears, and the more I scroll down, the more of it disappears:
1
The fix is to set MaxTextWidth to the width of the line instead of the ViewportWidth property:
iStartVisibleLine = GetFirstVisibleLineIndex ();
iEndVisibleLine = GetLastVisibleLineIndex ();
iOffset = GetCharacterIndexFromLineIndex (0);
iOffsetNext = GetCharacterIndexFromLineIndex (1);
strLine = Text.Substring (iOffset, iOffsetNext - iOffset);
geomFirstLine = formattedText.BuildHighlightGeometry (new Point (leftMargin, topMargin - this.VerticalOffset), iOffset, strLine.Length);
rcBounds = geomFirstLine.GetRenderBounds (null);
formattedText.MaxTextWidth = rcBounds.Width; // Space for scrollbar

I need to Delete a Control inside a WrapPanel created dynamically inside another WrapPanel while in Run-Time

So, I have a main WrapPanel called "valoresPanel". When I start running I need to click the Button labeled "2" (below) and a TextBox needs to appear inside the WrapPanel labeled "1" thats was created in runtime.
This is my code for the "+ button" right now:
void novoValor_Click(object sender, RoutedEventArgs e)
{
WrapPanel wpValores = new WrapPanel();
Button deleteValor = new Button();
TextBox txtValor = new TextBox();
deleteValor.Height = 25;
deleteValor.Width = 25;
deleteValor.Content = "X";
txtValor.Height = 25;
txtValor.Width = 70;
txtValor.Margin = new Thickness(0, 0, 8, 0);
wpValores.Height = 25;
wpValores.Width = 105;
wpValores.Children.Add(deleteValor);
wpValores.Children.Add(txtValor);
valoresPanel.Children.Add(wpValores);
deleteValor.Click += deleteValor2_Click;
}
So, i updated my code using only one WrapPanel per item, now i can add a item, add values and delete the item with its respective values but i cant delete a specific value, this is my code by now:
this image will help to understand
void novoValor_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
WrapPanel wpFather = btn.Parent as WrapPanel;
WrapPanel wpValue = new WrapPanel();
Button deleteValue = new Button();
TextBox txtValue = new TextBox();
wpValue.Height = 25;
wpValue.Width = 105;
deleteValue.Height = 25;
deleteValue.Width = 25;
deleteValue.Content = "-";
txtValue.Height = 25;
txtValue.Width = 70;
txtValue.Margin = new Thickness(0, 0, 8, 0);
wpValue.Children.Add(deleteValue);
wpValue.Children.Add(txtValue);
wpFather.Children.Add(wpValue);
deleteValue.Click += deleteValor_Click;
}
void deleteValor_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
WrapPanel panel = btn.Parent as WrapPanel;
entradasPanel.Children.Remove(panel);
}
If someone need any other information im willing to send it as fast as I can!
You should create a ListView which has a WrapPanel as ItemsPanel. Then to the ListView.ItemsSource you bind an ObservableCollection of data models. By defining a DataTemplate for the ListView.ItemTemplate you can make the data items be displayed as a TextBox with a Button where the TextBox binds to this item's data model. By pressing the delete button you simply remove this data model from the ObservaleColection ( the ItemsSource of the ListView).
DataModel.cs
class DataModel
{
public string UserInput { get; set; }
}
ViewModel.cs
class ViewModel
{
public ObservableCollection<DataModel> Items { get; set; }
public ICommand AddItemCommand => new AsyncRelayCommand(() => this.Items.Add(new DataModel()));
public ICommand RemoveItemCommand => new AsyncRelayCommand((item) => this.Items.Remove(item));
public ViewModel()
{
this.Items = new ObservableCollection<DataModel>();
}
}
MainWindow.xaml
<Window>
<Window.DataContext>
<ViewModel />
</Window.DataContext>
<StackPanel>
<Button Content="Add Item"
Command="{Binding AddItemCommand}" />
<ListView ItemsSource="{Binding Items}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="600" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type DataModel}">
<StackPanel Orientation="Horizontal">
<Button Content="Remove Item"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListView}, Path=DataContext.RemoveItemCommand}"
CommandParameter="{Binding}" />
<TextBox Text="{Binding UserInput}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Window>
I could solve my last question with the following code:
void deleteValue_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
WrapPanel panel = btn.Parent as WrapPanel;
WrapPanel panelPai = panel.Parent as WrapPanel;
panelPai.Children.Remove(panel);
}

WPF Dynamic change of GridViewColumn CellTemplate c#

I'm trying to learn something about the ListView and now I'm solving this problem:
I have a listview defined in the behindcode. I would like to change gridviewcolumn celltemplate dynamically. For example by the use of checkbox or button, or other. Is it even possible?
Definition of my ListView is here:
lvUsers.ItemsSource = LoadListViewData();
GridView gridview = new GridView();
lvUsers.View = gridview;
DataTemplate templateCheck = new DataTemplate();
FrameworkElementFactory factoryContentControlCheck = new FrameworkElementFactory(typeof(VsCheckBox));
factoryContentControlCheck.SetValue(VsCheckBox.MarginProperty, new Thickness(0, 0, 0, 0));
DataTemplate templateBorder = new DataTemplate();
FrameworkElementFactory factoryContentControlBorder = new FrameworkElementFactory(typeof(Border));
factoryContentControlBorder.SetValue(Border.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlBorder.SetValue(Border.WidthProperty, Width = 10);
factoryContentControlBorder.SetValue(Border.HeightProperty, Height = 10);
factoryContentControlBorder.SetValue(Border.BackgroundProperty, Brushes.Red);
DataTemplate templateAge = new DataTemplate();
FrameworkElementFactory factoryContentControlAge = new FrameworkElementFactory(typeof(ContentControl));
factoryContentControlName.SetValue(ContentControl.MarginProperty, new Thickness(0, 0, 10, 0));
factoryContentControlAge.SetValue(ContentControl.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlAge.SetValue(ContentControl.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlAge.SetBinding(ContentControl.ContentProperty, new Binding("Age"));
DataTemplate templateStack = new DataTemplate();
FrameworkElementFactory factoryContentControlStack = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack.AppendChild(factoryContentControlCheck);
factoryContentControlStack.AppendChild(factoryContentControlBorder);
templateStack.VisualTree = factoryContentControlStack;
DataTemplate templateStack1 = new DataTemplate();
FrameworkElementFactory factoryContentControlStack1 = new FrameworkElementFactory(typeof(StackPanel));
factoryContentControlStack1.SetValue(StackPanel.MarginProperty, new Thickness(10, 0, 0, 0));
factoryContentControlStack1.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
factoryContentControlStack1.SetValue(StackPanel.HorizontalAlignmentProperty, HorizontalAlignment.Right);
factoryContentControlStack1.SetValue(StackPanel.VerticalAlignmentProperty, VerticalAlignment.Center);
factoryContentControlStack1.AppendChild(factoryContentControlAge);
templateStack1.VisualTree = factoryContentControlStack1;
GridViewColumn colStack = new GridViewColumn();
colStack.Header = "Stack";
colStack.CellTemplate = templateStack;
gridview.Columns.Add(colStack);
I would like to change CellTemplate of colStack to templateStack1 in runtime by the checking a checkbox or button click.
Thank you for any of your ideas.
You can make use of DataTrigger in order to change dynamically the ContentTemplate of your columns. Here is an example using XAML:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<CheckBox x:Name="TemplateChanger" Content="Change template"
IsChecked="{Binding IsChecked}"/>
<DataGrid x:Name="DataGrid" Grid.Row="1" AutoGenerateColumns="False"
ItemsSource="{Binding Items}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="My column" IsReadOnly="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Foo}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellStyle>
<Style TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding DataContext.IsChecked, RelativeSource={RelativeSource AncestorType=DataGrid}}" Value="True">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="fsdfsdf"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTemplateColumn.CellStyle>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
And the codebehind file:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using WpfApp.Annotations;
namespace WpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : INotifyPropertyChanged
{
private bool _isChecked;
public MainWindow()
{
InitializeComponent();
Items.Add(new Item {Foo = "Foo1"});
Items.Add(new Item {Foo = "Foo2"});
Items.Add(new Item {Foo = "Foo3"});
Items.Add(new Item {Foo = "Foo4"});
}
public bool IsChecked
{
get => _isChecked;
set
{
_isChecked = value;
OnPropertyChanged();
}
}
public ObservableCollection<Item> Items { get; } = new ObservableCollection<Item>();
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Item
{
public string Foo { get; set; }
}
}
The result is that whenever you toggle the checkbox's IsChecked property the content template of the cell for the given column changes too.
EDIT How to do it with code behind only
For completness sake here is how you can achieve this with code behind only:
var datagrid = new DataGrid {AutoGenerateColumns = false};
Grid.SetRow(datagrid,1);
RootGrid.Children.Add(datagrid);
var templateColumn = new DataGridTemplateColumn
{
Header = "My column",
IsReadOnly = true
};
var cellTemplate = new DataTemplate();
var factory = new FrameworkElementFactory(typeof(TextBlock));
factory.SetBinding(TextBlock.TextProperty, new Binding("Foo"));
var style = new Style(typeof(DataGridCell));
var trigger = new DataTrigger();
var triggerBinding = new Binding("DataContext.IsChecked")
{
RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGrid), 1)
};
trigger.Binding = triggerBinding;
trigger.Value = true;
var triggerSetter = new Setter {Property = ContentTemplateProperty};
var triggerTemplate = new DataTemplate();
var anotherFactory = new FrameworkElementFactory(typeof(TextBlock));
anotherFactory.SetValue(TextBlock.TextProperty,"lol");
triggerTemplate.VisualTree = anotherFactory;
triggerSetter.Value = triggerTemplate;
trigger.Setters.Add(triggerSetter);
style.Triggers.Add(trigger);
templateColumn.CellStyle = style;
cellTemplate.VisualTree = factory;
templateColumn.CellTemplate = cellTemplate;
datagrid.Columns.Add(templateColumn);
datagrid.ItemsSource = Items;
IMHO this way looks a little bit messy, but the decision is yours =)

how to bind popup value to dynamically created textbox?

i am creating a Button and a textbox dynamically one by one in grid. My requirement is, if i click the button, the popup will show. and if i select the values from popup, i need to bind the corresponding row's textbox. Fr example, if i click the 5th row's button, i need to bind the popup item value to the 5th rows textbox. i struck on binding values to corresponding row's textbox. this may be simple one but i am unable to done this. this is my code.,
Xaml:
<Button x:Name="btn_addnewrow" Content="Add" HorizontalAlignment="Left" Margin="50,40,0,0" VerticalAlignment="Top" Width="89" Height="31" Click="btn_addnewrow_Click"/>
<Popup Name="popup" IsOpen="False" Placement="Mouse" VerticalOffset="15" HorizontalOffset="0" Margin="124,122,107,65">
<Border BorderBrush="Black" BorderThickness="1" Background="Coral">
<StackPanel Orientation="Horizontal" Height="143">
<ListView Margin="10,10,0,0" Name="ListView1" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="194" Height="133" MouseDoubleClick="ListView1_MouseDoubleClick">
<ListViewItem Content="Coffie"></ListViewItem>
<ListViewItem Content="Tea"></ListViewItem>
<ListViewItem Content="Orange Juice"></ListViewItem>
<ListViewItem Content="Milk"></ListViewItem>
<ListViewItem Content="Iced Tea"></ListViewItem>
<ListViewItem Content="Mango Shake"></ListViewItem>
</ListView>
</StackPanel>
</Border>
</Popup>
cs:
public int count = 0;
public Button btn1;
public Button btn2;
public TextBox txt1;
private void btn_addnewrow_Click(object sender, RoutedEventArgs e)
{
//Creating Rows..
RowDefinition row0 = new RowDefinition();
row0.Height = new GridLength(40);
grid1.RowDefinitions.Add(row0);
//Creating columns..
ColumnDefinition col0 = new ColumnDefinition();
ColumnDefinition col1 = new ColumnDefinition();
ColumnDefinition col2 = new ColumnDefinition();
col0.Width = new GridLength(50);
col1.Width = new GridLength(100);
col2.Width = new GridLength(70);
grid1.ColumnDefinitions.Add(col0);
grid1.ColumnDefinitions.Add(col1);
grid1.ColumnDefinitions.Add(col2);
int i = count;
////1st Column button
btn1 = new Button();
btn1.Margin = new Thickness(10, 10, 0, 0);
btn1.BorderThickness = new Thickness(0);
Grid.SetRow(btn1, i);
Grid.SetColumn(btn1, 0);
btn1.Tag = btn1;
btn1.Click += btnBindList_Click;
grid1.Children.Add(btn1);
//2nd column Textbox
txt1 = new TextBox();
txt1.Margin = new Thickness(10, 10, 0, 0);
txt1.Name = "txt" + i;
Grid.SetRow(txt1, i);
Grid.SetColumn(txt1, 1);
txt1.Tag = txt1;
grid1.Children.Add(txt1);
count++;
}
private void btnBindList_Click(object sender, RoutedEventArgs e)
{
?
?
popup.IsOpen = true;
}
private void ListView1_MouseDoubleClick(object sender, RoutedEventArgs e)
{
txt1.Text = (ListView1.SelectedItem as ListViewItem).Content.ToString();
popup.IsOpen = false;
}
Create a usercontrol with button, textbox and popup. This usercontrol should set to the cell template or item template of gridview or listview. The textbox is bound to selected value of popup listview. So when user open popup and choose the value, the selected value will update in corresponding textbox.
<Grid HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Text="{Binding ElementName=ListView1, Path=SelectedValue.Content}" Width="200" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="2"/>
<ToggleButton Content="Select" Grid.Column="1" HorizontalAlignment="Left" Margin="2" x:Name="btn"/>
<Popup PlacementTarget="{Binding ElementName=btn}" Placement="Bottom"
StaysOpen="False"
IsOpen="{Binding ElementName=btn, Path=IsChecked}">
<ListView Name="ListView1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Width="194"
Height="133">
<ListViewItem Content="Coffie"></ListViewItem>
<ListViewItem Content="Tea"></ListViewItem>
<ListViewItem Content="Orange Juice"></ListViewItem>
<ListViewItem Content="Milk"></ListViewItem>
<ListViewItem Content="Iced Tea"></ListViewItem>
<ListViewItem Content="Mango Shake"></ListViewItem>
</ListView>
</Popup>
</Grid>
If you want to use Binding, you need to creat a viewmodel,a class. And binding it to Button and TextBox. When you click a button,get the viewmodel, and set it's value by selecting in listview.
The code is very confused, but you can debug and rewrite it by yourself.
public int count = 0;
public Button btn1;
public Button btn2;
public TextBox txt1;
private void btn_addnewrow_Click(object sender, RoutedEventArgs e)
{
//Creating Rows..
RowDefinition row0 = new RowDefinition();
row0.Height = new GridLength(40);
grid1.RowDefinitions.Add(row0);
//Creating columns..
ColumnDefinition col0 = new ColumnDefinition();
ColumnDefinition col1 = new ColumnDefinition();
ColumnDefinition col2 = new ColumnDefinition();
col0.Width = new GridLength(50);
col1.Width = new GridLength(100);
col2.Width = new GridLength(70);
grid1.ColumnDefinitions.Add(col0);
grid1.ColumnDefinitions.Add(col1);
grid1.ColumnDefinitions.Add(col2);
int i = count;
Test t = new Test();
////1st Column button
btn1 = new Button();
btn1.Margin = new Thickness(10, 10, 0, 0);
btn1.BorderThickness = new Thickness(0);
Grid.SetRow(btn1, i);
Grid.SetColumn(btn1, 0);
Binding binding = new Binding();
binding.Source = t;
btn1.SetBinding(Button.TagProperty, binding);
btn1.Click += btnBindList_Click;
grid1.Children.Add(btn1);
Binding binding1 = new Binding("Content");
binding1.Source = t;
//2nd column Textbox
txt1 = new TextBox();
txt1.Margin = new Thickness(10, 10, 0, 0);
txt1.Name = "txt" + i;
txt1.SetBinding(TextBox.TextProperty, binding1);
Grid.SetRow(txt1, i);
Grid.SetColumn(txt1, 1);
txt1.Tag = txt1;
grid1.Children.Add(txt1);
count++;
}
private void btnBindList_Click(object sender, RoutedEventArgs e)
{
popup.IsOpen = true;
t = ((Button)sender).Tag as Test;
}
Test t;
private void ListView1_MouseDoubleClick(object sender, RoutedEventArgs e)
{
t.Content = (ListView1.SelectedItem as ListViewItem).Content.ToString();
popup.IsOpen = false;
}
}
class Test : INotifyPropertyChanged
{
private string content;
public string Content
{
get { return content; }
set
{
content = value;
OnPropertyChanged("Content");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

WPF ComboBox Hide (Disable) DropDown Button Programmatically

I would like to know how to disable ComboBox DropDown Button Programmatically. I had seen many similar subjects but all of these have a XAML solution.
By the way, if someone know how to disable all ComboBox control design and left visible only item template it can be helpful too.
UPDATE
its my XAML definition
<ComboBox Name="lang_ComboBox" SelectionChanged="LanguageSelection_ComboBox_SelectionChanged"/>
And there is how i use it:
String text = "dorf";
BitmapImage image = new BitmapImage(new Uri("http://img88.imageshack.us/img88/4351/butchermi4.png"));
lang_ComboBox.Width = 100;
lang_ComboBox.Height = 30;
Grid sp;
for (int i = 0; i < 5; i++)
{
ColumnDefinition gridCol1 = new ColumnDefinition();
gridCol1.Width = new GridLength(30.0);
ColumnDefinition gridCol2 = new ColumnDefinition();
gridCol2.Width = new GridLength(70.0);
sp = new Grid()
{
Width = 100,
Height = 30
};
Image im = new Image()
{
Source = image,
Width = 25,
Height = 25
};
Label la = new Label()
{
Content = text
};
sp.ColumnDefinitions.Add(gridCol1);
sp.ColumnDefinitions.Add(gridCol2);
Grid.SetColumn(im, 0);
Grid.SetColumn(la, 1);
sp.Children.Add(la);
sp.Children.Add(im);
lang_ComboBox.Items.Add(sp);
}
UPDATE 2
Hmmm I get it now, I use wrong word. It should be "Hide" control design and still can choose from a list. My bad sorry. But i know how i can solve it with Anatoliy Nokolaev's Code. To hide control design i use:
ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(lang_ComboBox);
dropDownButton.Visibility = System.Windows.Visibility.Collapsed;
Unwanted behavior is now only that i cant show combobox dropdownmenu, but I'll invoke it programmatically by add on click event and should be good.
If there is any easiest way to do this tell me :).
To disable only the ToggleButton in ComboBox programmatically, you need to find this in the ComboBox control using VisualTreeHelper and assign a property IsEnabled to false, like this:
XAML
<Window x:Class="DisableComboBoxButton.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"
Loaded="Window_Loaded">
<StackPanel>
<ComboBox Name="comboBox"
Width="100"
Height="25"
SelectedIndex="0">
<ComboBoxItem>Test1</ComboBoxItem>
<ComboBoxItem>Test2</ComboBoxItem>
<ComboBoxItem>Test3</ComboBoxItem>
</ComboBox>
<ComboBox Name="AllComboBoxDisabled"
Width="100"
Height="25"
IsEnabled="False"
SelectedIndex="0">
<ComboBoxItem>Test1</ComboBoxItem>
<ComboBoxItem>Test2</ComboBoxItem>
<ComboBoxItem>Test3</ComboBoxItem>
</ComboBox>
</StackPanel>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(comboBox);
dropDownButton.IsEnabled = false;
}
public static T GetFirstChildOfType<T>(DependencyObject dependencyObject) where T : DependencyObject
{
if (dependencyObject == null)
{
return null;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
var result = (child as T) ?? GetFirstChildOfType<T>(child);
if (result != null)
{
return result;
}
}
return null;
}
}
Output
Notes
Always use GetFirstChildOfType() function only when the control will be fully loaded, otherwise it will not find it and give null. In this case, I put this code in the event Window_Loaded which says that all the controls of the Window successfully load.
Edit: another version
Not to say that this version is easier to implement, but it would be more correct and a bit easier to use.
So, we need a template for your ComboBox, because it allows access to elements that are within the control. Just like that, the ToggleButton can not be accessed from both the code and of XAML.
We create attached dependency property that will serve the current ComboBox another property, such as which will give access to our button Visibility.
Our property Visibility:
public static class ButtonExt
{
public static readonly DependencyProperty VisibilityProperty;
public static void SetVisibility(DependencyObject DepObject, Visibility value)
{
DepObject.SetValue(VisibilityProperty, value);
}
public static Visibility GetVisibility(DependencyObject DepObject)
{
return (Visibility)DepObject.GetValue(VisibilityProperty);
}
static ButtonExt()
{
PropertyMetadata VisibiltyPropertyMetadata = new PropertyMetadata(Visibility.Collapsed);
VisibilityProperty = DependencyProperty.RegisterAttached("Visibility",
typeof(Visibility),
typeof(ButtonExt),
VisibiltyPropertyMetadata);
}
}
Setter property in ComboBox template (skip version, full version see in project in App.xaml file):
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton Name="ToggleButton"
Template="{StaticResource ComboBoxToggleButton}"
IsChecked="{Binding Path=IsDropDownOpen,
Mode=TwoWay,
RelativeSource={RelativeSource TemplatedParent}}"
Visibility="{TemplateBinding PropertiesExtension:ButtonExt.Visibility}" // <------ Here
Grid.Column="2"
Focusable="False"
ClickMode="Press" />
Now, we are setting this property like this:
<ComboBox Name="comboBox"
Style="{StaticResource ComboBoxBaseStyle}"
PropertiesExtension:ButtonExt.Visibility="Visible"
Width="100"
Height="30"
SelectedIndex="0">
<ComboBoxItem>Test1</ComboBoxItem>
<ComboBoxItem>Test2</ComboBoxItem>
<ComboBoxItem>Test3</ComboBoxItem>
</ComboBox>
or in code-behind via Click event handlers:
private void HideButton_Click(object sender, RoutedEventArgs e)
{
ButtonExt.SetVisibility(comboBox, Visibility.Hidden);
}
private void ShowButton_Click(object sender, RoutedEventArgs e)
{
ButtonExt.SetVisibility(comboBox, Visibility.Visible);
}
Full version of example project is here.
Try with this
Dispatcher.BeginInvoke(new Action(() =>
{
ToggleButton dropDownButton = GetFirstChildOfType<ToggleButton>(cboMedicos);
if (dropDownButton != null)
{
dropDownButton.IsEnabled = false;
}
}), System.Windows.Threading.DispatcherPriority.Render);
public static T GetFirstChildOfType<T>(DependencyObject dependencyObject) where T : DependencyObject
{
if (dependencyObject == null)
{
return null;
}
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dependencyObject); i++)
{
var child = VisualTreeHelper.GetChild(dependencyObject, i);
var result = (child as T) ?? GetFirstChildOfType<T>(child);
if (result != null)
{
return result;
}
}
return null;
}

Categories