How to add row in MVVM pattern? - xaml

Say I use xaml to create a telerik RadGridView.
<telerik:RadGridView x:Name="myRadGridView"
Width="1000"
IsReadOnly="True"
ValidatesOnDataErrors="None"
AutoGenerateColumns="False"
IsFilteringAllowed="False"
ShowGroupPanel="False"
ShowColumnFooters="False"
CanUserResizeColumns="False"
CanUserFreezeColumns="False"
SelectionMode="Single"
CanUserReorderColumns="False"
CanUserSortColumns="False"
CanUserInsertRows="False"
CanUserDeleteRows="False"
CanUserSelect="True"
RowIndicatorVisibility="Visible"
Height="250"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ItemsSource="{Binding Information}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
SelectionChanged="myRadGridView_SelectionChanged"
>
<telerik:RadGridView.Columns>
<telerik:GridViewColumn />
<telerik:GridViewColumn />
.....
</telerik:RadGridView.Columns>
There are many columns.
I get the data from my ViewModel. Now I want to add a new row to get the total value of the above rows.
My question is that how to add the row in my ViewModel?

Try this:
With this you can do it for specific columns via XAML (no need other code)
<telerik:GridViewDataColumn Header="Quantity"
DataMemberBinding="{Binding ProdQuantity}"
UniqueName="Quantity">
<telerik:GridViewDataColumn.AggregateFunctions>
<telerik:SumFunction Caption="Sum: " />
</telerik:GridViewDataColumn.AggregateFunctions>
</telerik:GridViewDataColumn>
OR For all numeric columns
<telerik:RadGridView x:Name="myRadGridView"
Width="1000"
IsReadOnly="True"
...
ShowColumnFooters="True"
AutoGeneratingColumn="GridView_AutoGeneratingColumn"
ItemsSource="{Binding Information}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
SelectionChanged="myRadGridView_SelectionChanged"
>
In code:
private void GridView_AutoGeneratingColumn(object sender, GridViewAutoGeneratingColumnEventArgs e)
{
if(!e.Column is GridViewDataColumn)
return;
GridViewDataColumn col = (e.Column as GridViewDataColumn);
if (col.DataType != null)
{
if (col.DataType == typeof(Int32) || col.DataType == typeof(long) || col.DataType == typeof(Double))
e.Column.AggregateFunctions.Add(new SumFunction());
}
}
note that columns must be GridViewDataColumn

Related

Slow expanding and collapsing TreeView nodes

When a node in TreeView contains many elements, like above 2000, its expanding and collapsing is very slow. For ListView I was using incremental loading:
<ListView
Width="500"
MaxHeight="400"
IsItemClickEnabled = "False"
SelectionMode ="None"
IncrementalLoadingThreshold="5"
IncrementalLoadingTrigger="Edge"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollMode="Enabled"/>
However I do not see such option for TreeView. How this can be optimized?
Slow expanding and collapsing TreeView nodes
Both TreeView and TreeViewItem do not contain IncrementalLoading behavior, so you can't make increment loading for treeview. But you could porcess data soure with linq select-take method to implement Incremental loading function.
placing a button in the last TreeViewItem that used to load more items.
For example
<DataTemplate x:Key="FileTemplate" x:DataType="local:ExplorerItem">
<TreeViewItem AutomationProperties.Name="{x:Bind Name}" IsSelected="{x:Bind IsSelected,Mode=TwoWay}">
<StackPanel Orientation="Horizontal">
<Image Width="20" Source="../Assets/file.png" />
<TextBlock Margin="0,0,10,0" />
<TextBlock Text="{x:Bind Name}" />
<Button Background="White" Margin="15,0,0,0" x:Name="LoadMore" Visibility="{Binding IsLastItem}"
Command="{Binding LoadMoreCommand}" CommandParameter="{Binding}">
<SymbolIcon Symbol="More"/>
</Button>
</StackPanel>
</TreeViewItem>
</DataTemplate>
Code Behind
WeakReferenceMessenger.Default.Register<object>(this, (s, e) =>
{
var temp = subitems.Skip(subitems.IndexOf(e as ExplorerItem)+1).Take(20);
(e as ExplorerItem).IsLastItem = false;
foreach (var item in temp)
{
folder1.Children.Add(item);
}
folder1.Children.Last().IsLastItem = true;
});
For complete code, please refer to this link.

Binding an ExpanderView do a viewModel?

