Xamarin Forms set margins through a setter - user-interface

I am trying to set margins programmatically based on the data. I have used a converter for to achieve this. It works great to set the background color but I can't find how to do it to set the margin.
This is my code:
private void SetStyles()
{
Style incomingMessageStyle = new Style(typeof(Frame))
{
Setters = {
new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.FromRgb(221, 221, 221) },
new Setter { Property = Margin, Value = "10,10,80,0"} //MARGIN IS NOT FOUND!
}
};
Resources.Add("IncomingMessageStyle", incomingMessageStyle);
Style outgoingMessageStyle = new Style(typeof(Frame))
{
Setters = {
new Setter { Property = VisualElement.BackgroundColorProperty, Value = Color.FromRgb(178, 226, 129) },
new Setter { Property = Margin, Value = "10,10,0,80"} //HOW TO SET THE MARGIN HERE?
}
};
Resources.Add("OutgoingMessageStyle", outgoingMessageStyle);
}

try this
new Setter { Property = View.MarginProperty, Value = new Thickness(...) }

Related

MvvmCross iOS UILabel AttributedText with Language converter

I create a custom control for UILabel with custom Kern parameter.
[Register("CustomLabelView"), DesignTimeVisible(true)]
public class CustomLabelView : UILabel
{
private float _textLetterSpacing;
public CustomLabelView(IntPtr handle) : base(handle)
{
}
[Export("TextLetterSpacing"), Browsable(true)]
public float TextLetterSpacing
{
get => _textLetterSpacing;
set
{
_textLetterSpacing = value;
SetNeedsDisplay();
}
}
public CustomLabelView()
{
Initialize();
}
public override void AwakeFromNib()
{
// Called when loaded from xib or storyboard.
Initialize();
}
void Initialize()
{
NSRange range = new NSRange(0, Text.Length);
var attributes = AttributedText.GetCoreTextAttributes(0, out range);
var attributedTitle = new NSAttributedString(Text, new CTStringAttributes() { KerningAdjustment = TextLetterSpacing, ForegroundColor = TextColor.CGColor, UnderlineStyle = attributes.UnderlineStyle });
AttributedText = attributedTitle;
SetNeedsDisplay();
}
}
I bind text to this control with language converter
set.Bind(CustomLabelView)
.For(c => c.Text)
.To(vm => vm.TextSource)
.WithConversion("Language", "AgreementText");
and underline property doesn't apply for bound text. Also I tried AttributedText property instead of Text. No any changes.
My LinkerPleaseInclude file contains this lines
public void Include(UILabel label)
{
label.Text = label.Text + "";
label.AttributedText = new NSAttributedString(label.AttributedText.ToString() + "");
}
Any ideas how to sort it out?
I changed the UnderlineStyle property's value to one of the enumeration of CTUnderlineStyle and it works for me.
namespace CoreText
{
//
// Summary:
// Specifies the style of an underline ornament.
//
// Remarks:
// To be added.
public enum CTUnderlineStyle
{
None = 0,
Single = 1,
Thick = 2,
Double = 9
}
}
Here is my code:
void Initialize()
{
this.Text = "This is some formatted text";
NSRange range = new NSRange(0, Text.Length);
var attributes = AttributedText.GetCoreTextAttributes(0, out range);
var attributedTitle = new NSAttributedString(Text, new CTStringAttributes() { KerningAdjustment = TextLetterSpacing, ForegroundColor = TextColor.CGColor, UnderlineStyle = CTUnderlineStyle.Single });
AttributedText = attributedTitle;
SetNeedsDisplay();
}
The underline appears,is this you want?
I just put Initialize method into Draw for my CustomLabel.
Here is the solution:
public override void Draw(CGRect rect)
{
Initialize();
base.Draw(rect);
}
private void Initialize()
{
var attributes = AttributedText.GetCoreTextAttributes(0, out _);
AttributedText = new NSMutableAttributedString(Text,
new CTStringAttributes
{
KerningAdjustment = TextLetterSpacing, Font = attributes.Font,
UnderlineStyle = attributes.UnderlineStyle
});
}

MvvmCross binding with NSTableView

