WPF datagridtextcolumn - always show textbox - c#

By default the WPF datagridtext appears as a label and enters an edit state upon clicking. Is there a way to modify the column so that the textbox is always visible (instead of depending on the click event)?
Thanks in advance,
JP

I updated my answer based on your clarification in your comment. You can set the template yourself for cells. Below is a sample where the age column uses textblocks.
XAML:
<Window x:Class="GridTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
Height="300" Width="300">
<StackPanel>
<Controls:DataGrid Name="dataGrid" AutoGenerateColumns="False" >
<Controls:DataGrid.Columns>
<Controls:DataGridTextColumn
Header="Name"
Binding="{Binding Path=Name}" />
<Controls:DataGridTemplateColumn Header="Age">
<Controls:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Age}" />
</DataTemplate>
</Controls:DataGridTemplateColumn.CellTemplate>
<Controls:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Age}" />
</DataTemplate>
</Controls:DataGridTemplateColumn.CellEditingTemplate>
</Controls:DataGridTemplateColumn>
</Controls:DataGrid.Columns>
</Controls:DataGrid>
</StackPanel>
</Window>
Code behind:
using System;
using System.Collections.Generic;
using System.Windows;
namespace GridTest
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
dataGrid.ItemsSource = new List<Person>(
new Person[]
{
new Person("Bob", 30),
new Person("Sally", 24),
new Person("Joe", 17)
});
}
}
public class Person
{
public String Name { get; set; }
public int Age { get; set; }
public Person(String name, int age)
{
Name = name;
Age = age;
}
}
}

Related

How to Create a Filter in WPF using Datagrid and ComboBox