I made some ExpanderViews and hardcoded everything. That worked and looked nice so I wanted to clean up and only write one ExpanderView in xaml and load everything else with a binding.
As far as I understood I need a ListBox around the whole thing to make it more dynamic?
This is my code so far:
<ListBox ItemsSource="{Binding ContactDe}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<toolkit:ExpanderView Header="{Binding}"
ItemsSource="{Binding LocationName}"
IsNonExpandable="False">
<toolkit:ExpanderView.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding LocationName}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" LineHeight="{StaticResource LongListSelectorGroupHeaderFontSize}" />
</DataTemplate>
</toolkit:ExpanderView.HeaderTemplate>
<toolkit:ExpanderView.ExpanderTemplate>
<DataTemplate>
<TextBlock Text="test" />
</DataTemplate>
</toolkit:ExpanderView.ExpanderTemplate>
<toolkit:ExpanderView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Information}" />
</DataTemplate>
</toolkit:ExpanderView.ItemTemplate>
</toolkit:ExpanderView>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The ContactViewModel-Class:
public class ContactDeViewModel : INotifyPropertyChanged
{
private string _locationName;
public string LocationName
{
get
{
return _locationName;
}
set
{
if (value != _locationName)
{
_locationName = value;
NotifyPropertyChanged("LocationName");
}
}
}
private List<string> _information;
public List<string> Information
{
get
{
return _information;
}
set
{
if (value != _information)
{
_information = value;
NotifyPropertyChanged("Information");
}
}
}
}
And this is where I fill the ContactViewModel:
this.ContactDe.Add(new ContactDeViewModel()
{
LocationName = "Stuttgart",
Information = new List<string>
{
"some text"
}
}
);
this.ContactDe.Add(new ContactDeViewModel()
{
LocationName = "Böblingen",
Information = new List<string>
{
"more text"
}
}
);
I made a SampleViewModel-File where I have:
<vm:MainViewModel.ContactDe>
<vm:ContactDeViewModel LocationName="Location 1" />
<vm:ContactDeViewModel LocationName="Location 2" />
</vm:MainViewModel.ContactDe>
In the preview-window it shows me 2 ExpanderViews with Location 1 and 2. But the same code doesn't work with the emulator or a real device. I don't really understand which Binding-Acces does what. It would already help me a lot if I could see a full example. I googled many tutorials but most only show 1 side, like a xaml without seing how the data is stored.
edit:
Now I edited the viewModel, so it's not a List<string> but a List<Info> with Info only containing string Text. So now I can say ItemsSource="{Binding Text}" which should be only 1 string at a time, right?
As stated in comment to #dellywheel's answer, that you set DataContext this way :
d:DataContext="{d:DesignData SampleData/MainViewModelSampleData.xaml}"
that set DataContext for use in design-time only, hence it doesn't work in run-time. To set DataContext with similar approach for use in run-time, you can try this way :
<ListBox ItemsSource="{Binding ContactDe}">
<ListBox.DataContext>
<vm:MainViewModel/>
</ListBox.DataContext>
........
........
</ListBox>
or this way to set DataContext in page level :
<phone:PhoneApplicationPage>
<phone:PhoneApplicationPage.DataContext>
<vm:MainViewModel/>
</phone:PhoneApplicationPage.DataContext>
........
........
</phone:PhoneApplicationPage>
Another suggestion, prefer ObservableCollection rather than List for use along with data binding. ObservableCollection automatically notify view to refresh whenever item added to or removed from collection.
You need to change your bindings slightly
<toolkit:ExpanderView Header="{Binding LocationName}"
ItemsSource="{Binding Information}"
IsNonExpandable="False">
<toolkit:ExpanderView.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontFamily="{StaticResource honeFontFamilySemiBold}" LineHeight="{StaticResource LongListSelectorGroupHeaderFontSize}" />
</DataTemplate>
</toolkit:ExpanderView.HeaderTemplate>
<toolkit:ExpanderView.ExpanderTemplate>
<DataTemplate>
<TextBlock Text="test" />
</DataTemplate>
</toolkit:ExpanderView.ExpanderTemplate>
<toolkit:ExpanderView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" />
</DataTemplate>
</toolkit:ExpanderView.ItemTemplate>
</toolkit:ExpanderView>
Hope that helps

DataBind to Combobox In SilverLight 4 .0

