How to Binding html to a WebView - xaml

i was searching about how to binding html in webview and i found this:
public static class WebBrowserHelper
{
public static readonly DependencyProperty HtmlProperty = DependencyProperty.RegisterAttached(
"Html", typeof(string), typeof(WebBrowserHelper), new PropertyMetadata(null, OnHtmlChanged));
public static string GetHtml(DependencyObject dependencyObject)
{
return (string)dependencyObject.GetValue(HtmlProperty);
}
public static void SetHtml(DependencyObject dependencyObject, string value)
{
dependencyObject.SetValue(HtmlProperty, value);
}
private static void OnHtmlChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var browser = d as WebView;
if(browser == null)
return;
var html = e.NewValue.ToString();
browser.NavigateToString(html);
}
}
and the xamls code should be that
<WebView Grid.Column="1" Height="628" Margin="10,0" VerticalAlignment="Top" cxi:WebBrowserHelper.Html="{Binding Question.Body}" />
but i can't acces this property in xaml, am i doing something wrong?

I see you're following the sample listed here.
Without seeing your full XAML listing, I'm going to guess that you don't have a namespace declaration for the cxi namespace. You probably copied the code from the page and pasted it into your own class that's in your own namespace. You need to make sure you have a namespace prefix defined for the namespace where this class resides before you can use it.
Lets say you defined WebBrowserHelper in the 'MyStuff' namespace. You would use:
xmlns:ms="using MyStuff"
At the top of your xaml file. Then later you would use
ms:WebBrowserHelper.Html
So you'd use the ms prefix instead of the cxi prefix.
Dev support, design support and more awesome goodness on the way: http://bit.ly/winappsupport

Related

Bind to an Item of a Dependency Collection