So here I have a MVVM form. the Form contains a Datagrid which is connected to the Databank. I also have a ComboBox which I want to use as a filter option. The Filter option shoud filter by the "AnlV nr" so when the user selects "01" from the ComboBox the datagrid should refresh and show only that "AnlV nr" that have "01" Below I will share you the code and you can see that i've gotten as far as showing the "AnlV" values in the ComboBox but I now do not know how to do the rest and make the filter work. Below is my Viewmodel and the Xaml code.
If anyone can help me with this I would really apreciate it.
Xaml Code:
<Window x:Class="QBondsFrontend.Views.Input.AnlVTexteView"
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"
xmlns:local="clr-namespace:QBondsFrontend.Views.Input" xmlns:input="clr-namespace:QBondsFrontend.ViewModels.Input" d:DataContext="{d:DesignInstance Type=input:AnlVTexteViewModel}"
mc:Ignorable="d"
Title="AnlVTexteView"
Width="800"
MinHeight="400"
Height="490"
MinWidth="1010"
MaxWidth="1010"
UseLayoutRounding="True">
<Grid Background="#A8A8A8" >
<StackPanel VerticalAlignment="Top" Background="#A8A8A8" Orientation="Horizontal" Height="57">
<Label
Content="AnlV Nr.:" Height="35" FontSize="12"/>
<ComboBox Background="LightGray" Height="20" Width="70" ItemsSource="{Binding lstAnlVTexte}" SelectedItem="{Binding Search}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding AnlVPara}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button Height="18" Width="68" Margin="5, 0"
Content="Filter löschen" FontSize="11" Style="{StaticResource STL_ButtonStandard}"
x:Name="filterlöschen"
Command="{Binding icdFilterDelete}"/>
</StackPanel>
<StackPanel Background="LightGray" VerticalAlignment="Top" Height="177" Margin="0,57,0,0">
<DataGrid x:Name="datagridXAML"
Height="177"
ItemsSource="{Binding lstAnlVTexte, Mode=TwoWay}"
Style="{StaticResource STL_DataGridReporting}"
CellStyle="{StaticResource STL_DataGridCellReporting}"
ColumnHeaderStyle="{StaticResource STL_DataGridColumnHeaderReporting}"
AlternatingRowBackground="#A8A8A8"
CanUserResizeColumns="False"
>
<DataGrid.Columns>
<DataGridTextColumn Header="AnlV-Nr"
Binding="{Binding AnlVPara}"
Width="60"/>
<DataGridTextColumn Header="gültig ab"
Binding="{Binding TextGueltigAb}"
Width="68"/>
<DataGridTextColumn Header="Text"
Binding="{Binding ParaText}"
Width="750"/>
<DataGridTextColumn Header="Info"
Binding="{Binding Info}"
Width="*"/>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
<StackPanel Background="#A8A8A8" HorizontalAlignment="Center" Margin="10,268,0,141" Width="1010" >
<Label Content="Bearbeitungsbereich" FontWeight="Bold" FontSize="12" Height="33" />
</StackPanel>
<StackPanel>
<StackPanel Orientation="Horizontal" Background="#A8A8A8" HorizontalAlignment="Center"
Width="1010" Margin="0,294,0,0" Height="31">
<Label Height="25" Width="60" Margin="20, 0, 0, 0" Content="AnlV-Nr.:" />
<ComboBox IsEditable="True" Background="gray" Height="22" Width="69" ItemsSource="{Binding AnlVPara}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding lstAnlVTexte}"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<CheckBox Height="15" Margin="10, 0, 0, 0" />
<Label Height="26" Width="122" Content="Editierwarnungen" />
<StackPanel Height="48" Width="100"/>
</StackPanel>
<StackPanel Height="22" Orientation="Horizontal">
<Label Margin="20, 0, 0, 0" Content="gültig ab:" Height="27" />
<TextBox Background="LightGray" Height="20" Width="100" />
</StackPanel>
<StackPanel Height="50" Orientation="Horizontal">
<Label Content="Text:" Height="27" Width="38" Margin="42,0,0,10" />
<TextBox Background="LightGray" Width="500" Height="43" />
</StackPanel>
<StackPanel Orientation="Horizontal" >
<Label Content="Info:" Height="27" Width="38" Margin="42,0,0,0" />
<TextBox Background="LightGray" Width="500" Height="20" />
<Button x:Name="BTN_speichern" Width="80" Height="18" Margin="20,0,0,0" Content="Speichern"
Style="{StaticResource STL_ButtonStandard}" Command="{Binding icdSpeichern}"/>
</StackPanel>
</StackPanel>
</Grid>
</Window>
ViewModel:
using Newtonsoft.Json;
using QBondsData.DBModels;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Linq;
namespace QBondsFrontend.ViewModels.Input
{
public class AnlVTexteViewModel : BaseViewModel
{
#region data
private string _AnlVPara;
private DateTime _TextGueltigAb;
private string _ParaText;
private string _Info;
private List<AnlVhistText> _lstAnlVTexte;
private string _search;
#endregion
#region constructor
public AnlVTexteViewModel()
{
icdFilterDelete = new RelayCommand<object>(parameter => filterdelete(), parameter => true);
icdSpeichern = new RelayCommand<object>(parameter => speichern(), parameter => true);
GetData();
}
#endregion
#region members
public ICommand icdFilterDelete { get; set; }
public ICommand icdSpeichern { get; set; }
private string Search
{
get { return _search; }
set
{
_search = value;
OnPropertyChanged("Search");
}
}
public string AnlVPara
{
get
{
return _AnlVPara;
}
set
{
_AnlVPara = value;
OnPropertyChanged("AnlVPara");
}
}
public DateTime TextGueltigAb
{
get
{
return _TextGueltigAb;
}
set
{
_TextGueltigAb = value;
OnPropertyChanged("TextGueltigAb");
}
}
public string ParaText
{
get
{
return _ParaText;
}
set
{
_ParaText = value;
OnPropertyChanged("ParaText");
}
}
public string Info
{
get
{
return _Info;
}
set
{
_Info = value;
OnPropertyChanged("Info");
}
}
public List<AnlVhistText> lstAnlVTexte
{
get { return _lstAnlVTexte; }
set
{
_lstAnlVTexte = value;
OnPropertyChanged("lstAnlVTexte");
}
}
#endregion
#region methods
private void filterdelete()
{
}
private void speichern()
{
}
private async Task GetData()
{
HttpResponseMessage Response = await Globals.SendRequest("AnlVTexte/GetAnlVTexte"
, "GET");
if (Response.IsSuccessStatusCode)
{
lstAnlVTexte = JsonConvert.DeserializeObject<List<AnlVhistText>>
(await Response.Content.ReadAsStringAsync());
}
else
{
lstAnlVTexte = new List<AnlVhistText>();
Application.Current.Dispatcher.Invoke((Action)delegate
{
Globals.CloseReportByHash(this.GetHashCode()
, "Fehler! (HTTP Status " + Response.StatusCode + ")." +
"Kontaktieren Sie den Support.");
});
}
}
#endregion
}
}
When you change the type of lstAnlVTexte to ICollectionView you get two events CurrentChanged and CurrentChanging which you can handle in your viewmodel. From the ICollectionView you can get the CurrentItem.
Like this:
private List<AnlVhistText> _anlVTexte = new List<AnlVhistText>();
public AnlVTexteViewModel()
{
[...]
lstAnlVTexte = new CollectionView(_anlVTexte);
lstAnlVTexte.CurrentChanged += SelectionChanged; // raised after the current item has been changed.
lstAnlVTexte.CurrentChanging += SelectionChanging; // raise before changing the current item. Event handler can cancel this event.
}
private void SelectionChanged(object sender, EventArgs e)
{
var selectedItem = lstAnlVTexte.CurrentItem;
}
private void SelectionChanging(object sender, CurrentChangingEventArgs e)
{
}
private ICollectionView _lstAnlVTexte;
public ICollectionView lstAnlVTexte
{
get { return _lstAnlVTexte; }
set
{
_lstAnlVTexte = value;
OnPropertyChanged("lstAnlVTexte");
}
}
Here's a sample using the community toolkit mvvm and linq.
If you're not familiar, the toolkit does code generation.
This is a simple scenario to illustrate the approach.
Mainwindowviewmodel.
public partial class MainWindowViewModel : ObservableObject
{
[ObservableProperty]
private int selectedFilterInt = -1;
partial void OnSelectedFilterIntChanged(int newValue)
{
FilteredList = new ObservableCollection<MyItem>(FullList.Where(x=>x.Category == selectedFilterInt).ToList());
}
public List<int> FilterOptions { get; set; } = new List<int> {1,2,3};
private List<MyItem> FullList= new List<MyItem>
{
new MyItem{ Category = 1},
new MyItem{ Category = 1},
new MyItem { Category = 1 },
new MyItem { Category = 2 },
new MyItem { Category = 2 },
new MyItem { Category = 3 }
};
[ObservableProperty]
private ObservableCollection<MyItem> filteredList = new ObservableCollection<MyItem>();
public MainWindowViewModel()
{
FilteredList = new ObservableCollection<MyItem>(FullList);
}
}
There's a full list of all the items.
But a filtered list is going to be bound to the itemssource of my listbox ( equivalent to your datagrid ).
Due to the code generated, when selectedFilterInt changes, OnSelectedFilterIntChanged will be called. It's got a handler listening for property changed of SelectedFilterInt if you dug into the generated code.
That method uses a linq where to filter the full list into filtered list.
Setting that filtered list property raises property changed and the view re reads the new collection.
MainWindow. ( I did mention this is simplified )
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<StackPanel>
<ComboBox SelectedItem="{Binding SelectedFilterInt}"
ItemsSource="{Binding FilterOptions}"/>
<ListBox ItemsSource="{Binding FilteredList}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Category}"/>
<TextBlock Text="{Binding Comment}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</Grid>
</Window>
and MyItem
public partial class MyItem : ObservableObject
{
[ObservableProperty]
private int category = 0;
[ObservableProperty]
private string comment = "Some test string";
}
Which is a bit underwhelming visually but works:
In your code you need to get all the data into a collection.
Call that FulList.
You then need another collection which will be the filtered data.
Call this FilteredList.
Bind itemssource to FilteredList
Initially, you presumably want FilteredList to be = FullList
Then when the user selects something in the combobox you need to react to that.
You could bind selecteditem to a property and act in the setter or handle propertychanged like my code does.
However you do it, you get a new integer.
You then use that to filter FullList into a new collection which will replace the bound FilteredList.
You also need to somehow have one entry per AnlV nr whatever that is in your combobox.
AnlV nr isn't going to work as a property name since it's got a space but it is the equivalent to Category in my sample.
You will use that selected value in the linq.
Substitute the name of that property for Category. Substitute the type of whatever your collection is. Maybe that's AnlVhistText. I'm not sure.

