I need a solution for this.
I need to create a view model for grid view. This viewmodel should be a strong typed one. ex.
List<Person> lstPersons=new List<Person>();
something like this. also, with this I should be able to have custom column header names. I can go with data annotation with enabling AutoGenerateColumns="True"
like,
class Person
{
[DisplayName("Person Name")]
public string name { get; set; }
}
something like this. But I have 2 issues with this.
I donno how to change this display name at run time.
Im using telerik RADGridView. with that when I'm using AutoGenerateColumns="True" and ShowColumnFooters="True", the whole UI get stucked. I think this s an error with telerik controls. So I have to define all columns in XAML and add binding path for each as well.
Anyway, This is possible with DataTable I think. but I feel data tables are very oldie struct and heavy object.
How to create a Viewmodel to achieve this? Any suggestions ?
Feel free to ask any question. im not sure above description is clear to everyone.
You can continue to use the DisplayName attribute on your model, but as you pointed out, cannot change it at run-time. To do so, implement a dictionary in your ViewModel that populates
public PeopleGridViewModel
{
public ObservableCollection<Person> People;
public Dictionary<string, string> PersonColumnHeaders;
public PeopleGridViewModel()
{
// 1. write C# here to snag the property names from the typeof(Person)
// 2. get the DisplayName attribute value for that property too.
// 3. add the propertyName.ToString() and the DisplayName string to the dictionary as a key/value pair.
// the result is you have a collection of column headers that start with the defaults from the propertys on the object... but they can be manipulated at run-time, and you don't havem them 100% hard typed like in adcool's example.
}
}
I think the show column footers deal is a Telerik issue as you suggested.
Try this discussion about data binding the column header.
I assume that the columns you want ot display is Fixed.... so your ViewModel Will be like
class MyViewModel
{
//Implement Properties nad proper binding in Xaml and INotifyPropertyChanged for every property that you need on View Level
ObservableCollection<Persons> persons;
string columnheader1;
string columnheader2;
string columnheader3;
}
XAML
<telerik:RadGridView.Columns>
<telerik:GridViewDataColumn DataMemberBinding="{Binding UserName}" Width="200">
<telerik:GridViewDataColumn.Header>
<TextBlock Text="{Binding Columnheader1}"></TextBlock>
</telerik:GridViewDataColumn.Header>
</telerik:GridViewDataColumn>
<telerik:GridViewDataColumn Header="{Binding Columnheader2}" DataMemberBinding="{Binding IsOnline}" MinWidth="200" Width="*"/>
<telerik:GridViewDataColumn Header="{Binding Columnheader3}" DataMemberBinding="{Binding LastActivityDate}" MinWidth="200"/>
</telerik:RadGridView.Columns>
This might do the trick..... :)
Related
I am working on a project where the user should be able to export the values of different custom objects.
I am trying to find a way to load a number of check boxes dynamically (i am thinking user controls) based on a list of property names (string). The user should then be able to check or uncheck the check boxes based on the values that should be exported.
The problem I have is that I cannot give the user controls check boxes custom names which would link to the values that should be exported.
ListBox or ItemsControl (if you need more flexibility) are definitely the way to go. However, it's not going to be enough to just generate the CheckBoxes as you're also going to need a way to track whether they're selected, so you want to make some kind of Choice class and bind the properties of the CheckBox to those of your Choice class. Something like this:
<ListBox ItemsSource="{Binding Choices}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Content="{Binding Name}"
IsChecked="{Binding IsChosen}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And the code-behind:
public class Choice
{
public string Name { get; set; }
public bool IsChosen { get; set; }
}
Where your Choices property is a List or IEnumerable of Choices.
I currently have an application where I'm parsing a YAML dictionary. I have a model named Line that looks like this -
public class Line
{
private ObservableDictionary<string, string> language = new ObservableDictionary<string, string>();
public Line()
{
Language = new Dictionary<string, string>();
}
// used with the YAML parser
[YamlMember(Alias = "language")]
public Dictionary<string, string> Language { get; set; }
}
You've probably noticed that I'm using an ObservableDictionary, which is not a standard type. I took the code from this other StackOverflow answer. As I understand it, it's just setting up the necessary INotifyPropertyChanged interface.
Anyway, for my Line, I have a ListView populated with a dictionary of translations represented as the language abbreviation and a textbox. To better exemplify what I'm talking about, here is a graphic.
In my App.xaml, I have a DataTemplate for my ListView defined - together, they look like this:
<ListView
ItemTemplate="{StaticResource LinesTemplateItem}"
ItemsSource="{Binding Value.Language}"
SelectionMode="None">
</ListView>
...
<DataTemplate x:Key="LinesTemplateItem">
<StackPanel Background="Transparent">
<TextBlock Text="{Binding Key}" />
<TextBox Text="{Binding Value, Mode=TwoWay}" />
</StackPanel>
</DataTemplate>
Everything seems like it should work fine. My data shows properly. However, when I change a value, it does not update the underlying source with the error:
Error: Cannot save value from target back to source.
BindingExpression: Path='Value' DataItem='Windows.Foundation.Collections.IKeyValuePair`2<String,String>';
target element is 'Windows.UI.Xaml.Controls.TextBox' (Name='null');
target property is 'Text' (type 'String').
From the error, I would guess that for some reason the databinding is targeting the entire UI control instead of the text inside of it. I've been searching for a while, but I can't seem to figure out how to fix this error. Any help is appreciated. Thanks.
The problem is that the property IKeyValuePair.Value is read-only so you cannot modify it. My proposition is to change you data model a little bit i.e. firstly create an additional class to store translations.
public class Translation
{
public string Expression { get; set; }
}
Now you should also change a definition of your dictionary e.g.:
public Dictionary<string, Translation> Language { get; set; }
Binding should be also updated accordingly:
<TextBox Text="{Binding Value.Expression, Mode=TwoWay}" />
Thanks to that if you change a value, the data binding will update Expression property which is not read-only.
I didn't test this code but I did similar things in the past so something like that should work.
Since you're binding to Dictionary<string,string>, each item is bound to KeyValuePair<string,string>, which is of value type - it's fields cannot be changed (while unboxed). You should bind to the pair itself, rather than its parts and use value converter to produce a pair with changed value.
Let us say we have a data object which contains two values CompanyID and Price. Also I have more than one control which depending on CompanyID should update Price.
There are four grids with same layout each layout contains a <TextBlock/> control in it. All controls share same variable (Price). If I put <TextBlock Text="{Binding Price}"/> in each of four layouts same value will be updated on every single control. It should update only one <TextBlock/> depending on CompanyID given. Prices will be updated at the runtime.
In modelView constructor:
PriceObj = new Model(CompanyID, Price);
Object will be stored in a property (PriceObj) which is owned by modelView.
What would be the best practice to distinguish which control should update Price value regarding CompanyID value?
Would it be better to create a different Price for each company, let us say Price0, Price1 and then accessing those values directly via DataBinding in XAML?
Can distinguish be made within INotifyPropertyChanged interface implementation?
Note: I do not want the easiest way, I want most MVVM pattern suited way. Code example would be much appreciated.
If you have 100 companies, and each company has its own price, it's very inefficient to produce Price0...Price99 properties. This is not about MVVM, this is about common sense.
Obviously, the way to go is a collection of PriceObj at View Model level, and ItemsControl at View level. Something like this:
public PriceObj
{
public int CompanyID { get; set; }
public decimal Price { get; set; }
}
public class PriceEditorViewModel
{
public ObservableCollection<PriceObj> Prices { ... }
/* ... */
}
XAML:
<ListBox ItemsSource="{Binding Prices}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding CompanyID}"/>
<TextBox Text="{Binding Price}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
ItemsControl (ListBox in sample) generates a separate set of controls per item in ItemsSource. In the markup above controls are defined using DataTemplate (more about data templating here).
I don't understand your question fully but I guess you have list of companies and their price and you want to show the price when someone selects a company?
If it's the case, I'd create 2 grids, one for the companies, and other for the prices.
I'd also create lists of companies and prices in the view model and whenever someone selects a company, I'd filter price list in view model.
May be I dint understand your qq.
I have a code in wich i need to be able to access to a different amount of prebuilt grids in XAMl and make them visible or collapsed
All grid are named like grid1,grid2,grid3 etc. I have the ability in code to obtain the string name via a random number and get the name od the grid i'd like to show.
I searched online and people suggest to use the reflect method, but i'm having a hard time trying to figure out the syntax that i have to use.
Best regards
The most straight forward way of doing this is to just declare a Name value for each Grid...:
<Grid Name="Grid1">
...
</Grid>
... and then you can access them by that name from the code behind:
Grid1.Visibility = Visibility.Hidden;
However, this is WPF and that is generally not recommended. A preferred method would be to add some bool properties to your code behind or view model...:
public bool IsGrid1Visible { get; set; } // Implement INotifyPropertyChanged interface
... and then to bind these directly to the Grid1.Visibility property using a BooleanToVisibilityConverter:
<Grid Grid1.Visibility="{Binding IsGrid1Visible, Converter={StaticResource
BooleanToVisibilityConverter}}">
...
</Grid>
Then you can change the Grid.Visibility value by simply setting the IsGrid1Visible property to true or false.
I'm new to WPF/C#/NET but I have been learning by way of coding some small exercises.
Anyway, I'm stuck. I have seached on here and google and can't find the answer or maybe more correctly can't find an answer I can make sense of.
My problem is this... using the Entity Framework I have two tables. One for Employee details and one for Company details. Employees work for 0 or 1 Company's.
I would like to, via WPF/XAML, define a datagrid to navigate Employees. But within each employee row I would like to show the name of the Company they work for (if there is a relationship) or "Unemployed" in the cases where there is no related Company record.
I have not given details of the tables as it really doesnt matter - the problem is displaying concatentated information from parent/child relationships in a single datagrid.
I dont know what the best approach to this kind of problem is, I'm assuming WPF/DataGrid, so I would really appreciate help on how to go about doing it, the binding (assuming WPF) or even an example of the WPF/XAML
Thanks in advance.
There are many ways to accomplish this - one way you might try is to create a View Model that encapsulates the data you want to display - e.g.
public class EmployeeViewModel
{
private readonly Employee _employee;
public EmployeeViewModel(Employee employee)
{
_employee = employee;
}
public string Name { get { return _employee.Name; } }
public string CompanyName { get { return _employee.Company == null ? "Unemployed" : _employee.Company.CompanyName; } }
}
Then, given an IEnumerable<Employee> you can project your employee data into this view model and set it as the ItemsSource of your DataGrid - e.g.
IEnumerable<Employee> employees = GetEmployeesFromDatabase();
DataGrid1.ItemsSource = employees.Select(x => new EmployeeViewModel(x));
You would normally set the ItemsSource via a xaml binding here rather than setting it directly in code but that would involve the use of a parent ViewModel set as the DataContext of the View and I'm trying to keep things simple.
Another way to accomplish this with a DataGrid would be to forgo the use of a View Model, bind directly to an IEnumerable<Employee> collection and set the column bindings explicitly - e.g.
<DataGrid ItemsSource="{Binding Employees}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Employee Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Company Name" Binding="{Binding Company.Name}" />
</DataGrid.Columns>
</DataGrid>
Note that with the second example, you won't get "Unemployed" appearing in the Company Name column where there is no associated company for an employee.
EDIT: To clarify the point about setting the items source for your Grid from a property on a 'main' view model bound to the View, you might create a ViewModel class that represents the whole of the current view. e.g.
public class MainViewModel
{
private readonly IEnumerable<Employee> _employees;
public MainViewModel(IEnumerable<Employee> employees)
{
_employees = employees;
}
public IEnumerable<Employee> Employees
{
get { return _employees; }
}
}
You'd set this as the DataContext for the Window / UserControl.
e.g. in simple cases you could do this in the constructor for your Window (although calls to the database should really be asynchronous for WPF apps where possible).
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel(GetAllEmployees());
}
Then you can set up the binding on your Grid like this:
<DataGrid ItemsSource="{Binding Employees}" ...
The data context for the main window is then used for all the child controls contained therein except where you explicitly set the DataContext on a child control. This technique becomes useful where you have more complex ViewModels with many properties and commands. If you are interested in finding out more you should take a look at the MVVM pattern and either or both of the Prism / Caliburn frameworks.