I'm trying to create a custom control that has a header and a footer and body. The idea is that the body of the report is a custom stack panel control that will allow the user to indicate page orientation and grouping. I created a dependency property on the custom UC to accept an IList of the custom stack panel. What I am trying to do is bind to one of the stack panels in the list. But for some reason the binding is not working.
The ReportPage:
public class ReportPage : StackPanel
{
//Nothing right now but will eventually include controls for page orientation and size (8.5x11, 11x17, etc.)
}
The UserControl code behind:
public partial class Report : UserControl, INotifyPropertyChanged
{
public Report()
{
ReportPages = new List<ReportPage>();
}
public static readonly DependencyProperty =
DependencyProperty.Register("ReportPages", typeof(IList), typeof(Report));
public IList ReportPages
{
get => (IList)GetValue(ReportPagesProperty);
set
{
SetValue(ReportPagesProperty, value);
ActivePage = value[0];
OnPropertyChanged(nameof(ActivePage));
}
}
private ReportPage _activePage;
public ReportPage ActivePage
{
get => _activePage;
set
{
_activePage = value;
OnPropertyChanged(nameof(ActivePage));
}
{
}
The UserControl xaml:
<Grid>
<!--Some xaml for the header and footer.-->
<ContentControl Content="{Binding ActivePage, RelativeSource={RelativeSource, FindAncestor, AncestorType=local:Report}}"/>
</Grid>
Here is how I am consuming the custom control. This should, in my mind at least, make three "pages" which I can toggle between using a button control that I didn't share.
<reportEngine:Report>
<reportEngine:Report.ReportPages>
<reportEngine:ReportPage>
<TextBlock>This is Page 1</TextBlock>
</reportEngine:ReportPage>
<reportEngine:ReportPage>
<TextBlock>This is Page 2</TextBlock>
</reportEngine:ReportPage>
<reportEngine:ReportPage>
<TextBlock>This is Page 3</TextBlock>
</reportEngine:ReportPage>
</reportEngine:Report.ReportPages>
</reportEngine:Report>
Any Ideas why the binding isn't working?
So I at least found a quick work around. I utilized the Collection Changed Event handler pattern from this answer and modified it for static dependency properties. Then, to get the values from the collection bound to the dependency property I create a static instance of the Report object in the constructor and use that to pass various values back to the object from the collection. Something like this:
public partial class Report : UserControl, INotifyPropertyChanged
{
private static Report _thisReport;
public Report()
{
InitializeComponent();
ReportPages = new ObservableCollection<ReportPage>();
_thisReport = this;
}
public static readonly DependencyProperty ReportPagesProperty =
DependencyProperty.Register("ReportPages", typeof(IList), typeof(Report), new FrameworkPropertyMetadata(ReportPagesChanged));
public IList ReportPages
{
get => (IList)GetValue(ReportPagesProperty);
set
{
SetValue(ReportPagesProperty, value);
//Update some other properties associated with the control (Total Page Numbers, etc.)
}
}
private static void ReportPagesChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs eventArgs)
{
var newColl = (INotifyCollectionChanged)eventArgs.NewValue;
if (newColl != null)
newColl.CollectionChanged += ReportPages_CollectionChanged;
var oldColl = (INotifyCollectionChanged)eventArgs.OldValue;
if (oldColl != null)
oldColl.CollectionChanged -= ReportPages_CollectionChanged;
}
private static void ReportPages_CollectionChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
{
var newPages = (IList<ReportPage>) sender;
//Updates properties of the Report control.
_thisReport.ActivePage = newPages[0];
_thisReport.TotalPageNumber = newPages.Count;
}
}
Whether this is "correct" or not I couldn't say, but it works. If someone has a better answer I will change the answer.

Issue with bindings on attached properties in Xamarin.Forms

EDIT: Please, do not post answers on how to implement gestures in Xamarin.Forms - read the entire post first.
I'm creating a swipe gesture handlers as effects using the attached properties (as described in Xamarin guides). Skipping the approach discussion I have a strange issue with attached properties implementation.
Long story short (code below) - XAML bindings to attached properties are not working. The Set\Get...Command methods in my static class are not executed at all. I don't see any Debug.WriteLine() result in app output. The debugger doesn't hit the breakpoints set there as well. The same with ...CommandPropertyChanged() handler.
This is my class for the properties handling:
namespace Core.Effects
{
public static class Gesture
{
public static readonly BindableProperty SwipeLeftCommandProperty =
BindableProperty.CreateAttached("SwipeLeftCommand", typeof(ICommand), typeof(Gesture), null, propertyChanged: SwipeLeftCommandPropertyChanged);
public static readonly BindableProperty SwipeRightCommandProperty =
BindableProperty.CreateAttached("SwipeRightCommand", typeof(ICommand), typeof(Gesture), null, propertyChanged: SwipeRightCommandPropertyChanged);
public static ICommand GetSwipeLeftCommand(BindableObject view)
{
Debug.WriteLine("GetSwipeLeftCommand");
return (ICommand) view.GetValue(SwipeLeftCommandProperty);
}
public static void SetSwipeLeftCommand(BindableObject view, ICommand value)
{
Debug.WriteLine("SetSwipeLeftCommand");
view.SetValue(SwipeLeftCommandProperty, value);
}
public static ICommand GetSwipeRightCommand(BindableObject view)
{
Debug.WriteLine("GetSwipeRightCommand");
return (ICommand) view.GetValue(SwipeRightCommandProperty);
}
public static void SetSwipeRightCommand(BindableObject view, ICommand value)
{
Debug.WriteLine("SetSwipeRightCommand");
view.SetValue(SwipeRightCommandProperty, value);
}
private static void SwipeLeftCommandPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
Debug.WriteLine("SwipeLeftCommandPropertyChanged");
// ...
}
private static void SwipeRightCommandPropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
Debug.WriteLine("SwipeRightCommandPropertyChanged");
// ...
}
// ...
}
}
and here is how I use it in XAML:
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:effects="clr-namespace:Core.Effects"
x:Class="Core.Pages.RequestDetailsPage">
<ContentPage.Content>
<StackLayout Spacing="0"
Padding="0"
VerticalOptions="FillAndExpand"
effects:Gesture.SwipeLeftCommand="{Binding NavigateToPreviousRequestCommand}"
effects:Gesture.SwipeRightCommand="{Binding NavigateToNextRequestCommand}">
I have corresponding commands in my view model (MVVM implemented with FreshMvvm framework):
namespace Core.PageModels
{
public class RequestDetailsPageModel : FreshBasePageModel
{
public IRelayCommand NavigateToNextRequestCommand;
public IRelayCommand NavigateToPreviousRequestCommand;
IRelayCommand is my type deriving from ICommand. The BindingContext is properly set by FreshMvvm (works well in other places on this view).
Any clue what might be wrong?
I have done sample repo on GitHub, Check Below Link.
https://github.com/softlion/XamarinFormsGesture
https://github.com/tkowalczyk/SimpleCustomGestureFrame
http://arteksoftware.com/gesture-recognizers-with-xamarin-forms/
My mistake was pretty simple (and pretty hard to track either). Bindings do not operate on fields but on properties:
namespace Core.PageModels
{
public class RequestDetailsPageModel : FreshBasePageModel
{
public IRelayCommand NavigateToNextRequestCommand {get; set;}
public IRelayCommand NavigateToPreviousRequestCommand {get; set;}

XAML Binding - App.cs

Question about binding in XAML with WP8.
In my App.cs I declare a public property for class Setting. In other xaml pages I need to access that propery and pass that property to a ConverterParameter. I can't say I've found a clean way of doing this. Below is my current method of how I accomplish this, but it just feels dirty. Any other ways out there?
So what's happening with code below? In app the settings data gets loaded. Any time the settings gets loaded or the a setting changes it Removes/Adds App.Current.Resource. This then allows me to data bind it {StaticResource {resourceName}}
Again, this works 100%...but is there a better/another way to accomplish this?
App.cs
private static Settings _settings = null;
public static Settings Settings
{
get { return _settings; }
private set { _settings = value; }
}
private async void Application_Launching(object sender, LaunchingEventArgs e)
{
if (Settings == null)
Settings = await FlightPath.Core.Data.LoadSettingsAsync();
App.Current.Resources.Add("Settings", App.Settings);
Settings.SettingsChanged += Settings_SettingsChanged;
}
private void Settings_SettingsChanged(object sender, EventArgs e)
{
if (App.Current.Resources["Settings"] == null)
App.Current.Resources.Add("Settings", App.Settings);
else
{
App.Current.Resources.Remove("Settings");
App.Current.Resources.Add("Settings", App.Settings);
}
}
Application Page XAML using Converter / ConverterParameter
<TextBlock Text="{Binding observation_time,
Converter={StaticResource ZuluToLocalTimeConverter},
ConverterParameter={StaticResource Settings}}"
Style="{StaticResource PhoneTextNormalStyle}"
Margin="-4,0,0,0"/>
if you are using MVVM you can Create a SettingManager class which having a Singleton instance. Then declare its propert in ViewModelBase class. Finally use it into your xaml code
XAML
C#
class ViewModelBaseClass: InotifyPropertyChanged
{
public SettingManager Settings{get{return SettingManager.Instance;}}
}
class SettingManager
{
public static Instance{get{...}}
public string this[string sName]
{
return "whatever you need";
}
}
class MYViewModel: ViewModelBase
{
}

XamlParseException Failed to assign to property. Binding not working with attached property

I want to create custom text box with attached property for Windows Store app. I am following this solution. Now it uses hard coded value as property value but I want to set value using binding, but it's not working. I tried to search a lot but didn't helped me any solution.
The exception details is like this
An exception of type 'Windows.UI.Xaml.Markup.XamlParseException'
occurred in CustomTextBox.exe but was not handled in user code
WinRT information: Failed to assign to property
'CustomTextBox.Input.Type'.
MainPage.xaml
<!-- local:Input.Type="Email" works -->
<!-- local:Input.Type="{Binding SelectedTextboxInputType}" not working -->
<TextBox x:Name="txt" local:Input.Type="{Binding SelectedTextboxInputType}" Height="30" Width="1000" />
<ComboBox x:Name="cmb" ItemsSource="{Binding TextboxInputTypeList}" SelectedItem="{Binding SelectedTextboxInputType}" Height="30" Width="200"
Margin="451,211,715,527" />
MainPage.xaml.cs
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
DataContext = new ViewModel();
}
}
Input.cs
//InputType is enum
public static InputType GetType(DependencyObject obj)
{
return (InputType)obj.GetValue(TypeProperty);
}
public static void SetType(DependencyObject obj, InputType value)
{
obj.SetValue(TypeProperty, value);
}
public static readonly DependencyProperty TypeProperty =
DependencyProperty.RegisterAttached("Type", typeof(InputType), typeof(TextBox), new PropertyMetadata(default(InputType), OnTypeChanged));
private static void OnTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is InputType)
{
var textBox = (TextBox)d;
var Type = (InputType)e.NewValue;
if (Type == InputType.Email || Type == InputType.URL)
{
textBox.LostFocus += OnLostFocus;
}
else
{
textBox.TextChanged += OnTextChanged;
}
}
}
ViewModel.cs
public class ViewModel : BindableBase
{
public ViewModel()
{
TextboxInputTypeList = Enum.GetValues(typeof(InputType)).Cast<InputType>();
}
private InputType _SelectedTextboxInputType = InputType.Currency;
public InputType SelectedTextboxInputType
{
get { return _SelectedTextboxInputType; }
set { this.SetProperty(ref this._SelectedTextboxInputType, value); }
}
private IEnumerable<InputType> _TextboxInputTypeList;
public IEnumerable<InputType> TextboxInputTypeList
{
get { return _TextboxInputTypeList; }
set { this.SetProperty(ref this._TextboxInputTypeList, value); }
}
}
This is a pretty common mistake. The problem is, binding targets cannot be CLR properties in XAML. It's just the rules. A binding source can be a CLR property, just fine. The targets simply must be dependency properties.
We all get the error! :)
I describe the whole thing here: http://blogs.msdn.com/b/jerrynixon/archive/2013/07/02/walkthrough-two-way-binding-inside-a-xaml-user-control.aspx
Best of luck.
Incorrect
public static readonly DependencyProperty TypeProperty =
DependencyProperty.RegisterAttached("Type", typeof(InputType), typeof(TextBox), new PropertyMetadata(default(InputType), OnTypeChanged));
Correct
public static readonly DependencyProperty TypeProperty =
DependencyProperty.RegisterAttached("Type", typeof(InputType), typeof(Input), new PropertyMetadata(default(InputType), OnTypeChanged));

