In my 1 screen I have a RadGridView & RadMenu. From 1 RadMenuItem I have to allow user to save this Grid Data to Excel. So I have a command which Fires & take RadGridView as a CommandParameter. Everything goes fine till here. But in my code when I try to Open SaveFileDialog it gives me issue for security & Code breaks.
I tried my code like this example
http://demos.telerik.com/silverlight/#GridView/ExportingExcelML
my ViewModel is same like in example code
My xaml Code is like this
.....
<telerik:RadMenuItem Header="Excel" Command="{Binding ExportExcelRouteDataCommand}" CommandParameter="{Binding ElementName=RouteGridView}">
...
</telerik:RadGridView>
<telerik:RadDataPager HorizontalAlignment="Stretch"
Grid.Row="2"
Grid.Column="0"
VerticalAlignment="Top"
x:Name="RoutesDataPager"
PageSize="{Binding PageSize,Mode=TwoWay}" FontSize="12"
BorderThickness="1,0,1,1"
Source="{Binding AllRoutesItemSource}"
DisplayMode="All"/>
</Grid>
I'm getting this Error :
System.Security.SecurityException was unhandled by user code
Message=Dialogs must be user-initiated.
StackTrace:
at System.Windows.Controls.SaveFileDialog.ShowDialogInternal(Window owner)
at System.Windows.Controls.SaveFileDialog.ShowDialog()
at Delasoft.Hpms.Module.Routes.ViewModel.RoutesDashBoardViewModel.Export(Object parameter)
at Delasoft.Hpms.Module.Routes.ViewModel.RoutesDashBoardViewModel.OnExportRouteData(Object param)
at Telerik.Windows.Controls.DelegateCommand.Execute(Object parameter)
at Telerik.Windows.Controls.RadMenuItem.ExecuteCommand()
at Telerik.Windows.Controls.RadMenuItem.OnClickImpl()
at Telerik.Windows.Controls.RadMenuItem.OnClick()
at Telerik.Windows.Controls.RadMenuItem.ClickItem()
at Telerik.Windows.Controls.RadMenuItem.HandleMouseUp()
at Telerik.Windows.Controls.RadMenuItem.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName, UInt32 flags)
InnerException:
My application is in Prism 4, Silverlight 5 & Telerik controls. Any help for using FileOpenDialog in MVVM parttern ?
Related
Imagine a UserControl with a ListBox having a CheckBox in a DataTemplate. The ItemsSource for the ListBox is some global list. The CheckBox has Checked/Unchecked events attached to it.
<ListBox ItemsSource="{Binding Source={x:Static a:MainWindow.Source}}">
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type a:Data}">
<CheckBox Content="{Binding Path=Name}"
Checked="ToggleButton_OnChecked"
Unchecked="ToggleButton_OnUnchecked"
IsChecked="{Binding Path=IsEnabled}"
Padding="10"
VerticalContentAlignment="Center"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I am logging loaded/unloaded/checked/unchecked events in the main window's log.
private void ToggleButton_OnChecked(object sender, RoutedEventArgs e)
{
Log("Checked");
}
private void ToggleButton_OnUnchecked(object sender, RoutedEventArgs e)
{
Log("Unchecked");
}
private void UserControl1_OnLoaded(object sender, RoutedEventArgs e)
{
Log("Loaded");
}
private void UserControl1_OnUnloaded(object sender, RoutedEventArgs e)
{
Log("Unloaded");
}
The main window features a dynamic list of UserControl1 instances (starting with just one). There are add/remove buttons that allow me to add more instances.
<UniformGrid Rows="2">
<DockPanel>
<Button DockPanel.Dock="Top" Click="Add">Add</Button>
<Button DockPanel.Dock="Top" Click="Remove">Remove</Button>
<ListBox x:Name="ListBox">
<local:UserControl1 />
</ListBox>
</DockPanel>
<ListBox ItemsSource="{Binding ElementName=This,Path=Log}" FontFamily="Courier New"/>
</UniformGrid>
The window's codebehind:
private void Add(object sender, RoutedEventArgs e)
{
ListBox.Items.Add(new UserControl1());
}
private void Remove(object sender, RoutedEventArgs e)
{
if (ListBox.Items.Count == 0) return;
ListBox.Items.RemoveAt(0);
}
When I run the app there is just one UserControl1 instance. If I add one more and then immediately remove one of them, then click the one and only checkbox on the screen, I see two "Checked" events logged. If I now uncheck it, there are two "Unchecked" events (even though "Unloaded" event was previously clearly logged. The hex numbers on the left show the output of a GetHashCode() which clearly shows the events were handled by distinct UserControl1 instances.
So even though one of UserControl1 gets unloaded, the events don't seem to get unsubscribed automatically. I have tried upgrading to NET Framework 4.8 to no avail. I see the same behavior. If I add 10 new controls and remove them immediately, I will observe 10 "Checked" or "Unchecked" events.
I have tried searching for a similar problem but could not find it. Is there something I am missing or did I just encounter a bug? Looking for workarounds.
Full source code is available on GitHub. https://github.com/wpfwannabe/datacontext-event-leak
In the MVVM pattern, the view is bind to the view model and doesn't survive it when the garbage collection do it's job.
In the example you provided, the view model is a static object and by definition can't be garbage collected, so the view can't neither be garbage collected.
There is no automatic unbinding since you can reuse an instance of an user control (it can be Loaded and UnLoaded multiple times).
The simplest¹ way to fix this memory leak is to do the unbinding on unload :
Wpf
// First give the ListBox a name
<ListBox x:Name="ListBox" ItemsSource="{Binding Source={x:Static a:MainWindow.Source}}">
Code behind
private void UserControl1_OnUnloaded(object sender, RoutedEventArgs e)
{
Log("Unloaded");
ListBox.ItemsSource = null;
}
1: The proper way is to wrap the static list in a dedicated list view model, make the view model disposable (to unbind the wrapper from the static list on dispose), dispose the view model on remove.
I'm converting a Silverlight 3 project to Silverlight 4. I recently got the project able to run, but I am running into problems instantiating a search window. VS threw the following error at me:
Microsoft JScript runtime error: Unhandled Error in Silverlight Application Set property 'System.Windows.FrameworkElement.Style' threw an exception. [Line: 242 Position: 46] at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at ESM.Visualization.SearchWindow.InitializeComponent()
at ESM.Visualization.SearchWindow..ctor(Map mapWindow, String addressServiceUrl, String projectServiceUrl)
at ESM.Visualization.MainPage.InstantiateSearchWindow()
at ESM.Visualization.MainPage.MapWindow_Progress(Object sender, ProgressEventArgs e)
at ESRI.ArcGIS.Client.Map.layersProgressHandler(Object sender, ProgressEventArgs args)
at ESRI.ArcGIS.Client.LayerCollection.layer_OnProgress(Object sender, ProgressEventArgs args)
at ESRI.ArcGIS.Client.Layer.ProgressHandler.Invoke(Object sender, ProgressEventArgs args)
at ESRI.ArcGIS.Client.Layer.OnProgress(Int32 progress)
at ESRI.ArcGIS.Client.DynamicLayer.bitmap_DownloadProgress(Object sender, DownloadProgressEventArgs e, Image img, EventHandler`1 onProgressEventHandler, Int32 id)
at ESRI.ArcGIS.Client.DynamicLayer.<>c__DisplayClass7.<getSourceComplete>b__4(Object sender, DownloadProgressEventArgs e)
at MS.Internal.CoreInvokeHandler.InvokeEventHandler(Int32 typeIndex, Delegate handlerDelegate, Object sender, Object args)
at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)
I researched the error and tried re-installing Silverlight in accordance to this solution. But the error still occurred. I looked at this SO question, but my App.xaml is hardly 242 lines. Here's my MainPage.xaml at around line 242:
<StackPanel Orientation="Vertical" HorizontalAlignment="Left" Grid.Row="2" VerticalAlignment="Bottom">
<esriToolkit:Navigation x:Name="MapNavigation" Margin="5" Map="{Binding ElementName=MapWindow}" Visibility="Collapsed" />
<!--<esri:ScaleBar x:Name="MainScaleBar" Margin="5" MapUnit="DecimalDegrees" Foreground="Black"
Map="{Binding ElementName=MapWindow}"
DisplayUnit="Miles" Visibility="Visible" />-->
</StackPanel>
And here is the .xaml for the search window I am trying to instantiate (at around line 242):
<grid:AgDataGrid x:Name="grdAddressResults" Grid.Row="1" Grid.Column="0" ColumnsAutoWidth="True"
ShowTotals="False" FocusMode="Row" FocusedRowChanged="grdResults_FocusedRowChanged"
IsMultiSelect="False" Margin="0,10,0,0">
<grid:AgDataGrid.Columns>
<grid:AgDataGridColumn FieldName="Address" />
<grid:AgDataGridColumn FieldName="X" Visible="False" />
<grid:AgDataGridColumn FieldName="Y" Visible="False" />
</grid:AgDataGrid.Columns>
<grid:AgDataGrid.TotalSummary>
<grid:AgDataGridSummaryItem FieldName="Address" SummaryType="Count" Title="Matches Found" />
</grid:AgDataGrid.TotalSummary>
</grid:AgDataGrid>
The exception tells
Set property 'System.Windows.FrameworkElement.Style' threw an exception.
Though this is not in the code you displayed - but I am almost sure you will find something like this somewhere in your code:
<SomeControl Style="MyCoolStyle" ... />
where it should be:
<SomeControl Style="{StaticResource MyCoolStyle}" ... />
In Silverlight 4 I have a DataGrid which is bound to a RIA DomainDataSource, all done in XAML. The AutoGenerateColumns property is set to false and each column is manually defined and bound. Basically this works fine.
Where I now run into problems is having an additional DataGridTextColumn which has no Binding. I want to manually populate the cells in this column in the code behind. When having this column without the Binding, at runtime the following exception pops up:
System.ArgumentNullException: Value cannot be null.
Parameter name: binding
at System.Windows.Data.BindingOperations.SetBinding(DependencyObject target, DependencyProperty dp, BindingBase binding)
at System.Windows.Controls.DataGridTextColumn.GenerateElement(DataGridCell cell, Object dataItem)
at System.Windows.Controls.DataGrid.PopulateCellContent(Boolean isCellEdited, DataGridColumn dataGridColumn, DataGridRow dataGridRow, DataGridCell dataGridCell)
at System.Windows.Controls.DataGrid.AddNewCellPrivate(DataGridRow row, DataGridColumn column)
at System.Windows.Controls.DataGrid.CompleteCellsCollection(DataGridRow dataGridRow)
at System.Windows.Controls.DataGrid.GenerateRow(Int32 rowIndex, Int32 slot, Object dataContext)
at System.Windows.Controls.DataGrid.AddSlots(Int32 totalSlots)
at System.Windows.Controls.DataGrid.RefreshRows(Boolean recycleRows, Boolean clearRows)
at System.Windows.Controls.DataGrid.RefreshRowsAndColumns(Boolean clearRows)
at System.Windows.Controls.DataGrid.InitializeElements(Boolean recycleRows)
at System.Windows.Controls.DataGridDataConnection.NotifyingDataSource_CollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
at System.Windows.Controls.DomainDataSourceView.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
at System.Windows.Controls.DomainDataSourceView.OnCollectionViewCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
at System.Windows.Controls.EntityCollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
at System.Windows.Controls.PagedEntityCollectionView.OnCollectionChanged(NotifyCollectionChangedEventArgs args)
at System.Windows.Controls.PagedEntityCollectionView.RefreshView()
at System.Windows.Controls.PagedEntityCollectionView.SourceCollectionChanged(NotifyCollectionChangedEventArgs args)
at System.Windows.Controls.EntityCollectionView.HandleSourceCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
at System.Windows.Controls.PagedEntityCollection.RaiseCollectionChanged(NotifyCollectionChangedAction action, Entity entity, Int32 index)
at System.Windows.Controls.PagedEntityCollection.CompleteLoad()
at System.Windows.Controls.DomainDataSource.ProcessLoadedEntities(LoadContext loadContext, IEnumerable`1 entities)
at System.Windows.Controls.DomainDataSource.DomainContext_Loaded(LoadedDataEventArgs e, LoadContext loadContext)
How can I avoid this exception and have my DataGrid with most columns bound and one column unbound?
Thanks in advance.
Edit:
My XAML looks as follows:
<sdk:DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding Data, ElementName=MyDomainDataSource, Mode=OneWay}">
<sdk:DataGrid.Columns>
<sdk:DataGridTextColumn Binding="{Binding Name}" Header="Name" />
<sdk:DataGridTextColumn Binding="{Binding CreationDate}" Header="Creation Date" />
<sdk:DataGridTextColumn Header="Unbound Col" />
</sdk:DataGrid.Columns>
</sdk:DataGrid>
Edit #2:
One idea I found on the web was to bind the last column to some unique value (I have an ID in my data model) and use a custom IValueConverter which converts the ID to a dependent value. This would have been exactly what I wanted, but unfortunately I get the dependent value from a WCF service call, which is always asynchronous. As you cannot use async method calls in an IValueConverter this solution is not an option for me.
Have you considered using a DataGridTemplateColumn instead? It does not matter if you set the binding or not for this type of column.
For example, if you just want to set the unbound value once at the time of loading you could do something like this:
<sdk:DataGridTemplateColumn>
<sdk:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="MyText" Loaded="MyText_Loaded"></TextBox>
</DataTemplate>
</sdk:DataGridTemplateColumn.CellTemplate>
</sdk:DataGridTemplateColumn>
...and then set the value in the code behind like this:
private void MyText_Loaded(object sender, RoutedEventArgs e)
{
var textBox = sender as TextBox;
if (textBox != null) textBox.Text = "My one off text";
}
I'm not sure what your exact requirements are.
Is there any way to effectively "alias" commands in WPF ? My situation is this : I've created an application that uses ApplicationCommands.Delete in the context of a graphical editor that has a number of customized canvases. Some of the controls that are on these canvases use TextBoxes, but here's the problem : TextBox doesn't respond to ApplicationCommands.Delete, it responds to EditorCommands.Delete. Is there any way to cleanly get TextBox to respond to ApplicationCommands.Delete without subclassing or manually setting bindings on every TextBox instance ?
To answer your specific question, I know of no way to cause two separate routed commands to be treated as the same command. But because ApplicationCommands.Delete is a routed command, after it is delivered to its target, the TextBox and there is no command binding, it will begin bubbling up. So the simplest solution that meets your requirements is to install a command binding for ApplicationCommands.Delete somewhere inbetween the TextBox all the way up to and possibly including the Window, that implements the behavior you desire.
Here's an example that installs a handler on a parent Grid that sends the "right" command the the focused element which in this case will be a TextBox:
<Grid>
<Grid.CommandBindings>
<CommandBinding Command="ApplicationCommands.Delete" CanExecute="CommandBinding_CanExecute" Executed="CommandBinding_Executed"/>
</Grid.CommandBindings>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_Edit">
<MenuItem Header="_Delete" Command="ApplicationCommands.Delete"/>
</MenuItem>
</Menu>
<StackPanel>
<TextBox Text="Some text"/>
</StackPanel>
</DockPanel>
</Grid>
and here's the code-behind:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
EditingCommands.Delete.Execute(null, Keyboard.FocusedElement);
}
I'm trying to figure out WPF binding to SQLite.
I have an ADO.NET Entity Data Model generated to represent my SQLite database. The database only holds one table "People" with two columns "person_id" and "person_name". Now, I generated EDM classes for that table within my WPF Application.
I'm trying to bind to a list box. I can delete items from source and see it updating the list box. But I can't add items to the source using a text box and see it update the list box.
I declared data entities in Window1 class like this:
private static MyNewSqliteDbEntities2 _myEntities = new MyNewSqliteDbEntities2();
I have a list box that is bound to the ObjectQuery in the Window_Loaded event handler like this:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
peopleListBox.ItemsSource = _myEntities.People;
}
I have another text box which I use to add people by clicking on button. And I can delete Items by selecting an item in the list box and clicking delete button. Changes are committed to the database when a commit button is clicked. Please consider the code below:
private void addButton_Click(object sender, RoutedEventArgs e)
{
if (addPersonTextBox.Text != "")
{
People newPerson = new People();
newPerson.person_name = addPersonTextBox.Text;
//_myEntities.AddToPeople(newPerson);
_myEntities.AddObject("People", newPerson);
addPersonTextBox.Text = "";
}
}
private void deleteButton_Click(object sender, RoutedEventArgs e)
{
_myEntities.DeleteObject(peopleListBox.SelectedItem);
}
private void commitButton_Click(object sender, RoutedEventArgs e)
{
_myEntities.SaveChanges();
}
I tried refreshing the list box control using another button called "Refresh" in the following manner but with no luck (although, when I step through the code I see the source is updated):
private void refreshButton_Click(object sender, RoutedEventArgs e)
{
peopleListBox.ItemsSource = null;
peopleListBox.ItemsSource = _myEntities.People;
}
Here is the XAML code if you are wondering:
<Window x:Class="BindingToSqLite.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="400" Width="400" Loaded="Window_Loaded">
<Window.Resources>
<DataTemplate x:Key="personNameTemplate">
<TextBlock Text="{Binding Path=person_name}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="190*" />
<ColumnDefinition Width="94*" />
<ColumnDefinition Width="94*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="182*" />
<RowDefinition Height="38*" />
<RowDefinition Height="38*" />
<RowDefinition Height="32*" />
</Grid.RowDefinitions>
<ListBox Margin="5" Name="peopleListBox" Grid.ColumnSpan="3" ItemTemplate="{StaticResource personNameTemplate}" />
<TextBox Grid.Row="1" Grid.ColumnSpan="2" Margin="5,10" Name="addPersonTextBox" />
<Button Grid.Column="2" Grid.Row="1" Margin="5" Name="addButton" Click="addButton_Click">Add</Button>
<Button Grid.Row="2" Margin="5" Name="commitButton" Click="commitButton_Click">Commit</Button>
<Button Grid.Column="1" Grid.ColumnSpan="2" Grid.Row="2" Margin="5" Name="deleteButton" Click="deleteButton_Click">Delete</Button>
<Button Grid.Row="3" Margin="5" Name="refreshButton" Click="refreshButton_Click">Refresh</Button>
</Grid>
</Window>
I'm not sure if I'm doing this completely wrong. Any help is appreciated.
The People property needs to be an ObservableCollection<T> for this to work.