I've already search for any solutions but I just couldn't find one. I've found several post in several websites/forum that discusses my problem, but I want a very simple solution.
while (SQLDataReader.Read())
{
var view = new GridView();
view.Columns.Add(new GridViewColumn { Header = "User", DisplayMemberBinding = new Binding("User") });
view.Columns.Add(new GridViewColumn { Header = "hostNamedb", DisplayMemberBinding = new Binding("hostNamedb") });
view.Columns.Add(new GridViewColumn { Header = "fullName", DisplayMemberBinding = new Binding("fullName") });
view.Columns.Add(new GridViewColumn { Header = "location", DisplayMemberBinding = new Binding("location") });
view.Columns.Add(new GridViewColumn { Header = "department", DisplayMemberBinding = new Binding("department") });
view.Columns.Add(new GridViewColumn { Header = "position", DisplayMemberBinding = new Binding("postion") });
view.Columns.Add(new GridViewColumn { Header = "message", DisplayMemberBinding = new Binding("message") });
view.Columns.Add(new GridViewColumn { Header = "status", DisplayMemberBinding = new Binding("status") });
view.Columns.Add(new GridViewColumn { Header = "ip", DisplayMemberBinding = new Binding("ip") });
ListView2.View = view;
ListView2.Items.Add(new
{
User = SQLDataReader["User"].ToString(),
hostNamedb = SQLDataReader["hostNamedb"].ToString(),
fullName = SQLDataReader["fullName"].ToString(),
location = SQLDataReader["location"].ToString(),
department = SQLDataReader["department"].ToString(),
position = SQLDataReader["position"].ToString(),
message = SQLDataReader["message"].ToString(),
status = SQLDataReader["status"].ToString(),
ip = SQLDataReader["ip"].ToString(),
});
}
userName_click = System.Convert.ToString(ListView2.Items[var2].User.Text.ToString());
hostName_click = System.Convert.ToString(ListView2.Items[var2].hostNamedb.Text.ToString());
fullName_form = System.Convert.ToString(ListView2.Items[var2].SubItems[2].Text.ToString());
location_form = System.Convert.ToString(ListView2.Items[var2].SubItems[3].Text.ToString());
department_form = System.Convert.ToString(ListView2.Items[var2].SubItems[4].Text.ToString());
position_form = System.Convert.ToString(ListView2.Items[var2].SubItems[5].Text.ToString());
message_Form = System.Convert.ToString(ListView2.Items[var2].SubItems[6].Text.ToString());
status_form = System.Convert.ToString(ListView2.Items[var2].SubItems[7].Text.ToString());
id_form = System.Convert.ToString(ListView2.Items[var2].SubItems[8].Text.ToString());
userIP_click = System.Convert.ToString(ListView2.Items[var2].SubItems[9].Text.ToString());
Basically, the codes here works like this: the program will get the data from my database and then add them to my Listview2.
(Also, can someone check if my adding items to listview2 will work? I can't run the program right now because I really have to do lots of re-coding. I'm migrating from VB.NET to C# WPF).
Going on: each variable, like userName_click will have the data from the
listview2-row-VAR2 with columns 0 to 8.
I tried replacing the subitems[n] with binding names like User from -->
(new binding("user")) but it didn't work.
by the way, here is my XAML code in listview2.
<ListView x:Name="ListView2" HorizontalAlignment="Left" Height="34" Margin="-10,446,-22,-50" VerticalAlignment="Top" Width="702" Grid.ColumnSpan="3" ClipToBounds="True">
<ListView.View>
<GridView ColumnHeaderContainerStyle="{DynamicResource CustomHeaderStyle}">
<l:FixedWidthColumn Header="username" DisplayMemberBinding="{Binding User}" FixedWidth="65"/>
<l:FixedWidthColumn Header="Host Name" DisplayMemberBinding="{Binding hostNamedb}" FixedWidth="65"/>
<l:FixedWidthColumn Header="fullname" DisplayMemberBinding="{Binding fullName}" FixedWidth="85"/>
<l:FixedWidthColumn Header="location" DisplayMemberBinding="{Binding location}" FixedWidth="65"/>
<l:FixedWidthColumn Header="department" DisplayMemberBinding="{Binding department}" FixedWidth="65"/>
<l:FixedWidthColumn Header="position" DisplayMemberBinding="{Binding position}" FixedWidth="65"/>
<l:FixedWidthColumn Header="message" DisplayMemberBinding="{Binding message}" FixedWidth="65"/>
<l:FixedWidthColumn Header="status" DisplayMemberBinding="{Binding status}" FixedWidth="65"/>
<l:FixedWidthColumn Header="id" DisplayMemberBinding="{Binding id}" FixedWidth="65"/>
<l:FixedWidthColumn Header="ip" DisplayMemberBinding="{Binding ip}" FixedWidth="65"/>
</GridView>
</ListView.View>
</ListView>
Your solution is not following, but since you know about binding I think you already know that. I can not help you making your existing code work, but instead suggest the following: Use an observable collection to hold your DB-Objects with fields like user, hostNamedb...
public DbEntry(){
user = SQLDataReader["User"].ToString();
hostNamedb = SQLDataReader["hostNamedb"].ToString();
fullName = SQLDataReader["fullName"].ToString();
location = SQLDataReader["location"].ToString();
...
}
These will fill your observable collection. Next you bind to that collection via ItemsSource in your XAML.
<ListView ItemsSource="{Binding DBObjectsCollection}">
Filling your variables with data is now only a matter of specifiying the index of the "row" from which to get the data, and getting the right field or property, e.g.
userName_click = DBObjectsCollection[2].user;
Mind you, this code will not work. This is only meant to be a basic pointer to how to solve your problem in WPF. There is already tons on information on WPF, but feel free to ask questions, should any arise.
Related
The source code can be found here : https://www.codeproject.com/Articles/24973/TreeListView
The way the original author has set it up, is the data is filled in the xaml itself. I need to create the TreeViewList inside of my ViewModel, but I can't figure out how to bind my own TreeViewList within the xaml to display it properly.
Here's an example of me creating a tree in the code behind and calling the window.
public TreeListView TreeList { get; set; } = new TreeListView();
private void generateTree()
{
TreeList.Columns.Add(new GridViewColumn() { Header = "Col1" });
TreeList.Columns.Add(new GridViewColumn() { Header = "Col2" });
TreeList.Columns.Add(new GridViewColumn() { Header = "Col3" });
}
public ICommand AssemblyTreeCommand => new RelayCommand(AssemblyTree, p => CanAssemblyTree);
public bool CanAssemblyTree { get; set; } = true;
private void AssemblyTree(object parameter)
{
generateTree();
AssemblyTreeDialogWindow dialog = new AssemblyTreeDialogWindow()
{
DataContext = this,
Topmost = true
};
dialog.ShowDialog();
}
AssemblyTreeDialog Window class looks like this:
<local:TreeListView AllowsColumnReorder="True" ItemsSource="{Binding TreeList}">
<!--Create an item template to specify the ItemsSource-->
<local:TreeListView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}" />
</local:TreeListView.ItemTemplate>
<local:TreeListView.Columns>
<!--Create the first column containing the expand button and the type name.-->
<GridViewColumn Header="Name" Width="200">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--The Expander Button (can be used in any column (typically the first one))-->
<local:TreeListViewExpander/>
<!--Display the name of the DataElement-->
<TextBlock Text="{Binding}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!--Create a second column containing the number of children.-->
<GridViewColumn Header="Children" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<!--Display the size of the DataElement-->
<TextBlock Text="{Binding Children.Count}" HorizontalAlignment="Right"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<!--Create a third column containing the brush of the material.-->
<GridViewColumn Header="Brush" Width="100">
<GridViewColumn.CellTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!--Border showing the actual color-->
<Border Background="{Binding Brush}" CornerRadius="2"
Width="16" Height="16"
BorderThickness="1" BorderBrush="DarkGray"/>
<!--Display the brush-->
<TextBlock Text="{Binding Brush}"/>
</StackPanel>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</local:TreeListView.Columns>
<!--Create some sample data-->
<MaterialGroup>
<MaterialGroup>
<DiffuseMaterial Brush="Blue"/>
<DiffuseMaterial Brush="Red"/>
<SpecularMaterial Brush="Orange"/>
</MaterialGroup>
<EmissiveMaterial Brush="AliceBlue"/>
</MaterialGroup>
</local:TreeListView>
Interestingly if I bind the line <GridViewColumn Header="Name" Width="200"> so that it reads <GridViewColumn Header="{Binding TreeList}" Width="200">it gives me this:
I'll explain my end goal as best as possible.
The System is a giant list of parts. A main table displays all of the parts while a subtable displays all of the parts which make up that part. All parts (including those which are used to create other parts) exist within the MainTable. So a Parent part might have a set of children parts, which each individually have children parts which they are made up of. This is the relationship i'm trying to model using this tool.
The code that I've written maps the parts list out into a list of class objects which contain the data. I'll post it below. It's working to map to a TreeView right now.
A datastructure I've based it off is here : Treeview with multiple columns
private void generateTree(string PN)
{
Proces selectedRow = new Proces() { procesId = (int)Vwr.Table.SelectedRow.Row["PID"], procesName = (string)Vwr.Table.SelectedRow.Row["PN"], subProcesses = generateSubtable(PN) };
processes.Add(selectedRow);
}
public List<Proces> generateSubtable(string PN)
{
List<Proces> subTable = new List<Proces>();
foreach (DataRow mplrow in Vwr.Table.Tbl.Rows) if (mplrow["PN"].ToString() == PN)
MainVM.Modules.AllModules[0].SubVwr.Tables[0].LoadTableQuery.Prms[0].Val = mplrow[0];
MainVM.Modules.AllModules[0].SubVwr.Tables[0].Tbl = Db.GetTable(MainVM.Modules.AllModules[0].SubVwr.Tables[0].LoadTableQuery);
foreach (DataRow sub in MainVM.Modules.AllModules[0].SubVwr.Tables[0].Tbl.Rows)
{
Proces subItem = new Proces() { procesId = (int)sub["ItemNo"], procesName = sub["PN"].ToString(), subProcesses = generateSubtable(sub["PN"].ToString()) };
subTable.Add(subItem);
}
return subTable;
}
Found the answer! After some pretty extensive searching, and trying many different solutions. Thought i'd post incase someone else might also be trying to do the same.
credit:
http://dlaa.me/blog/post/9898803
In my WPF app I have a Listview with a couple columns and one column with a checkbox inside.
The xaml is as follows:
<ListView x:Name="listviewImported">
<ListView.View>
<GridView>
<GridViewColumn Header="Check" Width="50">
<GridViewColumn.CellTemplate>
<DataTemplate>
/*This line may be the prob.*/ <CheckBox IsChecked="{Binding MarkedForCheck}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Pos." Width="75" DisplayMemberBinding="{Binding PositionAsString}" />
<GridViewColumn Header="Value" Width="175" DisplayMemberBinding="{Binding ImportValue}" />
<GridViewColumn Header="Type" Width="175" DisplayMemberBinding="{Binding ImportValueTypeDescription}" />
</GridView>
</ListView.View>
</ListView>
The ItemSource is assigned like this:
listviewImported.ItemsSource = _catalog.ImportedList;
The ImportedList in the _catalog is of Type ImportedElem:
private List<ImportedElem> _importedList = new List<ImportedElem>();
This is the ImportedElem class:
public class ImportedElem : BaseElem {
public ImportedElem(int Position, string ImportValue) : base(Position, ImportValue) {
}
//MARKED FOR CHECK
public bool MarkedForCheck = true;
}
This is the problem:
When I add an ImportedElem to the List, then the Listview will update and the columns "Pos.", "Value" and "Type" contain the correct Data. However, the Column with the checkbox ("Check") always shows a nonchecked Checkbox after adding it to the List. The Data is correct, the column just shows the wrong Data. I can modify the checkbox in the list and it will update the Data, that is good. But the List should contain the correct Data right after adding the Element to the list, wich it is not doing. It would be very interesting to know why 3 columns are correct and the checkbox doesn't work.
change public bool MarkedForCheck = true; TO public bool MarkedForCheck {get;set;}
I can't seem to get this to work. Anyone have any ideas why?
Here is the markup:
<ListView Width="210" Height="83" Margin="0 0 5 0" Name="FiltersListView">
<ListView.View>
<GridView>
<GridViewColumn Header="Column" Width="Auto" DisplayMemberBinding="{Binding FilterColumn}"></GridViewColumn>
<GridViewColumn Header="Rule" Width="Auto" DisplayMemberBinding="{Binding FilterRule}"></GridViewColumn>
<GridViewColumn Header="String" Width="Auto" DisplayMemberBinding="{Binding FilterString}"></GridViewColumn>
</GridView>
</ListView.View>
</ListView>
Here is the window initializer:
public SelectionWindow()
{
InitializeComponent();
rows = new List<Row>();
// Create a new binding object and set the binding of this list view to it.
Binding myBinding = new Binding();
myBinding.Source = rows;
FiltersListView.SetBinding(ItemsControl.ItemsSourceProperty, myBinding);
}
Here is my rows object and class:
List<Row> rows;
public class Row
{
public string FilterColumn;
public string FilterRule;
public string FilterString;
}
But when I click this button, I don't see it getting added to the list:
private void AddButtonClick(object sender, RoutedEventArgs e)
{
Console.WriteLine("Adding row.");
rows.Add(new Row { FilterColumn = "1", FilterRule = "2", FilterString = "3" });
Console.WriteLine("Row added.");
}
This is because List<int> doesn't implement INotifyCollectionChanged, so the control doesn't know that the list has actually been updated.
Try to make rows an ObservableColelction<Row>.
Edit: as the OP mentioned, the other problem (empty rows) was due to using fields, not properties, on Row.
I am attempting to pull information from my listview but cannot seem to select a specific dataset. When pulling information from this I always get the entire contents back but can never read just one set.
I will be pulling the row data as:
chartViewList2.SelectedItem
I added information to the list view via
private void getServices(string ComputerName)
{
chartListView2.Items.Clear();
ServiceController[] services = ServiceController.GetServices(ComputerName);
foreach (ServiceController service in services)
{
chartListView2.Items.Add(new { Service = service.ServiceName, Status = service.Status, Desc = service.DisplayName });
}
}
List View XML:
ListView x:Name="chartListView2" Margin="12,59,46,6"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler2">
<ListView.View>
<GridView>
<GridViewColumn Header="Service" DisplayMemberBinding="{Binding Service}" Width="100"/>
<GridViewColumn Header="Status" DisplayMemberBinding="{Binding Status}" Width="60"/>
<GridViewColumn Header="Desc" DisplayMemberBinding="{Binding Desc}" Width="190"/>
</GridView>
</ListView.View>
</ListView>
All I want to get from this is the Service name field back.
Any help will be appreciated!
Reflection may help here.
var item = chartViewList2.SelectedItem;
var type = item.GetType();
var propertyInfo = type.GetProperty("Service");
var value = propertyInfo.GetValue(item, null);
Then you will have a value of Service field in 'value' variable.
Since .NET 4 and dynamic keyword even shorter way exists:
dynamic item = chartViewList2.SelectedItem;
dynamic propertyValue = item.Service;
If you are binding your ListView to a List<TypedObject> then you can do this:
var item = chartViewList2.SelectedItem as TypedObject
You can set the ListView SelectedvaluePath to Service and bind to your model or access using the ListView SelectedValue.
Example:
<ListView x:Name="chartListView2" SelectedValuePath="Service" SelectedValue="{Binding SelectedServiceName}" >
How do I recreate the following XAML databinding in code? I have most of it except for the DataTemplate definition.
Here is an example of the DataBinding in XAML
<GridViewColumn Width="140" Header="Name">
<GridViewColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=Label}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
Here is the code I have so far:
return new GridViewColumn()
{
Header = header,
Width = width,
DisplayMemberBinding = new System.Windows.Data.Binding(bindingProperty)
};
The problem is, how did I set the CellTemplate for the DataTemplate through code?
For anyone interested, here is the solution:
private GridViewColumn GetGridViewColumn(string header, double width, string bindingProperty, Type type)
{
GridViewColumn column = new GridViewColumn();
column.Header = header;
FrameworkElementFactory controlFactory = new FrameworkElementFactory(type);
var itemsBinding = new System.Windows.Data.Binding(bindingProperty);
controlFactory.SetBinding(TextBox.TextProperty, itemsBinding);
DataTemplate template = new DataTemplate();
template.VisualTree = controlFactory;
column.CellTemplate = template;
return column;
}