I have created a datagrid with each object has their own line. I added two column (edit,remove) but the command won't execute. I am using MVVM pattern. Here is the datagrid
<DataGrid Name="dgBillMeta" ItemsSource="{Binding FileObjectCollection}" AutoGenerateColumns="False" Grid.Row="0" IsReadOnly="False" >
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding id}"></DataGridTextColumn>
<DataGridTextColumn Header="Name" Binding="{Binding attName}"></DataGridTextColumn>
<DataGridCheckBoxColumn Header="Key" Binding="{Binding isKey}"></DataGridCheckBoxColumn>
<DataGridTextColumn Header="Type" Binding="{Binding attType}"></DataGridTextColumn>
<DataGridTextColumn Header="Required" Binding="{Binding isRequired}"></DataGridTextColumn>
<DataGridTextColumn Header="Location" Binding="{Binding attLoc}"></DataGridTextColumn>
<DataGridTextColumn Header="Length" Binding="{Binding attLength}"></DataGridTextColumn>
<DataGridTextColumn Header="Decimal" Binding="{Binding isDecimal}"></DataGridTextColumn>
<DataGridTextColumn Header="Alignment" Binding="{Binding attAlignment}"></DataGridTextColumn>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Edit"></Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding remCommand}" Content="Remove"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
I can see edit, and remove but when clicking on it, the object does not execute from my ModelView. If I put the button outside the datagrid ( anywhere on the windows, it does work).
Here how the ViewModel works
internal class BillMetaDataViewModel
{
private ObservableCollection<BillMetaData> _MyDataList;
private Command removeCommand;
public BillMetaDataViewModel()
{
Database dbobj = new Database();
MongoDatabase dtbase = dbobj.getDatabase;
var collection = dtbase.GetCollection<BillMetaData>("BillMetaData");
var entity = collection.FindAll();
_MyDataList = new ObservableCollection<BillMetaData>(entity.ToList());
removeCommand = new Command(removeComm);
}
public ObservableCollection<BillMetaData> FileObjectCollection
{
get { return _MyDataList; }
}
public void removeComm()
{
MessageBox.Show("Hello MessageBox");
}
public Command remCommand
{
get { return removeCommand; }
}
}
I may be missing selection number, but i am trying to learn first I believe it has to do something with the path but i am not sure how it would work. I have defined my datacontext on the xaml as follow
InitializeComponent();
DataContext = new BillMetaDataViewModel();
The DataTemplate for the button doesn't set the DataContext for button, try the following
Set the Name of the DataGrid to x:Name and
<DataGrid x:Name="dgBillMeta" ItemsSource="{Binding FileObjectCollection}" AutoGenerateColumns="False" Grid.Row="0" IsReadOnly="False" >
use element name and set the correct binding path.
<DataGridTemplateColumn Header="delete">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Command="{Binding Path=DataContext.remCommand, ElementName=dgBillMeta}" Content="Remove"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Related
i am using WPF, connected to SQL DataBase via LinqToSql.
I have filled DataGrid using ItemsSource.
I would like to clear everything in my DataGrid, except first two rows(ID,first and second name), and Headers ofcourse, by pressing a button. All items i would like to(either set to null or 0) remove, are floats, but I can't find the right logic to do that.
Here is the picture of my DataGrid-->
public partial class Spisak : Microsoft.Office.Interop.Excel.Window
{
DiplomskiDataContext diplomski = new DiplomskiDataContext();
public Spisak()
{
InitializeComponent();
dataGridRadnici.ItemsSource = diplomski.Radniks.ToList();
}
}
This is my code behind, and here is Xaml code:
<DataGrid HorizontalAlignment="Left" Name="dataGridRadnici" AutoGenerateColumns="False" Height="260" Margin="10,120,0,0" VerticalAlignment="Top" Width="550">
<DataGrid.Columns>
<DataGridTextColumn Header="Ime" Binding="{Binding Ime}"></DataGridTextColumn>
<DataGridTextColumn Header="Prezime" Binding="{Binding Prezime}"></DataGridTextColumn>
<DataGridTextColumn Header="BrSati" Binding="{Binding BrojSati, Converter={StaticResource ThreePlaceConverter}}"></DataGridTextColumn>
<DataGridTextColumn Header="Prekovremeni" Binding="{Binding BrojPrekovremenih, Converter={StaticResource ThreePlaceConverter}}"></DataGridTextColumn>
<DataGridTextColumn Header="Gorivo" Binding="{Binding BrojDana, Converter={StaticResource ThreePlaceConverter}}"></DataGridTextColumn>
<DataGridTextColumn Header="Bonus" Binding="{Binding Bonus}"></DataGridTextColumn>
<DataGridTextColumn Header="VracanjeDuga" Binding="{Binding VracanjeDuga}"></DataGridTextColumn>
<DataGridTextColumn Header="UkZarada" Binding="{Binding UkupnaPlata, Converter={StaticResource ThreePlaceConverter}}"></DataGridTextColumn>
<DataGridTextColumn Header="UkSaGorivom" Binding="{Binding UkupnoSaGorivom, Converter={StaticResource ThreePlaceConverter}}"></DataGridTextColumn>
</DataGrid.Columns>
<DataGrid.ContextMenu>
<ContextMenu>
<MenuItem Header="Izmeni" Click="MenuItem_Click"></MenuItem>
<MenuItem Header="Obrisi" Click="MenuItem_Click_1"></MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
</DataGrid>
Change the type of the columns that you want to be able to blank out from float to Nullable<float> (float?) and simply set the properties to null:
var sourceList = dataGridRadnici.ItemsSource as List<Radnik>; //or whatever your data is called
foreach (var item in sourceList)
{
item.BrojPrekovremenih = null; // or 0
//set the other properties the same way...
}
You also need to implement the INotifyPropertyChanged interface and raise property change notifications in your data class.
Got a list of objects which is currently being displayed via a datagrid. What I need to do is when a user double clicks on a specified row it opens up another window which is a model showing the data associated with the object of the row that is currently selected. I can't figure out how to a) detect when the user double clicks and b) how to know which row the user double clicked on.
The XAML:
<DataGrid x:Name="BlueprintsDataGrid" Grid.Row="0" IsReadOnly="True"
ItemsSource="{Binding Path=Game.Blueprints, ElementName=uc}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="80*" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ME" Width="30*" Binding="{Binding MaterialEfficiency}"
HeaderStyle="{StaticResource HeaderRightJustify}"
CellStyle="{StaticResource ColumnRight}"/>
<DataGridCheckBoxColumn Header="BPO" Width="30*" Binding="{Binding IsOrginial}"
HeaderStyle="{StaticResource HeaderRightJustify}"/>
</DataGrid.Columns>
</DataGrid>
You could do something like the following:
<DataGrid x:Name="BlueprintsDataGrid" Grid.Row="0" IsReadOnly="True"
ItemsSource="{Binding Path=Game.Blueprints, ElementName=uc}"
SelectedItem="{Binding CurrentSelection}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="80*" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ME" Width="30*" Binding="{Binding MaterialEfficiency}"
HeaderStyle="{StaticResource HeaderRightJustify}"
CellStyle="{StaticResource ColumnRight}"/>
<DataGridCheckBoxColumn Header="BPO" Width="30*" Binding="{Binding IsOrginial}"
HeaderStyle="{StaticResource HeaderRightJustify}"/>
</DataGrid.Columns>
</DataGrid>
Note: CurrentSelection must exist in your ViewModel-class. This property has to implement the INotifyPropertyChanged interface and must be the type of object your ItemsSource is holding!
For recognizing the mouse double click you can extend the above xaml to something like
<DataGrid x:Name="BlueprintsDataGrid" Grid.Row="0" IsReadOnly="True"
ItemsSource="{Binding Path=Game.Blueprints, ElementName=uc}"
SelectedItem="{Binding CurrentSelection}"
AutoGenerateColumns="False">
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDoubleClick">
<i:InvokeCommandAction Command="{Binding DoubleClickedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="80*" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ME" Width="30*" Binding="{Binding MaterialEfficiency}"
HeaderStyle="{StaticResource HeaderRightJustify}"
CellStyle="{StaticResource ColumnRight}"/>
<DataGridCheckBoxColumn Header="BPO" Width="30*" Binding="{Binding IsOrginial}"
HeaderStyle="{StaticResource HeaderRightJustify}"/>
</DataGrid.Columns>
</DataGrid>
Note: You therefore need a property DoubleClickedCommand of the type ICommand in your ViewModel. There you can check for your CurrentSelection.
public ICommand DoubleClickedCommand { get; set; }
In your ViewModel constructor:
DoubleClickedCommand = new RelayCommand(DoubleClick);
And the method itself:
private void DoubleClick()
{
if(CurrentSelection == null) { return; }
// Do stuff in here
}
You could handle the MouseDoubleClick event and cast the DataContext of the source of the event:
private void OnMouseDoubleClick(object sender, MouseButtonEventArgs e)
{
var fe = e.OriginalSource as FrameworkElement;
if (fe != null)
{
var blueprint = fe.DataContext as BluePrint;
if (blueprint != null)
{
//open window...
}
}
}
XAML:
<DataGrid x:Name="BlueprintsDataGrid" Grid.Row="0" IsReadOnly="True"
ItemsSource="{Binding Path=Game.Blueprints, ElementName=uc}"
AutoGenerateColumns="False"
MouseDoubleClick="Dgm_MouseDoubleClick">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Width="80*" Binding="{Binding Name}"/>
<DataGridTextColumn Header="ME" Width="30*" Binding="{Binding MaterialEfficiency}"
HeaderStyle="{StaticResource HeaderRightJustify}"
CellStyle="{StaticResource ColumnRight}"/>
<DataGridCheckBoxColumn Header="BPO" Width="30*" Binding="{Binding IsOrginial}"
HeaderStyle="{StaticResource HeaderRightJustify}"/>
</DataGrid.Columns>
</DataGrid>
Change BluePrint to whatever the name of your class is.
I have been looking for a way to get data out from this datagrid combobox that i made. Specifically the selected value of every combobox from columns. I am new to WPF and would be really grateful if someone would help.
Thanks
XAML:
<DataGrid x:Name="tb" Margin="5,51,5,5" ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridCheckBoxColumn Header="Include" Binding="{Binding Include}"/>
<DataGridTemplateColumn Header="Measure" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Margin="2" ItemsSource="{Binding Measure}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
C#:
ObservableCollection<State> items = new ObservableCollection<State>();
foreach (string col in columns)
{
items.Add(new State()
{
Name = col,
Include = true,
Measure = new ObservableCollection<string>() { "Sum", "Average" }
});
}
DataContext = items;
Picture of the columns:
I think you're confusing stuff. I assume you want your State items to have a string Measure property, and not a collection of them, but you want to be able to select the Measure value from a Combo with several options...
If that's the case, then you should redefine your Measure property to be a single string, and not a collection.
ObservableCollection<State> items = new ObservableCollection<State>();
foreach (string col in columns)
{
items.Add(new State()
{
Name = col,
Include = true,
Measure = string.Empty // Initialize it to whatever you want
});
}
DataContext = items;
Then create the Measure values collection somewhere else in your DataContext, or if you don't have a DataContext other than your collection, you can define it in XAML.
And, finally, in your DataGrid you must bind both the ItemsSource and the SelectedItem properties of your Combos. They'll share the same ItemsSource, which must be fetched from wherever you put the collection, instead of the row's DataContext:
<DataGrid x:Name="tb" Margin="5,51,5,5" ItemsSource="{Binding}"
AutoGenerateColumns="False">
<DataGrid.Resources>
<!-- This is where the values are defined -->
<col:ArrayList x:Key="MeasureValues">
<sys:String>Sum</sys:String>
<sys:String>Average</sys:String>
</col:ArrayList>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridCheckBoxColumn Header="Include" Binding="{Binding Include}"/>
<DataGridTemplateColumn Header="Measure" Width="*">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox Margin="2"
SelectedItem="{Binding Measure}"
ItemsSource="{StaticResource MeasureValues}" />
<!-- And this is where you consume those values -->
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
If you don't wanna put the values in XAML, you'll have to define the collection in another DataContext and create a Binding to it somehow (using RelativeSource, ElementName and stuff like that).
This works with a DataGridComboBoxColumn, too, of course:
<DataGrid x:Name="tb" Margin="5,51,5,5" ItemsSource="{Binding}"
AutoGenerateColumns="False">
<DataGrid.Resources>
<!-- This is where the values are defined -->
<col:ArrayList x:Key="MeasureValues">
<sys:String>Sum</sys:String>
<sys:String>Average</sys:String>
</col:ArrayList>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
<DataGridCheckBoxColumn Header="Include" Binding="{Binding Include}"/>
<DataGridComboBoxColumn Header="Measure" Width="*"
SelectedItemBinding="{Binding Measure}"
ItemsSource="{StaticResource MeasureValues}" />
<!-- And this is where you consume those values -->
</DataGrid.Columns>
</DataGrid>
Here my DataGrid in wpfwin.xaml. I want to collect "Challan_No" value in list but i can't do this ..please help me
<DataGridTextColumn Header="Chalaan ID" Width="Auto" Binding="{Binding Id, Mode=OneWay}"/>
<DataGridTextColumn Header="Challan No" Width="Auto" Binding="{Binding Challan_No, Mode=OneWay}" IsReadOnly="True"/>
<DataGridTextColumn Header="Company" Width="Auto" Binding="{Binding Organization_Name, Mode=OneWay}"/>
<DataGridTextColumn Header="Client" Width="Auto" Binding="{Binding Organization, Mode=OneWay}"/>
<DataGridTextColumn Header="Date" Width="Auto" Binding="{Binding Date, Mode=OneWay}"/>
<DataGridTemplateColumn Header="select" Width="100" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="ckselect" ></CheckBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
And here, I tried some code to get it in .cs page
ArrayList list = new ArrayList();
for (int i = 0; i < myGrid.Items.Count; i++)
{
CheckBox mycheckbox = myGrid.Columns[5].GetCellContent(myGrid.Items[i]) as CheckBox;
if (mycheckbox.IsChecked == true)
{
int inde = this.myGrid.SelectedIndex;
DataRowView drv = (DataRowView)myGrid.Items[inde];
object ch = drv[1];
list.Add(ch);
}
}
first you could simply use a DataGridCheckBoxColumn instead of adding a CheckBox inside a DataGridTemplateColumn :
<DataGridTextColumn Header="Chalaan ID" Width="Auto" Binding="{Binding Id, Mode=OneWay}"/>
<DataGridTextColumn Header="Challan No" Width="Auto" Binding="{Binding Challan_No, Mode=OneWay}" IsReadOnly="True"/>
<DataGridTextColumn Header="Company" Width="Auto" Binding="{Binding Organization_Name, Mode=OneWay}"/>
<DataGridTextColumn Header="Client" Width="Auto" Binding="{Binding Organization, Mode=OneWay}"/>
<DataGridTextColumn Header="Date" Width="Auto" Binding="{Binding Date, Mode=OneWay}"/>
<DataGridCheckBoxColumn Header="select" Width="100" />
</DataGrid.Columns>
</DataGrid>
and to get the list of checked items:
var SelectedList=new List<YourDataGridItemType>();
for (int i = 0; i < MyDataGrid.Items.Count; i++)
{
var item = MyDataGrid.Items[i];
var mycheckbox = MyDataGrid.Columns[1].GetCellContent(item) as CheckBox;
if ((bool)mycheckbox.IsChecked)
{
SelectedList.Add(YourDataGridItemsList[i]);
}
}
where YourDataGridItemsList represent the list of objects that your DataGrid is Binded to .
I think it would be best if you added an IsSelected property to whatever type it is you are displaying and then just TwoWay bind that property to the checkbox column. That way you can simply do this to get the selected elements:
mycollection.Where(x=>x.IsSelected);
I have a DataGrid in my WPF application as below.
<DataGrid Name="stDataGrid" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Edit" CanUserResize="False" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button" Click="btnEdit_Click">
<StackPanel>
<Image Source="images/edit.png"/>
</StackPanel>
</Button>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" IsReadOnly="True"></DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Path=Age}" Header="Age" IsReadOnly="True"></DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Path=Sex}" Header="Sex" IsReadOnly="True"></DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
Binding data into DataGrid like this.
using (var context = new CLASS_DBEntities())
{
var query = from s in context.STUDENT
orderby s.STUDENT_NAME
select new {s.STUDENT_ID, Name = s.STUDENT_NAME, Age = s.STUDENT_AGE,
Sex = s.STUDENT_SEX};
stDataGrid.ItemsSource = query.ToList();
}
When user click Button in DataGrid, I need to get STUDENT_ID value. How can i do this ?
Set an attached property of the same type as student_id on your button and bind it relativly to the datacontext.student_id of the DataGridRow control which should be the parent to all yours cells in a row.
Once you enter btnEdit_Click method just read out the value from your attached property.
Finally found answer by myself.
in btnEdit_Click method,
dynamic customerRow = stDataGrid.SelectedItem;
MessageBox.Show(customerRow.STUDENT_ID+"");