XAML ExtendedPicker - invoke code in a ViewModel - visual-studio

Is there a way to change this ExtendedPicker so that it will invoke MyCode() in a ViewModel when a user changes the select data?
<controls:ExtendedPicker
Style="{StaticResource FormEntry}"
x:Name="carTypePicker"
Picker.Title="{i18n:Translate SelectCar}"
ItemsSource="{Binding carTypes}"
DisplayProperty="Name" SelectedItem="{Binding SelectedCarType, Mode=TwoWay}">
</controls:ExtendedPicker>

Can't you just call MyCode() from the setter of the SelectedCarType property?:
private YourType _selectedCarType;
public YourType SelectedCarType
{
get { return _canFilterByOrderId; }
set { _selectedCarType = value; MyCode(); }
}

Related

How to fix the error like Do not contain a definition of "Contains" for adding the search bar in List View

I tried to add a search bar in the ListView but it failed.
after clicking debug the program, it shows the error like "does not contain a defination for "Contains" ... in the part of code behind
I would like to for help for this. Thanks
in the code behind :
public partial class ListPage : ContentPage
{
public ListPage()
{
InitializeComponent();
listView.ItemsSource = LoadData();
private void SearchBar_Pressed(object sender, EventArgs e)
{
var keyword = MainSearchBar.Text;
listView.ItemsSource = LoadData().Where(name => name.Contains(keyword));
}
//in the following codes is about the function LoadData()
which includes the information in the ListView
it is expected that I can search the keyword in the search bear how the error is "Error CS1929: 'Video' does not contain a definition for 'Contains' and the best extension method overload 'Enumerable.Contains(IEnumerable, string)' requires a receiver of type 'IEnumerable' (CS1929) (MVDemo)"
Please help for it. Thanks
Yes, ok, thanks, let me post other parts in this program. For the LoadDate(), The code behind is :
#region "LoadData"
protected IList<Video> LoadData()
{
var videos = new List<Video>();
videos.Add(new Video
{
ID = "27/items/Final_201903/心相契合Final.mp4",
Name = "心相契合",
Writer = "璞園詩歌",
Photo = ImageSource.FromFile("Heart.png")
});
videos.Add(new Video
{
ID = "2/items/20191006_769/明光照耀.mov",
Name = "明光照耀",
Writer = "璞園詩歌",
Photo = ImageSource.FromFile("Light.png")
});
return videos;
}
#endregion
in the xaml:
<StackLayout>
<SearchBar x:Name="MainSearchBar" SearchButtonPressed="SearchBar_Pressed"/>
<ListView IsPullToRefreshEnabled="True" x:Name = "listView" ItemTapped="Handle_ItemTapped" HasUnevenRows="true" SeparatorVisibility="Default">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell Text="{Binding Name}"
Detail="{Binding Writer}"
ImageSource="{Binding Photo}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
I made the page for the class "Video" in file "Models" , the code is:
public class Video
{
public Video()
{
}
public string Name { get; set; }
public ImageSource Photo { get; set; }
public string Writer { get; set; }
public string ID { get; set; }
}
Please help me for it. In fact, I'm new in the Xamarin. Thanks
If you want to filter the Name, please try the code below.
Change:
listView.ItemsSource = LoadData().Where(name => name.Contains(keyword));
To: The Name is what you defined in Video class.
listView.ItemsSource = LoadData().Where(name => name.Name.Contains(keyword));
I make the sample to test, it works well on my side.
Result:
your LINQ query has a syntax error
listView.ItemsSource = LoadData().Where(x => x.name.Contains(keyword));

How to access activity Argument within ActivityDesigner?

I need to get my custom activity's InArgument value at ActivityDesigner.
MyActivity:
[Designer(typeof(ReadTextDesigner))]
public sealed class ReadText : CodeActivity
{
public InArgument<string> ImageName { get; set; }
protected override void Execute(CodeActivityContext context)
{
}
}
My designer:
public partial class ReadTextDesigner
{
public ReadTextDesigner()
{
InitializeComponent();
//this.ModelItem is null here.. WHY is it null?
//How do I get Activity's ImageName here?
}
}
I also have a button as in the image below and when you click on it, I CAN SET my custom Activity's value like this:
private void BtnStart_OnClick(object sender, RoutedEventArgs e)
{
this.ModelItem?.Properties["ImageName"]?.SetValue(new InArgument<string>()
{
Expression = "some value"
});
}
XAML:
<sapv:ExpressionTextBox
Expression="{Binding Path=ModelItem.ImageName, Mode=TwoWay, Converter={StaticResource ArgumentToExpressionConverter}, ConverterParameter=In }"
ExpressionType="s:String"
HintText="Enter a string"
OwnerActivity="{Binding Path=ModelItem}"
Width="110"
Margin="0,5"
Grid.Row="0"
MaxLines="1"
x:Name="TxtImagePath"/>
<Button Grid.Column="0" Grid.Row="1" Content="Get Image" HorizontalAlignment="Center" Click="BtnStart_OnClick" x:Name="BtnStart"/>
How do I GET Activity InArgument ReadTextDesigner constructor?
Its quite weird but I found a workaround. Although this is A solution, I'm hoping for a much better one;
Since within the constructor, I cannot get the ModelItem, I created a new Thread apart from the Main Thread. This new Thread waits 2 milliseconds and then tries to get ModelItem and it succeeds somehow.
Here is the new modified ReadTextDesigner code (Note: I only changed ReadTextDesigner code nothing else)
public ReadTextDesigner()
{
InitializeComponent();
new TaskFactory().StartNew(() => { this.Dispatcher.Invoke(() => SetImage(this)); });
}
private void SetImage(ReadTextDesigner designer)
{
Thread.Sleep(2);
if (designer.ModelItem.GetCurrentValue() is ReadText readText)
{
var imageName = readText.ImageName?.Expression?.Convert<string>();
if (!string.IsNullOrWhiteSpace(imageName))
{
//imageName has a value at this point!
}
}
}
ModelItem is not null anymore and carries the necessary value.
Hope this will help someone or someone post a better solution.
Cheers!

How to send more than one param with DelegateCommnad

I have Button in ListView Cell. On button click I need to perform two actions from ViewModel
Get the current record (to make modification in data)
Get the current Cell/View (to modify text, bg color of button)
However, I am able to perform single action at a time using DelegateCommand by passing Student and object param respectively. See my code below
public StudentAttendanceListPageViewModel()
{
//BtnTextCommand=new DelegateCommand<object>(SetBtnText);
ItemCommand=new DelegateCommand<Student>(BtnClicked);
}
public DelegateCommand<object> BtnTextCommand { get; private set; }
public void SetBtnText(object sender)
{
if (view.Text == "P")
{
view.Text = "A";
view.BackgroundColor= (Color)Application.Current.Resources["lighRedAbsent"];
}
}
public DelegateCommand<Student> ItemCommand { get; }
public void BtnClicked(Student objStudent)
{
objStudent.AbsentReasonId="1001";
objStudent.AttendanceTypeStatusCD = "Absent";
objStudent.AttendanceTypeStatusId = "78001"
}
This is Button code
<Button x:Name="mybtn"
Command="{Binding Source={x:Reference ThePage}, Path=BindingContext.ItemCommand}"
CommandParameter="{Binding .}"
BackgroundColor="{DynamicResource CaribGreenPresent}"
Text="{Binding AttendanceTypeStatusId, Converter={x:StaticResource IDToStringConverter}}">
</Button>
If you see above code I have two methods SetBtnText and BtnClicked. How can I merge these two methods into one by passing Student and object params at a time in DelegateCommand?
You should bind the view's properties to the view model. Then pass the view model as command parameter and change whatever you want to change in the command and data binding will automatically update the view.
Example:
<Button Command="{Binding SomeCommand}"
Text="{Binding Text}">
</Button>
public class StudentViewModel
{
public StudentViewModel( Student student )
{
_text = $"Kick {student.Name}";
SomeCommand = new DelegateCommand( () => {
Text = "I have been kicked"
student.Exmatriculate();
SomeCommand.RaiseCanExecuteChanged();
},
() => student.IsMatriculated
);
}
public DelegateCommand SomeCommand { get; }
public string Text
{
get => _text;
set => SetProperty( ref _text, value );
}
private string _text;
}
As stated in the comments already, it's never ever necessary to pass the view to the view model. To me, it looks as if you don't have a view model in the first place, though, as your code only mentions Student (which most likely is part of the model), while there's no occurence of a StudentViewModel. You know, you do not bind to the model directly unless it's a trivial toy project.

How to save entry text to application.current.properties

Ive saved listviews previously like this so I was hoping I can use the same strategy:
This is my viewmodel where I save all the strings in the class "Notes". Even tho I added the entry binding to the Notes class it doesnt save.:
private void Save()
{
var art = Memory.Favs;
art.Add(Notes);
Memory.Favs = art;
}
This is my memory class:
public static class Memory
{
public static List<Notes> FavoriteNotes
{
get
{
if (Application.Current.Properties.ContainsKey("favoritenotes"))
return JsonConvert.DeserializeObject<List<Notes>>(Application.Current.Properties["favoritenotes"].ToString());
else
return new List<Notes>();
}
set
{
Application.Current.Properties["favoritenotes"] = JsonConvert.SerializeObject(value);
}
}
}
}
Now to the tricky part, I have an entry in xaml where i need to save data in the Save() void.
My xaml:
<Entry Placeholder="{Binding PlaceholderText}" HeightRequest="200" Text="{Binding TextSaveArt, Mode=TwoWay}" />

Trying to code in a VM command but it give me a "Use expression body for properties"

I have this in my XAML:
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding TapGestureForUpdateCategories, Source={x:Reference MainPage}}" CommandParameter="false" />
</Label.GestureRecognizers>
I have this in my ViewModel:
public Command TapGestureForUpdateCategories
{
get
{
return new Command(val => {
App.DB.UpdateAllCategoryGroups(val);
});
}
}
It's giving me an error on the line starting with App.DB. saying "Use expression body for properties"
Can someone give me some idea what I might be doing wrong and how I can fix this?
I don't think it is an error - it should probably be a suggestion or a warning - unless you have 'Treat warnings as errors' set in your project.
You can remove it by using:
public Command TapGestureForUpdateCategories =>
new Command(val => App.DB.UpdateAllCategoryGroups(val));
Or,
public Command TapGestureForUpdateCategories => new Command(val =>
{
App.DB.UpdateAllCategoryGroups(val);
App.DB.UpdateAllCategory(val);
});
Try this:
In your ViewModel:
public class MainPageViewModel : ViewModelBase
{
public ICommand TapGestureForUpdateCategories { get; set; }
public MainPageViewModel()
{
TapGestureForUpdateCategories = new Command(Tap);
}
private void Tap()
{
App.DB.UpdateAllCategoryGroups(val);
}
}
You should create a property for this purpose.

Resources