Binding a URL to custom SVG container's BindableProperty - xamarin.forms

I have been using the code layout here to create an SVG container for a Xamarin Forms project. It works well and I reconfigured it to read the image from a remote URL.
The ResourceId is from the source above:
public static readonly BindableProperty SvgUriProperty = BindableProperty.Create(
"ResourceId",
typeof(string),
typeof(SvgUriContainer),
default(string),
propertyChanged: RedrawCanvas);
public string ResourceId
{
get => (string)GetValue(SvgUriProperty);
set => SetValue(SvgUriProperty, value);
}
However I can not seem to bind that URL at run time in the XAML:
<control:SvgUriContainer
Grid.Row="0"
Grid.RowSpan="4"
Grid.Column="0"
ResourceId="{Binding StampUri}"
[...]
/>
That Binding returns a string and the rest of the bindings work fine. Any attempt to bind in that fashion results in a build error:
No property, bindable property, or event found for 'ResourceId', or mismatching type between value and property.
No matter what I do in the container logic with the BindablePropertycreation, the error is the same and is in the XAML. Am I getting the syntax wrong in the XAML? Is it because Binding is a BindingExtension (not a string) at build time?
Note: if I replace the Binding with a string/URL it all works fine.
Note: if I set the type of ResourceId to object I can get by the build error but the string does not resolve, of course.

Can you try to modify your bindableProperty to the standard format described in document:
public static readonly BindableProperty SvgUriProperty = BindableProperty.Create(
"SvgUri",
typeof(string),
typeof(EventToCommandBehavior),
"test",
propertyChanged: RedrawCanvas);
public string SvgUri
{
get => (string)GetValue(SvgUriProperty);
set => SetValue(SvgUriProperty, value);
}
Xamarin requires a Property naming convention.

Related

Attached Property binding not working for Flayout (Xaml, UWP)

I've faced a problem: Attached property doesn't work for Button's Flayout.
I have an outer button with inner button (flayout), attached property - is a ICommand type property. Outer button successfully binds to attached property BUT inner button doesn't.
Here User Control code:
<UserControl x:Class="uwp_AttachedProperty.MyUserControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:uwp_AttachedProperty"
Name="Root">
<Button Command="{Binding ElementName=Root, Path=(local:AttachedProps.CommandAdd), Mode=OneWay}">
<Button.Flyout>
<Flyout>
<!--*** DOESN'T WORK HERE***-->
<Button Command="{Binding ElementName=Root, Path=(local:AttachedProps.CommandAdd),Mode=OneWay}"/>
</Flyout>
</Button.Flyout>
</Button>
</UserControl>
Attached property code:
public sealed class AttachedProps : DependencyObject
{
public static readonly DependencyProperty CommandAddProperty = DependencyProperty.Register(
"CommandAdd",
typeof(ICommand),
typeof(AttachedProps),
new PropertyMetadata(null));
public static void SetCommandAdd(UIElement element, ICommand value) { element.SetValue(CommandAddProperty, value); }
public static ICommand GetCommandAdd(UIElement element) { return (ICommand)element.GetValue(CommandAddProperty); }
}
My case is an ICommand propery, but it doesn't work any type (double, string etc.) of attached property.
Does any one faced the same problem, how can it be fixed?
(Windows 10, 1809, Build: 17763)
Thanks.
Attached Property binding not working for Flayout (Xaml, UWP)
Derive this case reply The problem is you used Binding ElementName=Root in the Flyout, When you bind data in the content of Flyout, the binding source is in Page, but the actual binding target is in PopupRoot, they have different DataContext, so can't it work here.

Binding not working in Rg.Plugins.Popup for custom control

I have a custom control based on ContentView with some BindableProperty fields. These controls work great on normal ContentPage pages.
I am now trying to use them in a popup, using the Rg.Plugins.Popup nuget package. The controls display normally, but they never show any values - the binding does not appear to be working. The fields do appear to get bound to null before the constructor of the popups ContentView is called, but nothing happens when the BindingContext is changed.
Here is how the BindableProperty(s) are set up in the control:
public string FieldValue { get; set; }
public static readonly BindableProperty FieldValueProperty = BindableProperty.Create(
propertyName: "FieldValue",
returnType: typeof(string),
declaringType: typeof(MFGField),
defaultValue: "",
defaultBindingMode: BindingMode.TwoWay,
propertyChanged: FieldValuePropertyChanged);
private static void FieldValuePropertyChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (MFGField)bindable;
if(newValue != null)
control.ValueEntry.Text = newValue.ToString();
}
Here is how it is set up in the XAML:
<MyNamespace:MFGField x:Name="OrderNumber" FieldValue="{Binding CurrentPick[Order_Number]}" LabelText="Order Number:" ReadOnly="true" Grid.Column="0" Grid.Row="0"/>
The popup ContentView currently has a ViewLifecycleEffect that serves as the 'OnAppearing' for the popup, and that is currently where I am setting the BindingContext after loading the data:
private async void ViewLifecycleEffect_OnLoaded(object sender, EventArgs e)
{
await callingPage.LoadBinRecord(callingPage.SearchTextValue);
((AppData)this.BindingContext).CurrentPick = ((AppData)this.BindingContext).CurrentPicks[((AppData)this.BindingContext).PickIndex];
}
I have confirmed that the data in the object that should be bound is present and correct, but the PropertyChanged functions for my fields don't get called when the BindingContext is updated.
I am coming back to Xamarin Forms after some time, and I'm sure I'm missing something obvious, but I am missing it nevertheless. Any help is appreciated.
My apologies, this issue appears to be the result of my unfortunate choice of fields to which to bind. There are well over 200 fields in the object, and I happened to select several quite reasonable choices for testing, where the values are unexpectedly null.
Initially, I did have a problem getting the BindingContext set properly, and the field issue prevented me from seeing that I had actually fixed that problem. The binding does in fact seem to be working now that the correct fields are bound.

