I am using PRISM with xamarin forms, and I like to declare my viewmodels in the XAML,
xmlns:local="clr-namespace:MyProyect.ViewModels"
……
<ContentPage.BindingContext>
<local:RegistroPageViewModel />
</ContentPage.BindingContext>
so I can have XAML intellicense, in this sample my RegistroPageViewModel constructor have one parameter beacause it need for the base class but I don't know how to pass it within the xaml
public class RegistroPageViewModel : ViewModelBase
{
public RegistroPageViewModel(INavigationService navigationService):base(navigationService)
{
registro = new RegistroInfo();
Title = "Perfil de usuario";
}
My specific question is: How can I still using XAML viemodels's declaration if the viewmodel have a parameter ? how can I pass a parameter in the XAML declaration?
thnaks in advance
For XAML to know about ViewModel, enable XamlC and Compiled Bindings. Documentation provides how to enable and use them properly.
XamlC checks for general compile time errors like property names and open-closing matching tags etc...
Compiled Bindings checks for existence of any property that is bound
You can use the view model locator (ViewModelLocator.AutowireViewModel="True") to have the view model created for you with all dependencies automatically injected.
Setting the view model as design data context (d:DataContext={d:DesignInstance local:RegistroPageViewModel}) should give you intellisense.
Related
I have a .NET Blazor Server app and need to pass an object from one component to another. Both components are pages, meaning that they have #page directives with routes. I know how to use cascading values to pass a parameter between regular Blazor components, but this does not work with page components. I also know how to pass a parameter within an endpoint route. However, instead of a string or int I want to pass an object with multiple properties and am unsure how to best accomplish this.
Is it possible to pass an object as an endpoint route parameter? If not, what is a good way to accomplish this within a Razor components context?
Using dependency injection would likely solve this issue for you.
Example:
Create a class called "ApplicationService"
Create an interface in that class called "IApplicationService"
You could have something like this
public interface IApplicationService
{
public Task MsgBox(string value);
}
In the ApplicationService class inside the "ApplicationService.cs" file, go ahead and implement the interface member above.
You could have something like this:
public async Task MsgBox(string value)
{
await _JSRuntime.InvokeAsync<string>("alert", value);
}
In the program.cs class, you need to now register that "service" we just created.
You could have something like this
builder.Services.AddTransient<IApplicationService, ApplicationService>();
builder.Services.AddScoped<ApplicationService>();
In your _Imports.razor you can inject the class so that the pages have access to it:
#inject ApplicationService MainAppService;
Now in your razor components you should be able to do something like this:
await MainAppService.MsgBox("This is a message box");
This works in my WASM blazor app, hope it sheds some light on the server side of things 🚀
Use a DI service. Create a class to hold your object. Add it as a Scoped Service in Program. Use it in any component (pages are just components with a page attribute) though #inject.
I wonder if it is possible in UWP to bind to a converter like this:
{Binding Path=Value, Converter={Binding ElementName=control, Path=Converter, Mode=OneWay}, Mode=TwoWay}"
I need this for a UserControl, on which the consumer can set the Converter property according to his needs. The binding expression above doesn't work for me, but I'm not sure if it is because I've done something wrong or if it is because the framework doesn't support it.
Binding.Converter is regular property not a DependencyProperty thus binding won't work here. Like MSDN says:
A binding target. This is a DependencyProperty of the FrameworkElement in your UI that displays the data.
More information about Data Binding you will find at MSDN.
I have just fired up a WPF project and I want to use Caliburn.Micro.
I have a button
<Button Content="Button" Name="AppendData">
and in my ViewModel I have a method void AppendData(){..}
It doesn't work! There is no binding between the two! But when I do this
<Button Content="Button" cal:Message.Attach="AppendData()">
it suddenly works. What can be the cause of this?
Edit:
I have created a test application where the conventions doesn't work: http://ge.tt/8sNsu201?c
You can make it work, by replacing the controls in MyView with
<Button cal:Message.Attach="SetText()" Content="Button" HorizontalAlignment="Left" Margin="106,153,0,0" VerticalAlignment="Top" Width="75"/>
<Label Content="{Binding Text}" HorizontalAlignment="Left" Margin="124,104,0,0" VerticalAlignment="Top"/>
After taking a look at your source code, I noticed a major mistake which is causing all of this confusion:
public MyView()
{
InitializeComponent();
DataContext = new MyViewModel(); // SOURCE OF TROUBLE
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
In Caliburn.Micro you don't set the DataContext for your view manually like that, instead you let Caliburn.Micro use its conventions to find the appropriate view for your view-model, then it will bind the two together (by setting the view-model as the DataContext of the view), after that it will apply a number of conventions to make everything work correctly.
Explaining why using cal:MessageAttach() would work and directly using AppendData won't work would take a lot of explanation because it seems you don't know the basics of CM.
So I advise you to take a look at the documentation wiki first and go through the first 5 articles at least, then here is a hint that will help you discover why the first method worked and the second didn't:
Message Bubbling
Because this would expand the comments maximum length, I write it as an answer.
As you mentioned in your answer, doing DataContext = new MyViewModel() is a kind of code smell in CM. If you want to hook up it manually in your view, this would be the right way (view first). Check out the CM documentation regarding this one though, because I think there might be missing something:
var viewModel = new MyViewModel();
var view = this;
ViewModelBinder.Bind(viewModel, view, null);
You can accomplish this in the XAML of your view, either. Add the following into the UserControl tag of your view (view first, as well):
xmlns:cal="http://www.caliburnproject.org"
cal:Bind.Model="MyViewModel"
View model first would be done quite the same, in case you are not willing to use the default behavior you described in your answer:
xmlns:cal="http://www.caliburnproject.org"
cal:View.Model="MyViewModel"
I am not sure, but I think you have to add an explicitly named export contract to your view model, if you want to use View.Model or Bind.Model, but it might be it works without as well. Try it out:
[Export("MyViewModel", typeof(MyViewModel))]
public class MyViewModel : Screen
{
// ...
}
Design time views have nothing to do with view first or view model first though!
Design-time view support is accomplished as follows:
xmlns:cal="http://www.caliburnproject.org"
d:DataContext="{d:DesignInstance viewModels:MyViewModel, IsDesignTimeCreatable=True}"
cal:Bind.AtDesignTime="True"
I am currently not able to test all those things, so I hope there are not any mistakes!
is it possible to Access my Project Properties within the .cshtml Razor file?
I need something like this:
#if (myProject.Properties.Settings.Default.foo) {...}
while foo is a boolean
I get the error that because of a security reason it is not possible.
You shouldn't really be calling ConfigurationManager directly from your view. Views should be 'dumb' in MVC, ie not have any knowledge of the data structure or back-end, and by calling ConfigurationManager directly your view knows too much about how your settings are stored. If you changed your settings to use a different store (ie a database) then you'd have to change your view.
So, you should grab that value elsewhere and pass it to your view so your view just takes care of rendering it and that's it. You probably have 2 options:
Add something into the ViewBag and grab it in the view
Render an action from a common controller that passes a strongly typed ViewModel to a partial view.
I'd discourage option 1 because in general it is good to avoid the ViewBag because it isn't strongly typed (Is using ViewBag in MVC bad?). Also, to do this you'd either have to inherit from a BaseController for every controller which can be a pain, or create a global action filter that overrides ActionExecuted and stuffs something in the ViewBag there.
Option 2 is probably better. I'd create a common controller something like:
public class CommonController : Controller
{
[ChildActionOnly]
public ViewResult Settings()
{
// Get some config settings etc here and make a view model
var model = new SettingsModel { Foo = myProject.Properties.Settings.Default.foo };
return View(model);
}
}
Then in your layout file you can call:
#Html.Action("Settings", new { controller = "Common" })
Which renders a strongly-typed partial view (~/Views/Common/Settings.cshtml) which looks like:
#model YourProject.Models.SettingsModel
#if(Model.Foo)
{
// So something
}
That way you are still using a strongly typed model and view, your layout view stays clean and simple and your partial view remains 'dumb'
The app settings are stored in the web.config file as
<applicationSettings>
<YourProject.Properties.Settings>
<setting name="Setting" serializeAs="String">
<value>asdqwe</value>
</setting>
so you can try use ConfigurationManager.AppSettings dictionary like
ConfigurationManager.AppSettings["Setting"]
I'm trying to have all my views inherit from a custom class so that I can add certain behaviour and values to all pages, but I'm having some issues. I tried subclassing System.Web.Mvc.WebViewPage but I'm forced to implement an Execute procedure that I don't know what it should do. Also, if I try to access the Context variable, I get a null reference (really weird). This leads me to think that I may have the wrong base class....
Any thoughts?
Diego, System.Web.Mvc.WebViewPage is the right base type (and you should have another class inheriting from System.Web.Mvc.WebViewPage<TModel> if you want strongly-typed views). You should mark your own class as abstract so that you are not forced to implement the Execute method.
Update: To configure all your views to use your custom base class, look into the ~\Views\Web.config file. Inside of it there's a Razor-specific section where you can use the pageBaseType attribute to configure your custom type.
As far as the Context property is concerned, it should be fully initialized once the view is executing. However, it might not be available if you try to access it too early (for example, from your classes constructor). When are you trying to access it?
The Execute method is something that is provided by the Razor compiler when your view is compiled. For example, given the following view file
Hello #Name!
The Razor compiler will behind the scenes generate the following class (this is a simplification, so the details might be off, but it should convey the point)
public class _Some_Generated_Class_Name_ : System.Web.Mvc.WebViewPage {
public void Execute() {
Write("Hello ");
Write(Name);
Write("!");
}
}
Then the framework calls the Execute method on your view class and your view gets executed.