Prevent showing details when hyperlink is clicked

I'm wondering how to prevent showing details row in DataGrid, when somebody clicks on hyperlink or button inside a cell. It's really annoying when you try to click hyperlink and details show instead of link.
Another problem is that I have some action buttons in one column, so when details are collapsed then you must first click row to show details and then click for example edit button.
Sample:
MainWindow.xaml.cs
namespace WpfApplication1
{
public class Item
{
public string Column0 { get; set; }
public string Mail { get; set; }
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
}
public ObservableCollection<Item> Items
{
get
{
ObservableCollection<Item> i = new ObservableCollection<Item>();
i.Add(new Item() { Column0 = "dsaads", Mail = "mail#sad.com" });
i.Add(new Item() { Column0 = "wdads", Mail = "adsdas#sad.com" });
return i;
}
}
public void HyperlinkClick(object sender, RoutedEventArgs e)
{
MessageBox.Show("Clicked");
}
}
}
MainWindow.xaml
<Window x:Class="WpfApplication1.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>
<DataGrid RowDetailsVisibilityMode="VisibleWhenSelected" ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Column0" Binding="{Binding Column0}" />
<DataGridHyperlinkColumn Header="Mail" Width="*" Binding="{Binding Mail}" >
<DataGridHyperlinkColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Padding" Value="2,0,2,0" />
<EventSetter Event="Hyperlink.Click" Handler="HyperlinkClick" />
</Style>
</DataGridHyperlinkColumn.ElementStyle>
</DataGridHyperlinkColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Grid Height="100">
</Grid>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
To see the problem: select first row and then try to click on hyperlink in a second row.
You can handle the tunneling event on hyperlink "OnPreviewMouseDown", that will prevent the event reaching the DataGrid which shows the RowDetailsTemplate.
private void OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var hyperlink = (Hyperlink)sender;
Process.Start(hyperlink.NavigateUri.AbsoluteUri);
e.Handled = true;
}
Full Example:
<Window x:Class="DummyTree.DataGridTest" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="DataGridTest" Height="300" Width="300">
<Grid>
<DataGrid ItemsSource="{Binding Customers}">
<DataGrid.Columns>
<DataGridTemplateColumn Header="First Name">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink PreviewMouseDown="OnPreviewMouseDown" NavigateUri="http://www.google.com">
<TextBlock Text="{Binding Name}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" />
<TextBlock Text=" details here" />
</StackPanel>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
Code Behind:
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
namespace DummyTree
{
public partial class DataGridTest : Window
{
public DataGridTest()
{
DataContext = new CustomerVM();
InitializeComponent();
}
private void OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var hyperlink = (Hyperlink)sender;
Process.Start(hyperlink.NavigateUri.AbsoluteUri);
e.Handled = true;
}
}
public class CustomerVM
{
public ObservableCollection<Customer> Customers { get; set; }
public CustomerVM()
{
Customers = new ObservableCollection<Customer> { new Customer { Name = "Leo" }, new Customer { Name = "Om" } };
}
}
public class Customer
{
public string Name { get; set; }
}
}