I am trying to databind to the combobox. Data is coming from a database table which name is tbltest and table has 2 fileds id and name.
When I am trying to bind name to combox it display me tbltest:name in View. I am using domain services and MVVM to bind data.
Below is my code of ViewModel:
public ViewModel()
{
var query = context.GetTblTestsQuery();
var load = context.Load(query);
load.Completed += (s, ea) =>
{
ObsCompanyCollection = new ObservableCollection<tblTest>(context.tblTests);
};
}
private ObservableCollection<tblTest> _ObsCompanyCollection = new ObservableCollection<tblTest>();
public ObservableCollection<tblTest> ObsCompanyCollection
{
get
{
return _ObsCompanyCollection;
}
set
{
if (_ObsCompanyCollection != value)
{
_ObsCompanyCollection = value;
NotifyPropertyChanged("ObsCompanyCollection");
}
}
}
and Below is code of my XAml file:
<UserControl.Resources>
<my:ViewModel x:Key="ViewModel"/>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White" DataContext="{StaticResource ViewModel}">
<ComboBox Height="23" HorizontalAlignment="Left" Margin="47,128,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" DisplayMemberPath="{Binding name,Mode=TwoWay}" ItemsSource="{Binding ObsCompanyCollection,Mode=TwoWay}" SelectedItem="{Binding tbldata.SelectCompanyId,Mode=TwoWay}" />
I dont know what is wrong with this code. I want only name to display in my combobox.
Thanks
try this
<ComboBox Height="23" HorizontalAlignment="Left" Margin="47,128,0,0" Name="comboBox1" VerticalAlignment="Top" Width="120" DisplayMemberPath="name" ItemsSource="{Binding ObsCompanyCollection,Mode=OneWay}"

Silverlight DataGridRow Background color change based on a column value and bind from the datagrid itemsource

I am trying to color the row based on a column value and may be other calculations in the value converter, but as long as I set the background value to any binding or anything but the hardcoded color Value="Red" in the setter, it throws a XAML parsing error. I am implementing like this:
<sdk:DataGrid ItemsSource="{Binding
EmailJobs}"
AutoGenerateColumns="False"
Height="Auto"
HorizontalAlignment="Center"
Name="dgEmailJObs"
VerticalAlignment="Top"
Width="Auto" Grid.Row="2">
<sdk:DataGrid.RowStyle>
<Style TargetType="sdk:DataGridRow">
<Style.Setters>
<Setter Property="Background"
Value="{Binding Path=Status,
Converter={StaticResource
valueConverter}}"/>
</Style.Setters>
</Style>
</sdk:DataGrid.RowStyle>
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Customer"
Width="Auto" Binding="{Binding
Customer}" />
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Program"
Width="Auto" Binding="{Binding
Program}" />
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True"
Header="Application" Width="Auto"
Binding="{Binding Application}"/>
<sdk:DataGridTextColumn
CanUserReorder="True"
CanUserResize="False"
CanUserSort="True" Header="Status"
Width="Auto" Binding="{Binding
Status}"></sdk:DataGridTextColumn>
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Last
Created By" Width="Auto"
Binding="{Binding LastChangedBy}"/>
<sdk:DataGridTextColumn
CanUserReorder="False"
CanUserResize="False"
CanUserSort="True" Header="Last
Created On" Width="Auto"
Binding="{Binding
LastChangedOn,StringFormat='MM/DD/YYYY
hh:mm tt'}" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
I am using MVVM and dont wanna use the triggering event. All I want is to simply supply the fourth column value to the converter, but it blows up, should be pretty simple jsut lack of XAML binding knowledge :( any help
I think I see... Silverlight 4 doesn't allow (anymore) bindings into Setters.
However there are 2 simple solutions to solve your issue :
You can remove the <sdk:DataGrid.RowStyle> and its content and replace it by RowStyle="{Binding Path=Status, Converter={StaticResource valueConverter}}" as a property of your datagrid (example below)
<sdk:DataGrid Grid.Column="1" ItemsSource="{Binding EmailJobs}" RowStyle="{Binding Path=Status, Converter={StaticResource valueConverter}}" AutoGenerateColumns="False" HorizontalAlignment="Center" Name="dgEmailJObs" Width="Auto" Margin="0,0,0,87" LoadingRow="dgEmailJObs_LoadingRow">
Or, you can manage it in the code behind after triggering the event LoadingRow:
void dgEmailJObs_LoadingRow(object sender, DataGridRowEventArgs e)
{
myClass c = e.Row.DataContext as myClass;
if (c != null)
{
if (c.Status == "Stopped")
{
e.Row.Background = new SolidColorBrush(Colors.Red);
}
else
{
e.Row.Background = new SolidColorBrush(Colors.Green);
}
}
}
Hope that helps ;)
private void grdPendingRequest_LoadingRow(object sender, DataGridRowEventArgs e)
{
string changedColPath = string.Empty;
dynamic itemData = (dynamic)e.Row.DataContext;
if (itemData != null)
changedColPath = itemData.Changed_Field;
if (changedColPath != string.Empty)
{
string colPath;
System.Windows.Data.Binding binding;
string[] ChangedColNameList = null;
foreach (DataGridColumn col in grdPendingRequest.Columns)
{
if (col is DataGridBoundColumn)
{
binding = (col as DataGridBoundColumn).Binding;
colPath = binding.Path.Path;
ChangedColNameList = changedColPath.Split(';');
if (ChangedColNameList.Contains(colPath))
{
FrameworkElement felt = col.GetCellContent(e.Row);
FrameworkElement felt_result = GetParent(felt, typeof(DataGridCell));
if (felt_result != null)
{
DataGridCell cell = (DataGridCell)felt_result;
//cell.Background = new SolidColorBrush(Color.FromArgb(255, 196, 219, 249));
cell.Background = new SolidColorBrush(Colors.Red);
}
}
}
}
}
}
my value converter:
public class EmailJobStatusConverter:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return (value.ToString()=="Stopped") ?
new SolidColorBrush(Colors.Red) :
new SolidColorBrush(Colors.Green);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
SolidColorBrush resultColor = value as SolidColorBrush;
if (resultColor.Color == Colors.Green)
{
return "Green";
}
else
return "Red";
}
}

