Telerik PdfViewer - Binding to a PDF source - c#

I've tried the samples on telerik's website as well, and to no avail. So I have this code:
public ICommand EmailPopUpCmd { get; set; }
private void EmailPopUp(object sender) {
//ToDo: pdf viewer pop up
selectedDataRow = (DataRow)sender;
var window = new Window();
window.Content = new EmailView() { DataContext = this}; //shares the same data context
MemoryStream str = new MemoryStream();//= new MemoryStream(pdfAsByteArray);//new System.Uri(#"pack://application:,,,/Resources/TestPDF.pdf", System.UriKind.RelativeOrAbsolute);
using(FileStream fs = File.OpenRead(#"C:\Source\UI.MailViewer\Resources\TestPDF.pdf")) {
str.SetLength(fs.Length);
fs.Read(str.GetBuffer(),0, (int)fs.Length);
}
AttachmentPath = new PdfDocumentSource(str);
if (window.ShowDialog() == true) {
//from child back to parent
}
}
C:\Source\UI.MailViewer\Resources\TestPDF.pdf
Is where my PDF is located and I bind it to the UI as follow:
telerik:RadPdfViewer x:Name="pdfEmailViewer"
Grid.Row="2"
DocumentSource="{Binding AttachmentPath,Converter={StaticResource DebugConverter}}">
Now using this, I get an object not set to an instance error. Any idea as to why? Using the debug converter, the value of the PDF document created is null, why is that happening?

Okay so to help other users, I found this on the telerik forums: (Telerik Forum Link)
There is one additional thing to do in order to make RadPdfViewer work in a WinForms application: you should ensure that the Application.Current property is initialized before the user control is initialized, for example by adding this code in the constructor of the user control:
public PdfViewerControl() {
if (Application.Current == null)
new Application();
InitializeComponent();
}
This worked for me in WPF as well.

Related

Serialize WPF Image Control but ignore Source property in runtime?

I'm currently working on an editor like WPF application where you can choose to edit a control and then a dialog opens with a copy of the control in it. For the copying of the control I use the XamlReader.Parse(string) and XamlWriter.Save(obj).
Now there are some (custom) controls than contain an Image control who has their Source set to an WriteableBitmap. The Bitmap is not serializable so the serializer is throwing some exceptions, but that's not the main problem because it isn't required to be serialized because it gets changed later anyways.
Is there a way to Serialize a WPF-Control and tell the Serializer to ignore a property of its children or override it with something that is serializeable (like null) in runtime?
I've already tried to manually set the source Property before and after serialization but for some unkown reason I can't change the Source of the deserialized control.
Code for the dialog
public void LaunchEditor()
{
Editor dlg = new Editor ();
dlg.Owner = Application.Current.MainWindow;
dlg.SetTemplateString(XamlWriter.Save(this));
if (dlg.ShowDialog() ?? false)
{
string s = dlg.GetTemplateString();
CustomControlType c = (CustomControlType)XamlReader.Parse(s);
Content = c;
}
}
Code for serialization
public void SetTemplateString(string template)
{
Placeholder = (CustomControlType)XamlReader.Parse(template);
/*Formatting Stuff*/
}
public string GetTemplateString()
{
StringBuilder sb = new StringBuilder();
XmlWriterSettings settings = new XmlWriterSettings()
{
Indent = true
};
XmlWriter writer = XmlWriter.Create(sb,settings);
XamlDesignerSerializationManager mgr = new XamlDesignerSerializationManager(writer);
XamlWriter.Save(Placeholder, mgr);
return sb.ToString();
}
Custom control that contains the Image
public partial class RollingViewControl : ContentConstrol
{
private RollingBitmap _bmp;
public RollingViewControl()
{
_bmp = new RollingBitmap(256, 256);
InitializeComponent();
ImageDisplay.Source = _bmp.Bitmap;
}
}
RollingBitmap is a Class for Manupilating the WriteableBitmap who is a Property of this Class.
The problem is the Source property of the Image Control, when serializing the Control the Source also gets serialized. Because it is precompiled code I cannot set any Attributes and I haven't found any way to apply XmlAttributeOverrides to the XamlWriter.

ReportViewer in MVVM WPF

I'm building an MVVM Light WPF app using Visual Studio 2015. The app needs to display some SQL Server Reporting Services reports locally.
The following two solutions exist:
Using MS ReportViewer in WPF
Walkthrough: Using ReportViewer in a WPF Application
Though the first is MVVM, it's mixing UI with the view model. The second is pure code-behind.
Here's what the first example suggests:
WindowsFormsHost windowsFormsHost = new WindowsFormsHost();
reportViewer = new ReportViewer();
windowsFormsHost.Child = reportViewer;
this.Viewer = windowsFormsHost
Note that ReportViewer is a UI control. The second solution uses a code-behind file:
private void ReportViewer_Load(object sender, EventArgs e)
{
//...
}
Is there a way to embed a local SSRS report into a WPF app and follow good MVVM practices? Thank you.
Update: No need to be fanatical! If some code-behind is needed, I'm okay with it.
We use a view to select the report from a ComboBox and a button to run it. In the viewmodel, we have the reports' ComboBox bound to an ObservableCollection of report names and IDs. We then employ the MVVM Light Toolkit's Messaging class to send/receive "messages." Note that the base viewmodel, MyAppViewModelBase, inherits from Light Toolkit's ViewModelBase, which has the RaisePropertyChanged() defined.
Also note that we could pass the selected report's VM instead of the view's VM; that would be more efficient but will require modifications to this code. Then we'd use a base class for all the report VMs and a pattern-matching switch in the code-behind to select which report to run.
Here's the pertinent code for the viewmodel:
using GalaSoft.MvvmLight.Messaging;
public class ReportsViewModel : MyAppViewModelBase
{
public ReportsViewModel()
{
// Register a listener that receives the enum of the
// report that's ready. The message it receives has
// name "SsrsReportReady" with handler SsrsReportReady.
Messenger.Default.Register<Constants.Report>(this, "SsrsReportReady", SsrsReportReady);
// Other logic...
}
// Bound to a button to run the selected report
public ICommand RunReportRelayCommand =>
new RelayCommand(RunReport);
// Backing field for the selected report.
private ReportViewModel _selectedReportVm;
public ReportViewModel SelectedReportVm
{
get { return _selectedReportVm; }
set
{
if (Equals(value, _selectedReportVm)) return;
_selectedReportVm = value;
// Built-in method from Light Toolkit to
// handle INotifyPropertyChanged
RaisePropertyChanged();
}
}
private void RunReport()
{
// Send a message called "RunSSRSReport" with this VM attached as its data.
Messenger.Default.Send(this, "RunSSRSReport");
}
// Handler for report-ready
private void SsrsReportReady(Constants.Report obj)
{
ShowReport = true;
IsRunReportButtonEnabled = true;
RunReportButtonContent = Constants.BtnGenerateReport;
// View uses Material Design's Expander control.
// We expand/collapse sections of the view.
ExpandReport = true;
ExpandParameters = false;
}
}
In the code-behind of the view:
using GalaSoft.MvvmLight.Messaging;
public partial class ReportsView : UserControl
{
public ReportsView()
{
InitializeComponent();
// Register a listener for the "RunSSRSReport"
// message, called from our viewmodel. Its
// handler is RunSsrsReport and its data type
// is ReportsViewModel.
Messenger.Default.Register<ReportsViewModel>(this, "RunSSRSReport", RunSsrsReport);
DataContext = new ReportsViewModel();
}
// Handler to run the selected report.
private void RunSsrsReport(ReportsViewModel obj)
{
// Basic validation
if (obj.SelectedReportVm == null || obj.SelectedReportVm.Id.Equals(-1))
{
return;
}
// Ugly switch to run the correct report.
// It can be re-written with pattern matching.
switch (obj.SelectedReportVm.Id)
{
case (int)Constants.Report.ReportA:
RunReportA(obj);
break;
case (int)Constants.Report.ReportB:
RunReportB(obj);
break;
// other reports....
}
}
// Run the report using dataset and tableadapter.
// Modify to use your code for running the report.
private void RunReportA(ReportsViewModel reportsViewModel)
{
var dataSet = new ReportADataSet();
dataSet.BeginInit();
// We reference the ReportViewer control in XAML.
ReportViewer.ProcessingMode = ProcessingMode.Local;
ReportViewer.LocalReport.ShowDetailedSubreportMessages = true;
ReportViewer.LocalReport.DataSources.Clear();
var dataSource = new ReportDataSource
{
Name = "ReportA_DS",
Value = dataSet.uspReportA // Uses a stored proc
};
ReportViewer.LocalReport.DataSources.Add(dataSource);
ReportViewer.LocalReport.ReportEmbeddedResource =
"MyApp.Reports.ReportA.rdlc";
dataSet.EndInit();
new reportATableAdapter { ClearBeforeFill = true }
.Fill(dataSet.uspReportA);
// Send message back to viewmodel that the report is ready.
Messenger.Default.Send(Constants.Report.ReportA, "SsrsReportReady");
}
}
The report view has a WindowsFormsHost with name ReportViewer, referenced in above code-behind:
<WindowsFormsHost Width="Auto" Height="500">
<rv:ReportViewer x:Name="ReportViewer" />
</WindowsFormsHost>

Binding a HTML control into a stacklayout using xamarin forms

Being a newbie to Xamrin I am struggling to adding some HTML to a StackLayout via Xamarin Forms. I have tried quite a few things and had a Google around.
Firstly I can't work out which bindable object I am supposed to be using. As I cannot find a straight answer on Google/Xamarin I am going to assume this is not as easy I was hoping.
var nameEntry = new Label ();
nameEntry.SetBinding (Label.TextProperty, "Club.ClubName");
var webView = new WebView ();
webView.SetBinding ( ??? , "Club.Description");
var content = new StackLayout {
Children = {
nameEntry,
???
}
};
I am not sure if this is possible within Xamarin forms itself. Can anyone help?
I should point out my data for the form is being retrieved asynchronously on a remote json endpoint
protected override void OnAppearing ()
{
base.OnAppearing ();
if (ViewModel == null || ViewModel.IsLoading)
return;
ViewModel.LoadItemsCommand.Execute (Club.ClubId);
}
My remote json api contains, Description contatins a HTML snippet which I would like to use.
{
ClubName: "Stourbridge",
Description: "<p>This club meets every TWO weeks on a <b>Friday</b>.</p>"
...
}
Try the following example that will show how to do the bindings.
Note that you have to use a HtmlWebViewSource to achieve this, and bind the WebView.Source to this.
Clicking the button will change the view model and update the WebView appropriately to the newly changed text.
StackLayout objStackLayout = new StackLayout();
MyView objMyView = new MyView();
objMyView.MyHtml = "<html><head></head><body><h1>Title</h1><p>Some body text</p></body></html>";
HtmlWebViewSource objHtmlWebViewSource = new HtmlWebViewSource();
objHtmlWebViewSource.SetBinding(HtmlWebViewSource.HtmlProperty, "MyHtml");
objHtmlWebViewSource.BindingContext = objMyView;
WebView objWebview = new WebView();
objWebview.HorizontalOptions = LayoutOptions.FillAndExpand;
objWebview.VerticalOptions = LayoutOptions.FillAndExpand;
objWebview.Source = objHtmlWebViewSource;
Button objMyButton2 = new Button();
objMyButton2.Text="Change Html";
objMyButton2.Clicked+=((o2,e2)=>
{
objMyView.MyHtml = "<html><head></head><body><h1>Title</h1><p>Some body text that has changed.</p></body></html>";
});
objStackLayout.Children.Add(objMyButton2);
objStackLayout.Children.Add(objWebview);
The view model is just a simple one with a bindable property as below:-
public class MyView
: Xamarin.Forms.View
{
public static readonly BindableProperty MyHtmlProperty = BindableProperty.Create<MyView, string>(p => p.MyHtml, default(string));
public string MyHtml
{
get { return (string)GetValue(MyHtmlProperty); }
set { SetValue(MyHtmlProperty, value); }
}
}
Before clicking the button gives:-
After clicking the button, adjusts the view model, and automatically updates the control via the binding giving:-

Programatically create a Popup with a Child element initialised by Caliburn Micro

Windows.Media.Captures has a handy CameraCaptureUI class that can be instantiated as follows to show a dialog to the user to capture photos or videos:
// Create dialog to Capture Video
CameraCaptureUI dialog = new CameraCaptureUI();
dialog.VideoSettings.Format = CameraCaptureUIVideoFormat.Mp4;
StorageFile file = await dialog.CaptureFileAsync(CameraCaptureUIMode.Video);
if (file != null)
{
// Do something with file...
}
I would like to create my own custom audio capture class that works in a very similar way:
// Create dialog to Capture Audio
AudioCaptureUI dialog = new AudioCaptureUI();
StorageFile file = await dialog.CaptureFileAsync();
if (file != null)
{
// Do something with file...
}
To do the above, I created the following three files:
AudioCaptureUI - The class that a user instantiates to show the audio capture dialog
AudioCaptureView - UI View for the audio capture experience
AudioCaptureViewModel - ViewModel that contains all the audio capture logic
To create a full screen audio capture dialog, I have figured out that the best way is to use a Popup and set its child to the AudioCaptureView. The problem I have with this approach is that it is pushing me use a View-First pattern. Since I am using Caliburn Micro, I wanted to be able to use CM to instantiate a View by creating the ViewModel first.
What I currently have is something on the following lines:
public class AudioCaptureUI
{
private Popup _popup;
private TaskCompletionSource<StorageFile> _taskCompletionSource;
public IAsyncOperation<StorageFile> CaptureFileAsync()
{
// Force my View to be full screen
AudioCaptureView audioCaptureView = new AudioCaptureView
{
Width = Window.Current.Bounds.Width,
Height = Window.Current.Bounds.Height
};
// Creating View, instead of a ViewModel. Renders Caliburn Micro useless!
_popup = new Popup { Child = audioCaptureView };
if (_popup.Child != null)
{
SubscribeEvents();
_popup.IsOpen = true;
}
return AsyncInfo.Run(WaitForInput);
}
...
}
The above pattern works. However, I am forced to wire all my actions manually and cannot leverage Caliburn Micro's MVVM goodness.
How else should I instantiate a ViewModel programatically from my AudioCaptureUI class?
It is also important to highlight that I am working on a Windows Store app and using the WinRT CM port.
You could always port the WindowManager to WinRT in your own project. Looking at the source I don't think too much will need to change. https://caliburnmicro.codeplex.com/SourceControl/latest#src/Caliburn.Micro.Platform/net40/WindowManager.cs
You could bring over the Interface as well and use DI but for the sake of time here is the stand alone class. The main part for Model first binding is the ViewLocator.LocateForModel which returns the View from the ViewModel (aka the magic)
using System;
using System.Collections.Generic;
using Windows.UI.Xaml.Controls.Primitives;
namespace Caliburn.Micro
{
public class WindowManager
{
public virtual void ShowPopup(object rootModel, object context = null, IDictionary<string, object> settings = null)
{
var popup = CreatePopup(rootModel, settings);
var view = ViewLocator.LocateForModel(rootModel, popup, context);
popup.Child = view;
//popup.SetValue(View.IsGeneratedProperty, true);
ViewModelBinder.Bind(rootModel, popup, null);
Caliburn.Micro.Action.SetTargetWithoutContext(view, rootModel);
var activatable = rootModel as IActivate;
if (activatable != null)
{
activatable.Activate();
}
var deactivator = rootModel as IDeactivate;
if (deactivator != null)
{
popup.Closed += delegate { deactivator.Deactivate(true); };
}
popup.IsOpen = true;
//popup.CaptureMouse();
}
protected virtual Popup CreatePopup(object rootModel, IDictionary<string, object> settings)
{
var popup = new Popup();
ApplySettings(popup, settings);
return popup;
}
bool ApplySettings(object target, IEnumerable<KeyValuePair<string, object>> settings)
{
if (settings != null)
{
var type = target.GetType();
foreach (var pair in settings)
{
var propertyInfo = type.GetPropertyCaseInsensitive(pair.Key);
if (propertyInfo != null)
{
propertyInfo.SetValue(target, pair.Value, null);
}
}
return true;
}
return false;
}
}
}
Then all you need to do is create an instance and give it a ViewModel:
var windowManager = new WindowManager();
windowManager.ShowPopup(new MyPopupThingViewModel());
Note: I've only used this in an 8.1 app so not 100% sure if it will completely work with 8.0
You might have some success with the Caliburn.Micro WindowManager. There isn't a great deal about it in the official documentation (you're best off searching Google and the CM discussions). I've used it in one of my applications where I needed to host a particular ViewModel in a new window, and wanted to utilise all of the Caliburn.Micro goodness (and my existing Views).
Have a look at the Caliburn.Micro.IWindowManager interface, you'll see some handy methods that you can call from a WindowManager instance (depending on the popup type you're after).
public interface IWindowManager
{
bool? ShowDialog(object rootModel, object context = null, IDictionary<string, object> settings = null);
void ShowPopup(object rootModel, object context = null, IDictionary<string, object> settings = null);
void ShowWindow(object rootModel, object context = null, IDictionary<string, object> settings = null);
}
In my application, to pop up my a Window with my ViewModel of choice, I did something along these lines (your names inserted):
// Some basic Window settings.
dynamic settings = new ExpandoObject();
settings.Title = "Test Window";
settings.WindowStartupLocation = WindowStartupLocation.Manual;
settings.SizeToContent = SizeToContent.Manual;
settings.Width = 450;
settings.Height = 300;
var localAudioCaptureViewModel new AudioCaptureViewModel ();
WindowManagerFactory.WindowManager.ShowWindow(localAudioCaptureViewModel, null, settings); // I didn't require context (null)
Caliburn.Micro should resolve your Views to the correct ViewModels, and you're good to go.

