Does anyone have a clue on how to control IsPresented property from a child view model?
I'm implementing a custom NavBar where I want to simulate the Hamburger icon behavior so my child page on load has
NavigationPage.SetHasNavigationBar(this, false);
which hides the navigation par.
Inside Xaml file I have a button which I want to bind to a PropertyCommand of child viewmodel and show Master page, basically somehow to call Master's IsPresented.
Thanks.
There are a couple of ways to go about it.
The way I would do it would be to use MVVM and use an interface to access the 'presenting the Master page' functionality where its needed.
public interface ICustomMasterDetail
{
void SetMasterPresented(bool isPresented);
}
Now extend on the MasterDetailPage and also implement the above interface
public class CustomMasterDetail : MasterDetailPage, IRootMasterDetail
{
public CustomMasterDetail() : base()
{
//constructor code
}
public void SetMasterPresented(bool isPresented)
{
IsPresented = isPresented;
}
}
Using using an IoC container to register and resolve the interface will let you use its functionality from where ever you want.
The other solution would be to just use a static variable to store the instance of your MasterDetailPage and access that directly to change the IsPresented property
Related
In my code behind I used to render the bitmap from my grid with RenderTargetBitmap.
var renderBitmap = new RenderTargetBitmap();
await renderBitmap.RenderAsync(UIElement);
I want to use the MVVM pattern but now the RenderTargetBitmap class does not work anymore.
Now I'm trying to use the WinRT XAML Toolkit - Composition
var gridBitmap = await WriteableBitmapRenderExtensions.Render(Grid);
but then I get this error: Message "Unable to expand length of this stream beyond its capacity." string
Is there a other way to render this in MVVM? Maybe with SharpDX? Or Iam doing anything wrong?
The problem here is that rendering a UI element into a bitmap is really not a task for view model, as it is very View-specific. In this case then I would see no harm in putting this code in the page's code behind and making it possible to trigger this method from the view-model.
Depending on the MVVM framework you are using, you could trigger the function in different ways. First would be to make the page implement an interface like IRenderGrid with this one method, then add a new method to the view-model that will take IRenderGrid as parameter and store the instance for later use, and then in OnNavigatedTo of the page call this view model method.
interface IRenderGrid
{
Bitmap RenderGrid();
}
class MainViewModel
{
...
private IRenderGrid _renderGrid;
public void RegisterRenderGrid( IRenderGrid renderGrid )
{
_renderGrid = renderGrid;
}
}
class MainPage : Page, IRenderGrid
{
...
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
var viewModel = DataContext as MainViewModel;//get the view model
viewModel.RegisterRenderGrid( this );
}
public Bitmap RenderGrid()
{
var renderBitmap = new RenderTargetBitmap();
await renderBitmap.RenderAsync(Grid);
}
}
Of course the problem is that if your view models reside in a different assembly, you will not have access to Bitmap there, so you will have to wrap it in some custom type.
Alternative approach to triggering the page's method would be to use a messenger, which many MVVM frameworks offer. In such case you would subscribe to a trigger message in the view and react to such message by executing the rendering and then pass the result to the view model either with another message or through a public method.
In a Windows Store split app, I want to pass a view model from a page to a user control. The scenario is that I want to reuse some common xaml in multiple pages, using a UserControl like a view.
In the main page:
<common:LayoutAwarePage
...
DataContext="{Binding ViewModel, RelativeSource={RelativeSource Self}}"
... >
<views:MyUserControlView Model="{Binding ViewModel}" />
...
In the user control code:
public sealed partial class MyUserControlView : UserControl
{
public static readonly DependencyProperty ModelProperty =
DependencyProperty.Register("Model", typeof(MenuSource),
typeof(MyUserControlView), null);
...
public ModelType Model
{
get
{
return this.GetValue(ModelProperty) as ModelType ;
}
set
{
this.SetValue(ModelProperty, value);
}
}
The Model setter is never called. How do I hook up the user control to the parent page's view model?
Or, is there a better way to implement shared views for use in pages?
Thanks.
-John
Correct binding would be:
<views:MyUserControlView Model="{Binding}" />
You've already set DataContext for the page above. All bindings are relative to the current DataContext.
The setter still won't be called, though. It is just a wrapper to access the DependencyProperty from code. Binding will call SetValue directly.
Depending on your requirements you might not even need to define your own Model DependencyProperty. Each control automatically inherits DataContext from its parent control. In your example above the user control already has its DataContext set to the same view model as the page.
I'm trying out Unity and I'm having problems declaring my viewmodel in XAML. Can you help me out?
XAML:
<UserControl.DataContext>
<search:SearchBoxViewModel />
</UserControl.DataContext>
Constructor:
[ImportingConstructor]
public SearchBoxViewModel(IRegionManager regionManager, IEventAggregator eventAggregator)
{
this.regionManager = regionManager;
this.eventAggregator = eventAggregator;
}
When I try to execute I get a resolutionfailedexception.
This worked when the viewmodel had an empty constructor. It seems as if it's having problems with the constructor injection.
If I load the module like this:
var searchView = Container.Resolve<SearchBoxView>();
searchView.DataContext = Container.Resolve<SearchBoxViewModel>();
//RegionManager.RegisterViewWithRegion(RegionNames.SearchRegion, typeof(SearchBoxView));
RegionManager.Regions[RegionNames.SearchRegion].Add(searchView);
It works.
Is there any possibility to do this with xaml ( with I personally think is better )?
By the way: I'm creating an application with wpf that primarily communicates with a webservice. What should I rather user: unity or MEF and what are the big differences between the two?
Thanks,
Raphi
http://msdn.microsoft.com/en-us/library/ms753379.aspx:
Requirements for a Custom Class as a XAML Element
In order to be able to be instantiated as an object element, your
class must meet the following requirements:
Your custom class must be public and support a default
(parameterless)
public constructor. (See following section for notes regarding
structures.)
...
So, if you want to use dependencies, you should right something like:
var searchView = Container.Resolve<SearchBoxView>();
public class SearchBoxView: UserControl
{
[Dependency]
public SearchBoxViewModel ViewModel
{
get { return (SearchBoxViewModel)DataContext; }
set { DataContext = value; }
}
I am developing a Windows Phone 7 app and am using the MVVM pattern. I have a need to pass a parameter to the contructor of the ViewModel for a page. All my datacontexts and binding are done in XAML. Through my research I've seen that I need to do so using a dependency injector such as NInject.
Here's a little detail on whats going on:
I have a page with a ListPicker that lists various tasks. Each task has a unique TaskID. When an item is selected I need to open another page that will show the selected Tasks detail. My ViewModel and binding is all done and works if I use a static TaskID in the ViewModel but of course I need to use a variable.
I've setup NInject in the project and the various classes needed such as ViewModelLocator and my NInjectModule as shown here:
public class LighthouseNInjectModule : NinjectModule
{
public override void Load()
{
this.Bind<TaskViewModel>().ToSelf().WithConstructorArgument("TaskID", 2690);
}
}
Note that I have hardcoded a TaskID here and using this code this value properly gets injected into my constructor. Of course, this is hardcoded and I need to get the TaskID for the selected ListPicker item. I know how to get the selected ID from the ListPicker but how do I make NInject aware of it so when my class constructor is run it will have the correct value?
Here is the basic definition of my ViewModel class showing use of the Injector attribute.
public class TaskViewModel : INotifyPropertyChanged
{
[Inject]
public TaskViewModel(int TaskID)
{
//run function to get data using TaskID
}
}
WithConstructorArgument has another oveload that accepts a lazy evaluated Func<Context, object>.
I am created a MainView that it's DataContext is a MainViewModel initialized in xaml.
The MainView contains a ContentControl that is bound to the Content property of the MainViewModel.
I added some content in the MainViewModel constructor, so that if the current user is not logged in, it automatucally loads LoginView (and correspondingly it's DataContext LoginViewModel) into this Content property.
Now my question is, what should I do when the user successfully logs in:
'To be called from the LoginCommand
Private Sub Login
'Do Login
If WebContext.Current.User.IsAuthenticated Then
' - Publish a global event to be subscribed and caught from the MainViewModel
' - Close LoginView
' - The MainViewModel should set it's Content property back
' to what the user initially intended to open
End If
End Sub
How is this done?
Note: I prefer using prism's EventAggregator rathen then other stuff, but I have no clue:
How to spread it out between the ViewModels
How to create events (I don't need to pass parameter, nor do I need it to be generic, just Action, LoginAction - no parameters.
How do I subscribe from the MainViewMode.
I do NOT use MEF or Unity, nor do I use seperated modules, all my application is in one single assembly.
I prefer not to write any code in the code-behind at all
Answer in both VB.NET or C# are welcommed the same
Any help would be recommended
You can go here for info regarding the EventAggregator.
You could also use the following code to create an instance of the EventAggregator without using MEF or Unity:
internal static class EventAggregatorHelper
{
private static IEventAggregator _Current = new EventAggregator();
public static IEventAggregator Current
{
get
{
return _Current;
}
}
}
And you could then call the EventAggregator like so passing in the required information to the aggregator:
EventAggregatorHelper.Current.GetEvent<SelectedItemChangedEvent>().
Subscribe(HandleSelectedItemChangedEvent);
In this case the SelectedItemChangedEvent and the subscriber that deals with this event.
The SelectedItemChangedEvent is a class declared as shown below:
public class SelectedItemChangedEvent : CompositePresentationEvent<String>
{
}
and the subscriber would be something like this:
internal void HandleSelectedItemChangedEvent(string viewName)
{
if (!String.IsNullOrEmpty(viewName))
{
//Do whatever you need to do here.
}
}
The link to the Event Aggregator I posted at the start should clear most things up for you.
Hope this helps.