Bind Click function with parameter - c#

In MVVM Cross for Android in Xamarin Studio,
I can write this in my .axml file to bind a click function to a button:
local:MvxBind="Click SendMessage"
SendMessage is a public method on the MvxViewModel with the signature
public void SendMessage()
{
//do stuff
}
However, I want to do something like like this,
local:MvxBind="Click SendMessage param1: foo, param2: bar"
which should call the method underneath with a signature like this,
public void SendMessage(T foo, T bar)
{
//do stuff
}
where foo and bar might be the current selected item, or the object represented in a particular row of a table etc.
I can't see anywhere that points towards how to do this, and I am hoping that it is a native functionality! Can anyone help?

The binding engine allows you to use either ICommand instances or public void methods. The latter only works if you also install the NuGet package MethodBinding.
As for the amount of parameters supported, it boils down to a single argument, which should correspond to the ViewModel bound to the item in the ListView.

You can use an ICommand instead of a void to execute your code, here you can paas one parameter.
An other option is to bind the parameters you need to objects and access these objects in your code.

Being a bit illiteracy with the exact functionality in xamarin studio, I would like to suggest a general different approach:
How about letting the controls on your View set a class wide property SelectedItem when they're selected, that could then be accessed by the buttons method when it's clicked?

Related

I'm trying to design a solution for a day/night color scheme and got stuck