After searching multiple blogs and videos I find that to implement the UITableView one can use MvxTableViewController, but what to use for NSTableView?
I do not find any tutorial, example that covers OSX binding TableView using MvvmCross. Any leads will be appreciated.
We don't have MvxTableViewController for macOS.
However, if you abstract from that, binding to a NSTableView is very similar to a UITableView on iOS.
private NSTableView _tableView;
public override void ViewDidLoad()
{
base.ViewDidLoad();
_tableView = new NSTableView();
// add constraints or size otherwise
var source = new MvxTableViewSource(_tableView);
_tableView.Source = source;
var set = this.CreateBindingSet<MyViewController, MyViewModel>();
set.Bind(source).For(v => v.ItemsSource).To(vm => vm.Items);
set.Apply();
}
This will bind the ViewModel Items to the ItemsSource. However, you will still need to specify what to bind in the cell. The simplest way to do this is to provide a TableColumn.
var column = new MvxTableColumn();
column.Identifier = "First";
column.BindingText = "Text Name";
column.HeaderCell = new NSCell("Example");
_tableView.AddColumn(column);
This will bind the Text property of the TableColumn to Name in the items provided in Items in the ViewModel.
If you need more than this you will need to subclass MvxTableViewSource and override GetOrCreateViewFor and in there provide your own subclass of MvxTableCellView where you do more. This could look something as follows.
public class MyCustomCell : MvxTableCellView
{
public MyCustomCell(IntPtr handle) : base(handle)
{
}
public MyCustomCell(string bindingText) : base(bindingText)
{
this.Frame = new CGRect(0, 0, 100, 50);
TextField = new NSTextField(new CGRect(50, 0, 100, 50))
{
Editable = false,
Bordered = false
};
ImageView = new NSImageView(new CGRect(0, 0, 50, 50));
AddSubview(TextField);
AddSubview(ImageView);
this.Initialize(bindingText);
}
private string _imageUrl;
public string ImageUrl
{
get => _imageUrl;
set
{
_imageUrl = value;
ImageService.Instance.LoadUrl(_imageUrl).Into(ImageView);
}
}
}
And the table source:
public class MyTableSource : MvxTableViewSource
{
private string _bindingText;
public MyTableSource(NSTableView tableView, string bindingText) : base(tableView)
{
_bindingText = bindingText;
}
public override NSView GetViewForItem(NSTableView tableView, NSTableColumn tableColumn, nint row)
{
if (ItemsSource == null)
return null;
var item = ItemsSource.ElementAt((int)row);
var view = new MyCustomCell(_bindingText);
if (view is IMvxDataConsumer bindable)
bindable.DataContext = item;
return view;
}
}
Then instead of using MvxTableViewSource in the first example, use your own MyTableSource instead:
var source = new MyTableViewSource(_tableView, "Text Name; ImageUrl Url");
_tableView.Source = source;
Where Name and Url are in the Item in the Items bound to the ItemsSource.

Xamarin forms Bind to ColumnDefinition Width Property

I am trying to bind the widthproperty of a column definition, but can't seem to get the binding to take. Can anyone tell me how to bind to a Xamarin Grid column definition to a property?
Binding property in custom class:
public static readonly BindableProperty PointsColumnsProperty = BindableProperty.Create(nameof(PointsBarColumns), typeof(ColumnDefinitionCollection), typeof(RewardsPanel), new ColumnDefinitionCollection());
This is my property:
public GridLength PointsFill {
get => (GridLength)GetValue(PointsFillProperty);
set => SetValue(PointsFillProperty, value);
}
This is how I am setting the binding:
_pointsBar.ColumnDefinitions[0].SetBinding(ColumnDefinition.WidthProperty, nameof(PointsFill));
I was missing the binding context on the _pointsBar.
_pointsBar = new Grid
{
BackgroundColor = BasicStyle.PrimaryColor,
Style = BasicStyle.PointsAndVisits, BindingContext = this,
ColumnDefinitions =
{
new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) },
new ColumnDefinition { Width = new GridLength(100, GridUnitType.Star) }
}
};

Using Messaging center xamarin forms PCL to set current objects value