Xamarin forms visual studio for Mac clean-namespace problem

I have created a Xamarin forms application using .net standard. Then I added a .net standard library project to the solution that will include common codes such as renders, behaviours etc. I include the reference of common .net standard library project to the main Xamarin forms project by right clicking on dependencies and Edit References menu. Finally I try to include the namespace of renderer files on the content page of main Xamarin forms by specifying the below line
using Xamarin.Forms;
namespace MyProject.Shared.Renderer
{
public class ExtendedEntry : Entry
{
public static readonly BindableProperty IsBorderErrorVisibleProperty = BindableProperty.Create(nameof(IsBorderErrorVisible), typeof(bool), typeof(ExtendedEntry),
false, BindingMode.TwoWay);
public bool IsBorderErrorVisible
{
get { return (bool)GetValue(IsBorderErrorVisibleProperty); }
set { SetValue(IsBorderErrorVisibleProperty, value); }
}
public static readonly BindableProperty BorderErrorColorProperty = BindableProperty.Create(nameof(BorderErrorColor), typeof(Color), typeof(ExtendedEntry),
null, BindingMode.TwoWay);
public Color BorderErrorColor
{
get { return (Color)GetValue(BorderErrorColorProperty); }
set { SetValue(BorderErrorColorProperty, value); }
}
public static readonly BindableProperty ErrorTextProperty = BindableProperty.Create(nameof(ErrorText), typeof(string), typeof(ExtendedEntry), string.Empty,
BindingMode.TwoWay);
public string ErrorText
{
get { return (string)GetValue(ErrorTextProperty); }
set { SetValue(ErrorTextProperty, value); }
}
}
}
xmlns:controls=“clr-namespace:MyProject.Shared.Renderer:assembly:MyProject.Shared”
Then I reference the control as
<controls:ExtendedEntry />
But this gives build error that says ExtendedEntry is not found in the assembly MyProject.Shared
Please help
Well actually this issue is quite common what happens is your project is not compiled properly or after compiling the bin and obj are missing this class which is fine.
Solution:
Delete all bin obj folders from all the projects in your solution.
Now individually build all your projects based on dependency i.e. if you have four projects A, B, iOS and Android and B is dependent on A i.e. it has a reference to A then you will first clean build A then B and then any amongst iOS and Android.
If even after this your issue is not resolved then you might want to restart VS all together
In case you still face this issue feel free to revert.
Good luck
Sorry...I had done blunder...a real blunder.
I typed ":" instead of "=" in assembly attribute.
It should be
xmlns:controls=“clr-namespace:MyProject.Shared.Renderer:assembly=MyProject.Shared”

ReactiveUI with XF: How to create a Command Binder for a custom control?