XAML Resource with static items?

<Window.Resource>
<ResourceDictionary>
<local:SomeResourceWithObsCollection x:Key="MyItemWithCollection">
<local:SomeClass.Instance /> <!-- THIS DOES NOT WORK -->
</local:SomeResourceWithObsCollection>
</ResourceDictionary>
</Window.Resources>
I don't know how to get that line to work... I've tried doing <x:Static SomeClass.Instance />, but that also isn't allowed.
[ContentProperty("TheItems")]
public class SomeResourceWithObsCollection
{
public class SomeResourceWithObsCollection()
{
TheItems = new ObservableCollection<IMyInterface>();
}
public ObservableCollection<IMyInterface> TheItems { get; set; }
}
public class SomeClass : IMyInterface
{
private static SomeClass _instance = new SomeClass();
private SomeClass() { }
public SomeClass Instance { get { return _instance; } }
}
You can't do what you're asking to do in XAML as of right now. Perhaps future versions of XAML will account for this. You have to do it in the code behind, here is an example:
Adding a static object to a resource dictionary
The closest I can suggest is a combination of the CompositeCollection and using ListBoxItems (or some other equivalent) to wrap your static content (as I believe you can only pull static content into XAML using the {x:Static} markup extension)
This can be used in XAML as below:
<ListBox>
<ListBox.ItemsSource>
<CompositeCollection>
<ListBoxItem Content="{x:Static local:Example.One}" />
<ListBoxItem Content="{x:Static local:Example.Two}" />
</CompositeCollection>
</ListBox.ItemsSource>
</ListBox>