Dynamically Changing Combobox to TextBox in datagrid inside Cell Editing Template in silverlight 4

I'm making an application in Silverlight 4. I am facing a problem, I need to change a particular combobox into textbox programmatically when a particular column value(using combobox) of the same row is changed.I need to change this on event cellEditEnded.
Please note that I need to change celleditingtemplate combobox to textbox not celltemplate textblock.
This my Column where I need to take the decision of its combo box selected value.
<sdk:DataGridTemplateColumn Header="Instruction Type"
CanUserResize="False" CanUserReorder="False">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding operationType}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="instruction" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
This Column comboBox need to change to textbox here:
<sdk:DataGridTemplateColumn Header="Destination">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding destination}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="destination"/>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
C# code:
public class Instruction
{
public string operationType { get; set; }
public string destination { get; set; }
}
private void myGrid_CellEditEnded(object sender, DataGridCellEditEndedEventArgs e)
{
DataGrid obj = (DataGrid)sender;
Instruction obj1 = (Instruction)obj.SelectedItem;
if (e.Column.Header.ToString() == "Instruction Type")
{
if (obj1.operationType == "ADD" || obj1.operationType == "SUB")
{
// Here I need Require Code ????/
}
}
}
I m waitng for anyone Genius who help me out ..
Here is a working example http://anzensoft.smtp.ru/FlashKiller2/DataGridTrickTestPage.html
And here is the source code http://cid-a1de71e9f2ae2f82.office.live.com/self.aspx/.Public/DataGridTrick.zip
xaml code
<Grid x:Name="LayoutRoot" Background="White">
<sdk:DataGrid x:Name="dataGrid1" AutoGenerateColumns="False"
PreparingCellForEdit="dataGrid1_PreparingCellForEdit">
<sdk:DataGrid.Columns>
<sdk:DataGridTemplateColumn Header="Instruction Type">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding operationType}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox x:Name="instruction"
SelectedValue="{Binding operationType, Mode=TwoWay}">
<s:String>ADD</s:String>
<s:String>MUL</s:String>
</ComboBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn Header="Destination">
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Margin="2" Text="{Binding destination}" />
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
<sdk:DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<Grid>
<ComboBox x:Name="destinationComboBox"
SelectedValue="{Binding destination, Mode=TwoWay}">
<s:String>sdas</s:String>
<s:String>dasdasdasd</s:String>
</ComboBox>
<TextBox x:Name="destinationTextBox"
Text="{Binding destination, Mode=TwoWay}"
Visibility="Collapsed"/>
</Grid>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellEditingTemplate>
</sdk:DataGridTemplateColumn>
</sdk:DataGrid.Columns>
</sdk:DataGrid>
</Grid>
C# code
namespace DataGridTrick
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
dataGrid1.ItemsSource = new List<Instruction>()
{
new Instruction(){operationType = "ADD", destination ="sdas"},
new Instruction(){operationType = "ADD", destination = "dasdasdasd"}
};
}
private void dataGrid1_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
{
if ((string)e.Column.Header == "Destination")
{
var tb = e.EditingElement.FindName("destinationTextBox") as TextBox;
var cb = e.EditingElement.FindName("destinationComboBox") as ComboBox;
var instruction = e.EditingElement.DataContext as Instruction;
if (tb == null || cb == null || instruction == null)
{
throw new
Exception("Something wrong here.. this dosen't have to happen!!");
}
else
{
if (instruction.operationType == "MUL")
{
tb.DataContext = e.EditingElement.DataContext;
cb.DataContext = null;
tb.Visibility = System.Windows.Visibility.Visible;
cb.Visibility = System.Windows.Visibility.Collapsed;
}
else
{
tb.DataContext = null;
cb.DataContext = e.EditingElement.DataContext;
tb.Visibility = System.Windows.Visibility.Collapsed;
cb.Visibility = System.Windows.Visibility.Visible;
}
}
}
}
}
public class Instruction
{
public string operationType { get; set; }
public string destination { get; set; }
}
}