I am working with Xamarin Forms and ReactiveUI and trying to bind a custom command from a custom XF control to my view model.
this.BindCommand(ViewModel, vm => vm.HasChangesCommand, view => view.socket1);
My control socket1 has a Dependency Property Command of type ICommand. However, I'm getting the error:
"System.Exception: Couldn't find a Command Binder for [ControlName]"
I think I have to create a Command Binder for my control but I can't find any hint on how to do this.
Is there any documentation on how to create a Command Binder for a custom control on Xamarin Forms?
EDIT:
I've seen that adding third parameter "eventName" it's working. However I would like to know if there's any way to build that Command Binder so you don't need to specify the event in that call.
If you want to be able to use BindCommand with a custom view, the easiest way is to have a property of type ICommand on the view that is named Command. Doing a OneWayBind as Daniel suggested is also easy, though it's also easy to forget to do that when you're used to using BindCommand for command bindings.
If you want to use anything else (an event, gesture recognizer, etc...), you can create an implementation of ICreatesCommandBinding that defines how the command is wired up to the target object. So you can do something like the following:
public class SocketControl : ContentView
{
public static readonly BindableProperty MyCustomCommandProperty = BindableProperty.Create(
nameof(MyCustomCommand),
typeof(ICommand),
typeof(SocketControl));
public ICommand MyCustomCommand
{
get => (ICommand)GetValue(MyCustomCommandProperty);
set => SetValue(MyCustomCommandProperty, value);
}
//...
}
public sealed class SocketControlCommandBinder : ICreatesCommandBinding
{
public IDisposable BindCommandToObject(ICommand command, object target, IObservable<object> commandParameter)
{
var socket = (SocketControl)target;
// get the original value so we can restore it when the binding is disposed...
var originalValue = socket.GetValue(SocketControl.MyCustomCommandProperty);
var disposable = Disposable.Create(() => socket.SetValue(SocketControl.MyCustomCommandProperty, originalValue));
// set the control's command to the view-model's command
socket.SetValue(SocketControl.MyCustomCommandProperty, command);
return disposable;
}
public IDisposable BindCommandToObject<TEventArgs>(ICommand command, object target, IObservable<object> commandParameter, string eventName)
{
/// not shown here ...
return Disposable.Empty;
}
/// <summary>
/// Returns a positive integer when this class supports BindCommandToObject for this
/// particular Type. If the method isn't supported at all, return a non-positive integer.
/// When multiple implementations return a positive value, the host will use the one which
/// returns the highest value. When in doubt, return '2' or '0'
/// </summary>
/// <param name="type">The type to query for.</param>
/// <param name="hasEventTarget">If true, the host intends to use a custom event target.</param>
/// <returns>A positive integer if BCTO is supported, zero or a negative value otherwise</returns>
public int GetAffinityForObject(Type type, bool hasEventTarget)
{
return type.GetTypeInfo().IsAssignableFrom(typeof(SocketControl).GetTypeInfo()) ? 2 : 0;
}
}
Once you have the command binder created, you need to register it so ReactiveUI knows how to use it. In your app.xaml.cs (or wherever you create your application):
Splat.Locator.CurrentMutable.Register(
() => new SocketControlCommandBinder(),
typeof(ReactiveUI.ICreatesCommandBinding));
One way to solve this is to do a OneWayBind to the command instead. Your control should then handle the command. Setting enabled if needed and execute command when needed.
this.OneWayBind(ViewModel, vm => vm.HasChangesCommand, view => view.socket1.CommandName);

How to bind to a WPF dependency property to window?

i create a dependency property to close a view from view model,
dependencyProperty:
public static class WindowBehaviors
{
public static readonly DependencyProperty IsOpenProperty =
DependencyProperty.RegisterAttached("IsOpen"
, typeof(bool),
typeof(WindowBehaviors),
new UIPropertyMetadata(false, IsOpenChanged));
private static void IsOpenChanged(DependencyObject obj,DependencyPropertyChangedEventArgs args)
{
Window window = Window.GetWindow(obj);
if (window != null && ((bool)args.NewValue))
window.Close();
}
public static bool GetIsOpen(Window target)
{
return (bool)target.GetValue(IsOpenProperty);
}
public static void SetIsOpen(Window target, bool value)
{
target.SetValue(IsOpenProperty, value);
}
}
and use it in my xaml like this:
<window
...
Command:WindowBehaviors.IsOpen="True">
it work's fine,but when i want to bind it to a property in viewModel,it dosen't work,and i guess,it dosen't work because i define the resource later in xaml.
in xaml:
<Window.Resources>
<VVM:myVieModel x:Key="myVieModel"/>
</Window.Resources>
and i don't know what should i do,where should i put this:
Command:WindowBehaviors.IsOpen="{binding Isopen}"
public MainWindow()
{
InitializeComponent();
// DO THIS
this.DataContext = Resources["myVieModel"];
}
You need to bind the data context for the scope where your binding is in. Usually this is fairly high up in your XAML, usually the first element in your form or control.
In your case, the data context beeing a static resource the folllowing should work:
<grid DataContext="{StaticResource myVieModel}">
<!-- the code with the binding goß into here -->
</grid>
Actually this is the same as ebattulga suggests, just the XAML way (no code behind).
Thanks for your helps,i fixed it and here is my solution,
i used to use MVVMToolkit but now i'm useing MVVMlight and as you know in MVVMLight,we just define Application Resources Once in App.xaml.so we can bind all the window's properties simply,hope this can help some people who has the same problem!!
app.xaml
<Application.Resources>
<!--Global View Model Locator-->
<vm:ViewModelLocator x:Key="Locator"
d:IsDataSource="True" />
</Application.Resources>
and in the window(view)
DataContext="{Binding DefaultSpecItemVM, Source={StaticResource Locator}}"
and it works perfect.:D

Resources