UserControl having binding that propagates to inner control

This is probably not a rocket science question, so forgive me for being a newcomer!
I have a UserControl that is for setting the name of a person (simple for test purposes).
PersonNameControl.xaml:
<UserControl x:Class="BindingPropagationTest.Controls.PersonNameControl"
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" Width="120" Height="23" Margin="0,0,0,0"
>
<TextBox Name="TextBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</UserControl>
and as you can see, it contains a TextBox that is the "real" textbox. The code behind looks like this.
PersonNameControl.xaml.cs:
using System.Windows.Controls;
using System.Windows;
using System.Diagnostics;
namespace BindingPropagationTest.Controls
{
public partial class PersonNameControl : UserControl
{
public static DependencyProperty nameProperty
= DependencyProperty.Register("PersonName", typeof(string), typeof(PersonNameControl));
public string PersonName
{
get
{
Debug.WriteLine("get PersonNameControl.PersonName = " + TextBox.Text);
return TextBox.Text;
}
set
{
Debug.WriteLine("set PersonNameControl.PersonName = " + value);
TextBox.Text = value;
}
}
public PersonNameControl()
{
InitializeComponent();
}
}
}
I use the usercontrol in MainWindow.xaml:
<Window x:Class="BindingPropagationTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:BindingPropagationTest.Controls"
xmlns:items="clr-namespace:BindingPropagationTest.ComboBoxItems"
Title="Testing binding in UserControl"
Width="179" Height="310">
<Canvas Height="241" Width="144">
<Label Canvas.Left="11" Canvas.Top="10" Content="Name" Height="28" Padding="0" />
<my:PersonNameControl x:Name="nameControl"
Width="120" Height="23"
HorizontalAlignment="Left" VerticalAlignment="Top"
PersonName="{Binding name}"
Canvas.Left="11" Canvas.Top="28" />
<Label Canvas.Left="11" Canvas.Top="57" Content="Address" Height="28" Padding="0" />
<TextBox Canvas.Left="11" Canvas.Top="75" Width="120" Text="{Binding address}"></TextBox>
<Label Canvas.Left="11" Canvas.Top="103" Content="Age" Height="28" Padding="0" />
<TextBox Canvas.Left="11" Canvas.Top="122" Height="23" Name="textBox1" Width="120" Text="{Binding age}" />
<ComboBox Canvas.Left="11" Canvas.Top="173" Height="23"
Name="comboBox1" Width="120" SelectionChanged="comboBox1_SelectionChanged">
<items:PersonComboBoxItem age="41" name="Donald Knuth" address="18 Donut Street" Height="23" />
<items:PersonComboBoxItem age="23" name="Vladimir Putin" address="15 Foo Street" Height="23" />
<items:PersonComboBoxItem age="32" name="Mike Hammer" address="10 Downing Street" Height="23" />
</ComboBox>
</Canvas>
</Window>
together with some normal TextBoxes as you can see.
In the code behind for MainWindow
MainWindow.xaml.cs:
using System.Windows;
using System.Windows.Controls;
using BindingPropagationTest.ComboBoxItems;
namespace BindingPropagationTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Person();
}
private void comboBox1_SelectionChanged
(object sender, SelectionChangedEventArgs e)
{
updateForm();
}
private void updateForm()
{
var item = (PersonComboBoxItem)comboBox1.SelectedItem;
DataContext = new Person()
{ age = item.age, name = item.name, address = item.address };
}
}
}
you see that I set DataContext to a "person".
Person.cs:
namespace BindingPropagationTest
{
public class Person
{
public string name {get; set; }
public int age { get; set; }
public string address { get; set; }
}
}
and as you notice I have invented an own ComboBoxItem like this.
PersonComboBoxItem.cs:
using System.Windows.Controls;
using System.Diagnostics;
namespace BindingPropagationTest.ComboBoxItems
{
public class PersonComboBoxItem : ComboBoxItem
{
private string _name = "";
public string name
{
get
{
return _name;
}
set
{
_name = value;
Content = _name;
}
}
public int age { get; set; }
public string address { get; set; }
public override string ToString()
{
Debug.WriteLine("name: " + name);
return name;
}
}
}
Running this application gives you this window:
And selecting a combobox item gives you this:
and as you can see, the name will not be filled in.
Why not?
You are almost there, a few things you need to change
Dependency properties are used like
public static DependencyProperty NameProperty = DependencyProperty.Register(
"Name",
typeof(string),
typeof(PersonNameControl));
public string Name
{
get
{
return (string)GetValue(NameProperty);
}
set
{
SetValue(NameProperty, value);
}
}
There is a very strict convention that is necessary for dependency properties. It must be called "NameProperty" if the Property is called Name. Also the property just sets and gets the dependency property.
You can them Bind the textbox to the property in the usercontrol like
<UserControl x:Class="BindingPropagationTest.Controls.PersonNameControl"
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"
x:Name="UserControl"
mc:Ignorable="d" Width="120" Height="23" Margin="0,0,0,0"
>
<TextBox Text="{Binding ElementName=UserControl, Path=Name}" Name="TextBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</UserControl>
I added the x:Name="UserControl" directive at the top, you could name it anything, as long as it matches the ElementName in the Binding
An extra note on how you are populating your comboBox
You could add a property on your MainWindow
private ObservableCollection<Person> _thePeople;
public ObservableCollection<Person> ThePeople
{
get
{
if (_thePeople == null)
{
List<Person> list = new List<Person>()
{
new Person() { name = "Bob" , address = "101 Main St." , age = 1000 },
new Person() { name = "Jim" , address = "101 Main St." , age = 1000 },
new Person() { name = "Mip" , address = "101 Main St." , age = 1000 },
};
_thePeople = new ObservableCollection<Person>(list);
}
return _thePeople;
}
}
then you can add to your main window the x:Name directive used on the usercontrol say
x:Name="TheMainWindow"
You can then use a datatemplate in your combobox as follows
<ComboBox ItemsSource="{Binding ElementName=TheMainWindow, Path=ThePeople}"
Height="23"
Name="comboBox1" Width="120" >
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding name}" />
<TextBlock Text="{Binding address}" />
<TextBlock Text="{Binding age}" />
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Because ObservableCollection was used in the code-behind the combobox will automatically get items added or removed whenever the code-behind adds or removes items from the "ThePeople" collection. Just call
ThePeople.Add(new Person());
and the combobox will automatically populate with a new entry

