I am using wpftoolkit from wpf.codeplex.com . While binding a data table(through linq object list) there is a collumn that contains a reference of another table content as a foreign key. So, generally, currently, on that column in datagrid, i want to show a combo box containing the element of another table and selelted item should be from my concerned table. Here is what I am writing:
<dg:DataGrid x:Name="UsersGrid" AutoGenerateColumns="False" CellEditEnding="UsersGrid_CellEditEnding" RowEditEnding="UsersGrid_RowEditEnding" PreviewKeyDown="UsersGrid_PreviewKeyDown">
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Binding="{Binding Path=Id}" Header="Id" Visibility="Hidden" />
<dg:DataGridTextColumn Binding="{Binding Path=Username}" Header="User Name" />
<dg:DataGridTextColumn Binding="{Binding Path=Password}" Header="Password" />
<dg:DataGridTextColumn Binding="{Binding Path=RoleId}" Header="Role ID" />
<dg:DataGridComboBoxColumn x:Name="Roles" ItemsSource="{Binding Path=TVRole}">
</dg:DataGridTemplateColumn>
</dg:DataGrid.Columns>
</dg:DataGrid>
For making the binding, the code behind file contains as the following code:
UsersGrid.ItemsSource = UserManager.GetAllUsers();
Problem is that, I am now don't know what to place in the "ItemsSource" property to achieve what i want for the DataGridComboBoxColumn column . Can anyone please help me? Again mentioning, i want to bind it with linq object.
There is a strange bug with a DataGridComboBoxColumn: the ItemsSource property doesn't support advanced bindings. But you can use DataGridTemplateColumn, and code will be like this:
<DataGrid ItemsSource="{Binding Users}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Path=Id}" Header="Id" Visibility="Hidden" />
<DataGridTextColumn Binding="{Binding Path=Username}" Header="User Name" />
<DataGridTextColumn Binding="{Binding Path=Password}" Header="Password" />
<DataGridTextColumn Binding="{Binding Path=RoleId}" Header="Role ID" />
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Path=DataContext.Roles, RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"
DisplayMemberPath="Title" SelectedValuePath="Id" SelectedValue="{Binding RoleId, Mode=TwoWay}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
And add this code to the constructor of the View:
var model = new MainViewModel() { Users = UserManager.GetAllUsers(), Roles = UserManager.GetAllRoles() };
this.DataContext = model;
Where the MainViewModel is an auxiliary class:
public class MainViewModel
{
public List<Role> Roles { get; set; }
public List<User> Users { get; set; }
}
Another way is using a list of UserViewModel instead of a list of User, where each viewmodel class contains the list of roles, so it will be possible to use a correct binding. But it is a more complicated solution than above-mentioned one.
Related
I have data grid that I want to update from external fields
I don't want to directly affect the data base
<DataGrid
AlternatingRowBackground="CadetBlue "
AutoGenerateColumns="False"
CanUserAddRows="False"
CanUserDeleteRows="False"
IsReadOnly="True"
ItemsSource="{Binding Path=Addresss ,Mode=TwoWay}"
SelectedItem="{Binding Path=Address, Mode=OneWayToSource}"
ColumnHeaderStyle="{StaticResource CenterColumnHeader}"
CellStyle="{StaticResource DataGridContentCellCentering}">
<DataGrid.Columns>
<DataGridTextColumn
Width="70"
Binding="{Binding Path=AddType}"
Header="النوع"
/>
<DataGridTextColumn
Width="80"
Binding="{Binding Path=AddAdjective}"
Header="الوصف" />
<DataGridTextColumn
Width="250"
Binding="{Binding Path=AddAddress}"
Header="العنوان" />
</DataGrid.Columns>
</DataGrid>
I made a combo box
<ComboBox x:Name="Cbox1" Width="69"
materialDesign:HintAssist.Hint="النوع"
Background="#252525"
ItemsSource="{Binding Path=AddTypelist}"
SelectedValue="{Binding Path=Addressl.AddType}"
Style="{StaticResource MaterialDesignFilledComboBoxFocus}"
IsTextSearchEnabled="True" IsTextSearchCaseSensitive="True"/>
I don't want the change to happen automatically. When I change it in the combo box, I want the process to be done with a button
I tried this method
public AddressTable Address
{
get => _address;
set
{
_address = value;
_addressl = _address;
NotifyOfPropertyChange(()=>Address);
}
}
private AddressTable _addressl;
public AddressTable Addressl
{
get => _addressl;
set
{
_addressl = value;
NotifyOfPropertyChange(() => Addressl);
}
}
But it didn't work
I have searched all over and keep finding similar examples that are not working for me. Can someone point out where I am messing up?
I have two tables AlarmName and AlarmLevel. Linked by a foreign key AlarmName.AlarmLevelID -> AlarmLevel.Id.
I have the following in my XAML:
<DataGrid Name="Alarms" AutoGenerateColumns="false">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="75" />
<DataGridTextColumn Binding="{Binding Description}" Header="Description" />
<DataGridTextColumn Binding="{Binding AlarmLevel.Name}" Header="AName" Width="75"/>
<DataGridTemplateColumn Header="Alarm Level">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.AlarmLevel, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
DisplayMemberPath="Name"
SelectedValuePath="AlarmLevelID"
SelectedValue="{Binding Id}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
And the following in my code behind:
UISimulation1.Data.UISimulationDBDataContext db = new UISimulation1.Data.UISimulationDBDataContext();
var alarm = (from v in db.AlarmNames
select v);
Alarms.ItemsSource = alarm;
The DataGridTextColumns work and pull the right data. However, I can not make the combobox work or display anything no matter what I try.
Clearly, I am missing something obvious; but have tried 50 variants of the combobox based on google examples with zero results.
--rt
You need to expose the records in the AlarmLevel table using a public property that you bind the ItemsSource property of the ComboBox to. Please refer to the following sample code.
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = this;
using (UISimulation1.Data.UISimulationDBDataContext db = new UISimulation1.Data.UISimulationDBDataContext())
{
AlarmNames = (from v in db.AlarmNames
select v).ToList();
AlarmLevels = (from v in db.AlarmLevels
select v).ToList();
}
}
public IEnumerable AlarmNames { get; private set; }
public IEnumerable AlarmLevels { get; private set; }
}
<DataGrid Name="Alarms" ItemsSource="{Binding AlarmNames}" AutoGenerateColumns="false">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name" Width="75" />
<DataGridTextColumn Binding="{Binding Description}" Header="Description" />
<DataGridTextColumn Binding="{Binding AlarmLevel.Name}" Header="AName" Width="75"/>
<DataGridTemplateColumn Header="Alarm Level">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding DataContext.AlarmLevels, RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}"
DisplayMemberPath="Name"
SelectedValuePath="AlarmLevelID"
SelectedValue="{Binding Id}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
The DataGrid columns don’t belong to the visual or logical tree of the DataGrid, see this
I have a DataGrid with 3 columns(id, User, MachineID) I am looking to get the machine Id from this grid. Preferably I would like to use a check box to select multiple rows, but I just need to get one row at a time sorted.
<DataGrid Grid.Column="0" Grid.Row="0"
DockPanel.Dock="Bottom" AutoGenerateColumns="False"
ItemsSource="{Binding Path=UserList}" SelectionMode="Single"
SelectedItem="{Binding SelectedCpuID, Mode=TwoWay}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding UserID}"></DataGridTextColumn>
<DataGridTextColumn Width="200" Header="User" Binding="{Binding UserName}"></DataGridTextColumn>
<DataGridTextColumn Width="210" Header="Machine ID" Binding="{Binding MachineID}"></DataGridTextColumn>
It is bound to the view model but I get the object name instead of the contents of the row(application.Users). I have tried SelectedItem="{Binding SelectedCpuID.MachineID, Mode=TwoWay}"> which also did not work. I am quite new to WPF and data binding so I have been trying to work off another program that we have produced here which does a similar thing but uses combo boxes and it doesn't seem to work the same with the datagrid.
Any one know how to get this to work please let me know.
Thanks,
Sam
You are probably just missing the COLUMNS of the data grid for the display. The DataGrid's ItemsSource, such as a DataTable, or a Collection (List<>, or other IEnumerable) of all items you want to present to the user. From there, you need to define each column you want to display and give those characteristics too (width, font, coloring, whatever). The binding of each column is a path as it would be found on each entry from the UserList.
Then,
<DataGrid
ItemsSource="{Binding UserList}"
AutoGenerateColumns=False >
<DataGrid.Columns>
<DataGridTextColumn Header="Id" Binding="{Binding Path=Id}" />
<DataGridTextColumn Header="User" Binding="{Binding Path=User}" />
<DataGridTextColumn Header="Machine" Binding="{Binding Path=MachineID}" />
</DataGrid.Columns>
</DataGrid>
Now, your UserList source. If it is such as a List(), then each property should be available via getter/setter, such as...
public class SomeUserClass()
{
public string Id {get; set;}
public string User {get; set;}
public string MachineID {get; set; }
}
I have a DataGrid:
<DataGrid x:Name="DG" ItemsSource="{Binding}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="?" Binding="{Binding l}">
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
In DataContext of the DataGrid there is the collection of class X:
public ObservableCollection<xxx> col{ get; set; }// = DataContext of DG
private string lName;
public string LName
{
get { return lName; }
set
{
lName= value;
NotifyPropertyChanged("LName");
}
}
I want lName will be the header of a particular column in DataGrid
I try this way:
<DataGridTextColumn Binding="{Binding l}">//l=prop of xxx class that contains the collection
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding DataContext.LName,
RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
It did not work
how can do this?
Try {Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.LName}
Also I wouldn't play with name cases. WPF is pretty case-sensivity. Avoid of using one-symbol names
Binding paths are also case-sensitive. There is no property lName in your DC.
I have the next class:
public class GridViewControlModel : NotificationObject
{
DataTable datasource;
public DataTable Datasource
{
get
{
return datasource;
}
set
{
datasource = value;
RaisePropertyChanged("Datasource");
}
}
ObservableCollection<string> fieldsNames;
public ObservableCollection<string> FieldsNames
{
get
{
if (fieldsNames == null)
{
fieldsNames = new ObservableCollection<string>();
}
return fieldsNames;
}
set
{
fieldsNames = value;
RaisePropertyChanged("FieldsNames");
}
}
//and more properties
}
The property "FieldsNames" contains list of columns Headers that I want bind to GridView data column header.
In my ViewModel I created property - GridViewControlModel CurrentGridViewData and I want to bind my GridView columns headers to my CurrentGridViewData.FieldsNames[indexes]
for example
<dxg:GridColumn1 Header="{Binding CurrentGridViewData, Path=CurrentGridViewData.FieldsNames[0]}">
<dxg:GridColumn2 Header="{Binding CurrentGridViewData, Path=CurrentGridViewData.FieldsNames[1]}">
and so on...
Im working with DevExpress gridCointrol but Im don`t think its matter .
How can I bind property to specific ObservableCollection index?
I will explain what Im trying to do.
I have GridControl with many views.
When the user switch view the grid control need to change its entire structure (different number of columns, columns headers, column size, types and etc). I created a class which contains all the properties and settings for each view (this CurrentGridViewData class from my question) and when the user switch view I change the reference fo CurrentGridViewData to the right view instance and by binding I want to make all grid changes.
Is there a better way?
Thanks
Thanks
I think I found possible solution related to DevExpress GridControl.
Look at the next link
http://documentation.devexpress.com/#wpf/CustomDocument10121
What are you thinking? Is it better approach than using DataTemplate?
Thanks
My solution for you would be to create a DataTemplate for each of the model you want to bind to your DataGrid.
For example lets say you have 3 different DataTables: OrdersDataTable, CustomersDataTable and ProductsDataTable.
First thing would be to replace your DataGrid control by a simple ContentControl.
<ContentControl Content="{Binding DataTable}"/>
Then add and create those DataTemplate in your application ressources.
<DataTemplate DataType="{x:Type local:OrdersDataTable}">
<DataGrid ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Header="ID"/>
<DataGridTextColumn Binding="{Binding Tax}" Header="Tax"/>
<DataGridTextColumn Binding="{Binding NetAmount}" Header="NetAmount"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CustomersDataTable}">
<DataGrid ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Header="ID"/>
<DataGridTextColumn Binding="{Binding FirstName}" Header="First name"/>
<DataGridTextColumn Binding="{Binding LastName}" Header="Last name"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:ProductsDataTable}">
<DataGrid ItemsSource="{Binding}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding ID}" Header="ID"/>
<DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
<DataGridTextColumn Binding="{Binding Quantity}" Header="Quantity"/>
<DataGridTextColumn Binding="{Binding UnitPrice}" Header="UnitPrice"/>
</DataGrid.Columns>
</DataGrid>
</DataTemplate>
This way, when you will bind your DataTable to the content control, it will lookup for the concrete DataTable type and crawl the application resources to find a corresponding DataTemplate to display your DataTable.
I recommend to use a Style for the DataGrid control so you don't have to reproduce the style in all the DataTemplate.
NB: The DataGrid.ItemsSource might not be correct for you, just adapt it.