C# Windows.Forms converting code to WPF

I am trying to convert my Windows Form program into a WPF program in order to get images in my NotifyIcon systemtray icon. I am having issues converting it though. My current program has a tabcontrol1 and it uses the function: TabPages and DrawItem. WPF does not have these functions, but instead of TabPages it has Items, but I do not know what to change "DrawItem" to for WPF.
The reason why I am using "DrawItem" in my Windows Form is to change the color of the Tab text.
Changing from:
if (!find<T>(p.Value))
{
T myPage = new T();
myPage.Text = "Ping";
this.FormstabControl.TabPages.Add(myPage);
this.FormstabControl.DrawItem += new DrawItemEventHandler(ListBox1_DrawItem);
myPage.DataGridView.DataSource = p.Result;
}
To:
if (!find<T>(p.Value))
{
T myPage = new T();
myPage.Text = "Ping";
this.WPFtabControl.Items.Add(myPage);
//this.WPFtabControl.DrawItem += new DrawItemEventHandler(ListBox1_DrawItem);
myPage.DataGridView.DataSource = p.Result;
}
I had to comment out DrawItem because I do not know what to use instead. Also, type "T" is of type "TabPages" not Item. Below is the Find function that checks to see if the Tab already exists in the tabcontrol. When I declare myPage of type T, it setsup the DataGridView from within a different class (same as where T is defined.) I tried to fix it by throwing the WPF TabControl1 into a Windows.Form TabControl2, then searching through that tabcontrol's tabpages instead of passing a WPF Tabcontrol Item.
private bool find<T>()
{
bool found = false;
System.Windows.Forms.TabControl FormstabControl= new System.Windows.Forms.TabControl();
FormstabControl.TabPages.Add(this.WPFtabControl.Items.ToString());
foreach (TabPage page in FormstabControl.TabPages)
{
if (page is T)
{
found = true;
break;
}
}
return found;
}
private bool find<T>(string text) where T : TabPage
{
bool found = false;
System.Windows.Forms.TabControl FormstabControl= new System.Windows.Forms.TabControl();
FormstabControl.TabPages.Add(this.WPFtabControl.Items.ToString());
foreach (TabPage page in FormstabControl.TabPages)
{
if (page is T && text.Equals(page.Text))
{
found = true;
break;
}
}
return found;
}
When I run this app and the adjacent function, it runs and completes and adds a BLANK text tab, but returns no data to the datagrid within the TabControl. I do not know what is wrong.
How can I incorporate images in my NotifyIcon? I incorporate it like this:
this.notifyIcon.ContextMenu = new ContextMenu();
this.notifyIcon.ContextMenu.MenuItems.Add(new MenuItem("Hide", new EventHandler(hideApp)));
this.notifyIcon.ContextMenu.MenuItems.Add(new MenuItem("Show", new EventHandler(showApp)));
this.notifyIcon.ContextMenu.MenuItems.Add(new MenuItem("Exit", new EventHandler(exitApp)));

Categories

Resources