How to add a new row to a datagrid(WPF toolkit) when click on a button in the outside of datagrid

I want to add a new row in the datagrid when click on a button in the outside of a datagrid.
The datagrid is bound with SQL Server database, and it have some data at runtime
I want to add new data to the database through the database
I tried a lot, but it was unsuccessful
Anyone reply me it will be very helpful for me...
Advance thanks..
If the collection of data bound to the grid implements INotifyCollectionChanged, adding a new item to the collection will add the row to the datagrid.
When you read the data from the DB, store it in an ObservableCollection (which implements this interface), then bind the data to the grid.
Example:
public class ViewModel {
public ObservableCollection<Data> Items { get; set; }
...
}
In View.xaml:
...
<DataGrid ItemsSource={Binding Path=Items}" ... />
...
And you have to set the DataContext property of the view to an instance of ViewModel.
From now on, adding/removing items from the observable collection will automatically trigger the same operation on the data grid.
XAML:
<Window x:Class="NewItemEvent.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="341" Width="567" xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit">
<Grid>
<my:DataGrid AutoGenerateColumns="False" Margin="0,0,0,29" Name="dataGrid1">
<my:DataGrid.Columns>
<my:DataGridTemplateColumn Header="Name" Width="150">
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}" Margin="3 3 3 3"/>
<TextBlock Text="{Binding LastName}" Margin="3 3 3 3"/>
</StackPanel>
</DataTemplate>
</my:DataGridTemplateColumn.CellTemplate>
<my:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Text="{Binding FirstName}" Margin="3 3 3 3"/>
<TextBox Text="{Binding LastName}" Margin="3 3 3 3"/>
</StackPanel>
</DataTemplate>
</my:DataGridTemplateColumn.CellEditingTemplate>
</my:DataGridTemplateColumn>
<my:DataGridTextColumn Header="Age" Binding="{Binding Age}" Width="100"/>
</my:DataGrid.Columns>
</my:DataGrid>
<Button Height="23" HorizontalAlignment="Left" Name="AddNewRow" Click="AddNewRow_Click" VerticalAlignment="Bottom" Width="75">New Row</Button>
Code:
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
ObservableCollection<Person> People = new ObservableCollection<Person>();
public Window1()
{
InitializeComponent();
dataGrid1.ItemsSource = People;
}
private void AddNewRow_Click(object sender, RoutedEventArgs e)
{
People.Add(new Person() { FirstName = "Tom", LastName = "Smith", Age = 20 });
}
}
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}