I'm working on an app that has a "day" and "night" color palette that can change automatically. We're using Xamarin Forms and, for historical reasons, we're not using XAML but I speak XAML so I'm going to use it in this post.
I've approached it by creating a base type with a property for relevant colors like "dark text" or "header background", then implementing that type for both schemes. Then, I made a type that references one of those and raises a PropertyChanged even if it changes. So a day->night transition involves setting the property, then anything in the UI bound to a path like "ColorScheme.DarkText" changes. Nice.
Now I've got a ViewModel that wants to have different colors for some items in a list. I want those colors backed by this day/night change system, but I might have designed myself into a corner. I'll show you what I did and how I want to redesign, but I'm curious if there's a clever way to go about it without causing other problems.
Here's a VM for an item I'm binding to, let's all assume there's nothing unexpected in ViewModelBase:
public class ItemViewModel : ViewModelBase {
public string IconColorName { get...; set...; }
public string IconText { get...; set...; }
}
That ViewModel's contained in another boring ViewModel that makes up the rest of the page:
public class PageViewModel : ViewModelBase {
public ObservableColorScheme ColorScheme { get...; set...; }
public ObservableCollection<ItemViewModel> Items { get...; set...; }
}
OK, so what I'm going for is I'd like XAML for my item's template to look something like:
<StackLayout>
<StackLayout.Children>
<Label TextColor={Binding IconColor, Converter={StaticResource StringToColorConverter} />
...
</StackLayout.Children>
</StackLayout>
Right. OK. So now here's the problem. I can imagine building that IValueConverter and setting it up so it has the same concept of the right color scheme, then using the string value here to get the appropriate property. But I have a problem: there can only be one source for a binding, right? I need the color to change if EITHER the ColorScheme or IconColorName changes. My hunch is WPF could do that, but Xamarin can't?
The most obvious solution I've thought of is some kind of extra ViewModel, in XAML-unfriendly format for brevity:
public class ColorViewModel : ViewModelBase {
public Color Color { get...; set...; }
public ColorViewModel(string colorName, ObservableColorScheme colorScheme) {
colorScheme.PropertyChanged += (s, e) => {
if (e.PropertyName == colorName) {
Color = colorScheme.Get(colorName);
}
}
Color = colorScheme.Get(colorName);
}
}
I do NOT like this. These items are created and destroyed a lot, so that means that event handler needs to be unsubscribed. I don't want to have to think about that, and I can assume a maintenance programmer will forget. I've thought about retooling it to use a WeakReference for the event subscription but... that's getting really icky.
So I'm not really sure how to proceed, short of making the Page here detect color scheme changes and manually update its child views. That feels icky too. I've been thinking about it for a couple of days and nothing nice is presenting itself.
I'm open to "you're doing this terribly wrong, and there's some feature that would make this dramatically easier for you". I'm suspicious that feature is Styles, which I'm not using because 1) the aforementioned lack of using XAML and 2) our project is older than Style support in Xamarin Forms. Feel free to tell me to throw this design away, but please don't do so without showing me a quick example of the better way!
I don’t know xamarin nor C#, so maybe I’ll use the wrong terms, but this is how I would approach this problem:
I assume you have some kind of ViewModel hierarchy and you know the root of this hierarchy.
I would create a ColorScheme class with a static getter of the current color scheme and getters for each color. So you can create a subclass for day and night scheme. Also a void ApplyTo(ViewModelBase). I would create an ViewModelBase interface which has an void UpdateColorScheme() and List Items().
Ok, now, each ViewModel can use the UpdateColorScheme method to setup the view will be created.
Probably there is some kind of event to change the color scheme. This could be a button or a clock based trigger. This event sets the correct ColorScheme and simply calls ColorScheme.CurrentScheme().ApplyTo(rootViewModel). The ApplyTo method walks down the ViewModel hierarchy and calls UpdateColorScheme() for each ViewModel.
This isn’t very fancy but your don’t have to create dozens of objects for something which will change rarely (only twice a day). You only have one instance of ColorScheme and be instance for each Color and a separate method for color settings. But you don’t have to create and register events listeners all the time. The base class will enforce the maintenance programmer to use this concept so he can not forget to setup a event listener and you use the same code for setting up and updating the view.
And a little side note: opinion based questions are not allowed on Stack Overflow. There is a Core Review Page of StackOverflow, I think this question belongs there.

Show context menu for some items in NSOutlineView

I have a SourceList (NSOutlineView) and I want to display a context menu for some of the items. Looking around I have found answers in Cocoa and Obj-C but I am trying to do this in MonoMac and C#.
It seems to me I need to do my own custom class which inherits from NSOutlineView and implement the method MenuForEvent. But when I try to replace my old, standard NSOutlineView with my own custom class, nothing shows up during runtime. In my controller I call View.ReplaceSubviewWith(oldTree, newTree).
Do I need to do something else? Or perhaps there's another way to accomplish this?
Instead of trying to swap the instance like that, you should be able to do it declaratively.
Make sure you 'Register' your custom outline view, e.g.:
[Register("MySourceList")]
private class MySourceList : NSOutlineView
{
// Need this constructor for items created in .xib
public MySourceList(IntPtr handle) : base(handle)
{ }
Then, in the Xcode designer, select your outline view and specify the name you registered as the Custom Class for that object:
That way, when your view is created from the nib, the runtime will create the proper instance of your outline view in the first place.

How do you send data from a form to a class?

I have a Class named Testing and a Form called TitleScreen. In TitleScreen I have a textBox1 who's text I would like to be passed to a Class and then pass it back to my Form into a textBox2.
I know how to do only the basics in C# so if you try and make it simple as possible.
In your Class:
public class Class1
{
public static string SeparateName(string fullName)
{
string[] wordsInText = fullName.Split(' ');
return wordsInText[0];
}
}
In your Form:
private void button1_Click(object sender, System.EventArgs e)
{
textBox2.Text = Class1.SeparateName(textBox1.Text);
}
"I highly recommend that you read a book or tutorial that targets new users, otherwise there will be holes in your understanding of the language and the frameworks."
It sounds like you want to perform an operation on the textbox's value and then print the result in another textbox.
You can write a method (function) that accepts an argument of type String and perform the operation in that method. The method can then set the Text property of the textbox to the result.
If you're asking how to input code in a winforms project, you can double-click the background of the form to reach its code. (At least in Visual Studio)
If you don't know how to do the above suggestions, I highly recommend that you read a book or tutorial that targets new users, otherwise there will be holes in your understanding of the language and the frameworks.
I would suggest you want to look at the concept of data binding, whereby you bind the controls on your forms to the properties of the underlying objects (instances of your classes).
Binding removes the need to write code to cross-load the data from the class into the form and back again, instead you can then say "text box 1 is bound to this property of my class". Then, when you update the value of the textbox the data is automatically placed into the chosen property of your class instance. Typically you then have a save button that calls a save method on your class to persist the data to your data store (database or whatever).
It is perfectly reasonable to bind more than one control on your form to the same property on your underlying class, so in your example you can bind both textBox1 and textBox2 to the same property on your class. Then, once you've implemented databinding, when you change the value in textBox1, the value will automatically be reflected in textBox2, either on each keystroke or when the field is validated (typically when you move focus to another control).
This is the microsoft documentation on Winforms binding which covers everything you need: https://msdn.microsoft.com/en-us/library/ef2xyb33(v=vs.110).aspx

Blindly calling a public method (C#)

OK, weird one. I have many usercontrols with a repeater, the layout of the repeater is the same in all controls, and they all have a bindData() method publically available.
I'm wondering, can I setup another usercontrol for paging without having to specify the parent control?
I'm able to do the following:
((controls.specificuserControlClass)Parent).bindData();
Which is all fine - however I'd need to specify the specificuserControlClass into the pager and then would need it "per repeater" if you see what I mean?
So can I call Parent.bindData() blindly from the child control? I "know" that method exists (or would build checks to make sure), however Visual Studio isn't happy as it doesn't know of the method.
Why not make your controls all implement a specific interface?
public interface IBindData
{
void bindData();
}
Then, you would simply do:
((IBindData)Parent).bindData()
And it should invoke each control's method as appropriate.

Find Focus To Know What To Copy

I have a Copy button in my Ribbon and I need to determine what control is focused so I know which Copy method to invoke. Any ideas on how to do this? I was thinking FocusManager.GetFocusedElement but I am using MVVM so I don't know what to pass as an argument.
private void Copy()
{
if (**Here_I_need_to_know_what_is_focused** is DataGridCell)
{
ApplicationCommands.Copy.Execute(null, this.DisplayedData);
}
else if ((this.CurrentFiles.SelectedItem is DSViewModel) || (this.CurrentFiles.SelectedItem is QViewModel))
{
this.CurrentFiles.Copy(this.CurrentFiles.SelectedItem);
}
else
{
ApplicationCommands.Copy.Execute(null, Keyboard.FocusedElement);
}
}
It really depends where your code is located.
I assume that it is located in the view model - in this case you will not have access to the FocusMangager directly. In order to get the currently focused element, you will have to pass it to the function via the CommandParameter attribute. This can be done by binding if there is only one possible target object.
However, I can imagine that this might be not an option, as the copy button in your ribbon most likely handles several objects. In this case I would not use the Command and CommandParameter attributes, but implement a click handler in the code behind.
Here, you now got the option to determine the focussed element or other target object using all the view's functionality, including the FocusManager. After you have determined the target you now can call you command's Execute method passing the correct object as a parameter.
Before trying to get the focused element you should, however, query the CanExecute method so that you only determine the target object if the command can be executed. If you want to enable/disable the copy button based on the outcome of the CanExecute method, some additional work is required.
Note: This post suggests that there might be some problems using the focus manger with the DataGrid.

Categories