I have a scenario where i create Entry Controls programmatically.
foreach (var control in FormInfo.FormElementsInfo)
{
case "textbox":
//Some code
break;
case "dropdown":
Entry objDropdown = new Entry();
objDropdown.HeightRequest = 40;
objDropdown.StyleId = Convert.ToString(control.ElementId);
objDropdown.SetBinding(Entry.TextProperty, "ElementValue",BindingMode.TwoWay);
objDropdown.BindingContext = control;
layout.Children.Add(objDropdown);
MessagingCenter.Subscribe<Picklists, string>(objDropdown, "PicklistSelected", (sender, arg) =>
{
objDropdown.Text = arg;
// I tried this too as this is two way binding. It didn't show the value.
//control.ElementValue = arg;
} );
break;
}
If i click on any entry it will open me a list view. Once i select the option in the list view it will populate that data in the Entry.
But this should show the selected value only in the current entry but it is changing the value in all the entry's.
How to avoid this situation. I want the selected value to be populated only in the current entry.
Any suggestion would be appreciated. Thank you.
=== More clear question=====
If we create n number of Entry controls programmatically with 2 way binding . Is it possible to change the single entry value on selecting something in other page? If yes how to achieve this?
FormInfo
public class FormInfo
{
public List<FormsElementInfo> FormElementsInfo { get; set; }
}
FormsElementInfo
public class FormsElementInfo : INotifyPropertyChanged
{
private string _elementValue;
public string ElementValue {
get => _elementValue;
set {
if(_elementValue != value)
{
_elementValue = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ElementValue"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
Content Page
public class ListStackOverflow : ContentPage
{
private FormInfo _info = new FormInfo
{
FormElementsInfo = new List<FormsElementInfo>()
{
new FormsElementInfo { ElementValue = "test 1"},
new FormsElementInfo { ElementValue = "test 2"},
new FormsElementInfo { ElementValue = "test 3"},
new FormsElementInfo { ElementValue = "test 4"},
}
};
private StackLayout _stack = new StackLayout();
private List<string> _source = new List<string>
{
"output 1","output 2","output 3","output 4",
};
public ListStackOverflow()
{
//BindingContext = _info;
foreach(var c in _info.FormElementsInfo)
{
Entry tempEntry = new Entry
{
HeightRequest = 40,
Placeholder = c.ElementValue,
BindingContext = c
};
tempEntry.SetBinding(Entry.TextProperty, "ElementValue");
_stack.Children.Add(tempEntry);
}
ListView _lv = new ListView { ItemsSource = _source };
_lv.ItemSelected += Lv_ItemSelected;
_stack.Children.Add(_lv);
Content = _stack;
}
private void Lv_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var selectedElement = e.SelectedItem.ToString();
var index = _source.IndexOf(selectedElement);
var entry = _info.FormElementsInfo[index];
entry.ElementValue = selectedElement;
}
}
Output
Selecting the corresponding index in the listview will update "ElementValue" for the same index.
First of all Thank you #Joshua Poling for taking time to help me.
I think MessagingCenter is not suitable for this approach.
I am assigning a unique styleId to each element that i create.That basically stores the position in the stack layout.
I have written a delegate which returns the selected value and also the position of the element. As the element is always an Entry that fires this event. I used the below code to achieve this.
Entry myentry = (Xamarin.Forms.Entry)layout.Children[src.ElementId];

Xamarin Forms - Can't Override Style With TextColor Property

I have a label style defined like:
var myLabelStyle = new Style(typeof(Label))
{
Setters =
{
new Setter { Property = Label.TextColorProperty, Value = Color.Blue },
new Setter { Property = Label.FontSizeProperty, Value = 30 }
}
};
Then I have a label defined like this:
var myLabel = new Label
{
Text = "My Label",
Style = myLabelStyle,
TextColor = Color.Red
};
Shouldn't the color of that label be Red? Well, it's blue.
I should be able to override any given property defined in a Style, according to intuition and Xamarin docs (see the single sentence after the screenshot).
What gives?
It appears to be a Xamarin Forms bug introduced somewhere between Version 2.0.0.6482 (works as expected) and Version 2.2.0.31 (broken! does not work as expected).
I do not see anything wrong with your code:, it is working in this example:
var myLabelStyle = new Style(typeof(Label))
{
Setters =
{
new Setter { Property = Label.TextColorProperty, Value = Color.Blue },
new Setter { Property = Label.FontSizeProperty, Value = 30 }
}
};
var myLabelRed = new Label
{
Text = "My Red Label",
Style = myLabelStyle,
TextColor = Color.Red
};
var myLabelBlue = new Label
{
Text = "My Blue Label",
Style = myLabelStyle,
};
var content = new ContentPage
{
Content = new StackLayout
{
Children = {
myLabelRed,
myLabelBlue
}
}
};
iOS:
Android:

Resources