WPF Templates and binding to DataContext in a GridView

I'm trying to create a series of bound columns in a RadGridView, and I'm using a template to create hyperlinks in two of the columns. Here is basically what I have:
<telerik:GridViewDataColumn IsReadOnly="True" UniqueName="Distributor" DataContext="{Binding Distributor}" CellTemplate="{StaticResource linkTemplate}"/>
and,
<DataTemplate x:Key="linkTemplate">
<TextBlock>
<Hyperlink DataContext={TemplateBinding DataContext} Click="Hyperlink_Click">
<TextBlock Text="{Binding Name}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
The RadGridView itself is bound to a set of DistributorContainer objects that have, among other things, a Distributor property. The linkTemplate refers directly to properties in the Distributor object, so the hyperlink's datacontext needs to be set to the Distributor.
Unfortunately, the Hyperlink's data context is the DistributorContainer object. I'm using the linkTemplate (as well as the Hyperlink_Click handler) on lists that bind to lists of Distributors, and I'd really like to re-use this template since it's basically the same thing.
Why isn't the template getting the Distributor as its DataContext through the TemplateBinding to the GridViewDataColumn?
Here is an example how to achieve this:
XAML
<Grid>
<Grid.Resources>
<DataTemplate x:Key="linkTemplate">
<TextBlock>
<Hyperlink>
<TextBlock
Text="{Binding
Value.Name,
RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type telerik:GridViewCell}}}" />
</Hyperlink>
</TextBlock>
</DataTemplate>
</Grid.Resources>
<telerik:RadGridView ItemsSource="{Binding}" AutoGenerateColumns="False">
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn
DataMemberBinding="{Binding Distributor1}"
CellTemplate="{StaticResource linkTemplate}" />
<telerik:GridViewDataColumn
DataMemberBinding="{Binding Distributor2}"
CellTemplate="{StaticResource linkTemplate}" />
</telerik:RadGridView.Columns>
</telerik:RadGridView>
</Grid>
C#
namespace WpfApplication1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext =
from i in Enumerable.Range(0, 10)
select new DistributorContainer()
{
ID = i,
Distributor1 = new Distributor() {
Name = String.Format("Distributor1 Name{0}", i) },
Distributor2 = new Distributor() {
Name = String.Format("Distributor2 Name{0}", i) }
};
}
}
public class DistributorContainer
{
public int ID { get; set; }
public Distributor Distributor1 { get; set; }
public Distributor Distributor2 { get; set; }
}
public class Distributor
{
public string Name { get; set; }
}
}

Categories