I'm trying to create a Message in my WPF application using Catel. I have a problem, because I'm trying to show this message over additional window (not over mainWindow)
I'm using Catel with Orchestra.MahApps.
When I'm trying to execute code like this:
IMessageService messageService = ServiceLocator.Default.ResolveType<IMessageService>();
messageService.ShowInformation(message, title);
in my Additional Window ViewModel, it shows my message, but over my MainWindow. Is there a way to show it over my second window?
Right now I have a workaround with Events, but with my application growing, it will be hard to maintain everything.
There are a few options:
Create (or override) a custom version of the PleaseWaitService. When showing the busy indicator, check the current foreground window and show that one.
If you really want per/view busy indicator, it might be easier to create boolean values on your vm (IsBusy) and bind to that from within the view.
Related
I'm epxloring different ways to best show dialog windows in my application.
MahApp Metro's IDialogCoordinator seems quite useful, but I couldn't quite adjust it to my use case yet.
Say I'm creating a UserControl (view), whose ViewModel needs to be able to display dialogues.
These dialogues should, when displayed, overlay/span the UserControl only, NOT the entire Window in which the UserControl is hosted.
Is there any way to achieve this?
Default behavior always seems to span over the entire window, and I haven't found any way to change this yet.
So far, I've been using the Dialog coordinator in a very straightforward way, doing the following in my view:
<UserControl
xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
Dialog:DialogParticipation.Register="{Binding}">
and set set the instance in my view's constructor by,
viewModel.Initialize(DialogCoordinator.Instance);
which I'd then call in the viewmodel via
IDialogCoordinator _DialogCoordinator; // set with viewModel.Initialize() called from the view
private async Task _SomeCmdExecute()
{
await _DialogCoordinator.ShowMessageAsync(this, "HEADER", "TEST");
}
Thanks!
Dialogs in MahApps.Metro are always at the window level (see the container PART_MetroActiveDialogContainer in the window's style.)
What you can do is changing the styling of dialogs, so they don't stretch horizontally accross the entire window. See the default template MetroDialogTemplate for reference.
i am working on winform application , one screen of my application i am using a wpf user control . i am setting visiblity of that WPF user control through binding.
there is no threading in my application, i want that as soon as set the visiblility of user control it should effect in UI,but is not happening like that.
i am able to see my WPF user control after the screen is loaded fully.
Hi,
i am working on winform application , one screen of my application i am using a wpf user control . i am setting visiblity of that WPF user control through binding.
there is no threading in my application, i want that as soon as set the visiblility of user control it should effect in UI,but is not happening like that.
i am able to see my WPF user control after the screen is loaded fully.
my code somewhat look like this
void Dosomething()
{
IsUserControlEnabled=true;//here the UI should reflect but not happening
//some time taking code assume 4-8 sec
IsUserControlEnabled=false;
}
What I have tried:
void Dosomething()
{
IsUserControlEnabled=true;//here the UI should reflect but not happening
//some time taking code assume 4-8 sec
// if aim not setting IsUserControlEnabled=false then i am able to see in my UI but i want that in this method only it should appear an disappear
}
i am assuming my problem is releated to below link
my problem is somewhat releated to this link
Make sure the class which you are binding to is implementing INotifyPropertyChanged and that you're raising a PropertyChanged event in the get accessor of your IsUserControlEnabled property. Your UserControl listens for PropertyChanged events to know when to update the control's visual properties, and if it doesn't get them it won't know to update itself.
So I have a main window that shows MDI type interface with multiple document tabs open inside it (just like VS). Both the main window and the document windows have their respective VMs. The CloseDocument command is handled in the document, but needs to tell main window VM about it, so that main window VM could update its Documents collection. What is the proper way of managing this in MVVM? A few ideas that I have:
I could add an event to document VM that is raised just before closing. I could then add its event listener to main window VM for each new document that I add.
I could move the CloseDocument command to main window VM, but ideally the event doesn't belong there.
I could pass reference of the Documents collection to my document VM, so that it updates the collection before closing itself.
Which among these (or if someone has a better one) should be used while following MVVM practices?
I think I would pick solution 1. If you use MVVM Light then you can apply Messenger type to pass the information between Documents.
Each document would have a Command with reference to this method:
private void CloseDocumentExecuteCommand()
{
var message = new DocumentCloseMessage() { Document = this};
Messenger.Default.Send<DocumentCloseMessage>(message);
}
And in the VM of main Window you would have something like this:
(in constructor)
Messenger.Default.Register<CloseMessage>(this, (msgData) => this.CloseMessageReceived(msgData));
... but this could works only if you have Messenger, otherwise you could use events, but then I am afraid you need to use strong references between VMs.
I'm working on an application, and I'm using the MVVM approach.
Basically, there are currently two Pages, and 1 MainWindow.
I switch between the pages using a Frame inside MainWindow.
In the main window, there are 2 buttons which are basically global and should show in all pages; x (exit) and settings.
This is basically my 'shell', as I decided to not use a window border.
The problem is I'd like each page to have a different background and this is where it gets complicated:
- Settings page: Grey background.
- Main Page: Rotating background color that changes according to a property.
The thing is the background is being set in the main window, because it should apply to the global area as well (the top, where the exit and settings buttons are).
I first set the background (in MainWindow) as bound to a property the represents the current page (the value is then being translated into a color hex code with the help of a converter).
All in all, this results in a case where the background changes when a page is changed, but not when the property inside MainPage changes. I can clearly understand why, but I have no idea how to solve it.
The possible solutions I came up with so far:
Somehow causing the binding in MainWindow to update/refresh when the property is changed in MainPage.
Changing the background manually from inside each of the pages. (Although doesn't it negate the idea of mvvm?)
Move the background into each of the pages and set it from there, while making the global buttons on top of the page (which could be a bad thing in case controls end up overlapping).
If so, what would be the best solution to this problem?
If you haven't already, I'd suggest you install some package via NuGet to make MVVM style development more enjoyable. I personally prefer MVVMLight which is... well, light, but it also packs lot's of helpful features.
To communicate between ViewModels, you have (at least) two possible approaches.
1) ViewModelLocator (not recommended)
ViewModelLocator is central place holding references to all of your viewmodels. You could add a property that is then used by all of the viewmodels to get/set the background.
....
x:Name="Main"
DataContext="{Binding Source={StaticResource Locator}, Path=MainVM}">
....
<Grid Background="{Binding Background, Converter={StaticResource StringBrushConverter}}">
...
2) Messenger (recommended)
When ever property changes in your viewmodel(s) or method is executed, you could send a message that your MainViewModel is registered to listen to. Sending a message would be as easy as...
Messenger.Default.Send(new UpdateBackgroundMessage(new SolidColorBrush(Colors.Blue)));
And you'd register for this message in your MainViewModel's constructor:
Messenger.Default.Register<UpdateBackgroundMessage>(this, message =>
{
Background = message.Brush;
});
Actual message class would be:
public class UpdateBackgroundMessage : MessageBase
{
public UpdateBackgroundMessage(Brush brush)
{
Brush = brush;
}
public Brush Brush { get; set; }
}
I know I'm simplifying things here but I hope you got the idea. Both approaches are valid even if you decide not to use MVVMLight.
Edit:
Here's Git repo with example https://github.com/mikkoviitala/cross-viewmodel-communication
I think you should use Application Properties for storing background. There are various benefit of this :
1) Globally available
2) Easy to remember or store user preference
3) Automatically maintain separate profile for each user as it store values in AppData folder of user.
you can use Messenger to notify that background property has changed so that main window or shell could pull out new background value and update it.
I need some help with overlaying views using the prism framework.Its a little more complexed than that so let me explain.I could be over-thinking this as well :D
i have shell (wpf window) and i have 2 views(A & B - both usercontrols) in a module.
when the shell loads it loads view A. On view A i have a button to "popup" view B
for some user input. so naturally i would think to some sort of modal window/control, maybe even a popup. however the problem i face with the popup is that when i move the shell the popup remains fixed and it doesnt block events in view A. I've tried disabling view A to stop events being fired and i've also tried to use a to get the view B move with the shell. Only the canvas works but i now need a way to block it tho'. Is there anyway i can overlay a view on top of another view with prism? or how does everyone else create modal popups with prism & wpf? any advise or pointers would be greatly appreciated.
If you want to use embedded dialogs without an extra window, you can use Prism's RegionManager to achieve the outlined behavior. The trick is to put the PopUp region parallel to your main region in the visual tree:
<Grid>
<ContentControl cal:RegionManager.RegionName="MainRegion" IsEnabled={Binding IsNoPopUpActive} />
<ContentControl cal:RegionManager.RegionName="PopUpRegion"/>
</Grid>
Now use the RegionManager to put view "A" into the "MainRegion". Create a controller class similar to IPopUpDialogController. It should be responsible for putting your view "B" (or any other PopUpView in your application) into the "PopUpRegion" on demand. Addtionally, it should control a flag that signal the underlying "MainRegion" to be enabled or disabled. This way a user won't be able to play with the controls in your view "A" until the pop up is closed.
This can even be done in a modal fashion by using ComponentDispatcher.PushModal() before pushing a frame onto the Dispatcher. However, I would recommend avoid modal dialogs.
Update: As requested in a comment, the IsNoPopUpActive could be implemented in the backing view model. There you could link it to RegionManager's View collection for the popup region:
public bool IsNoPopUpActive
{
get { return _regionManager.Regions["PopUpRegion"].Views.Count() == 0; }
}
Remember to trigger a PropertyChanged event as soon as you modify the views collection (add/remove a popup).
Just for your information: nowadays I avoid disabling the controls in the background and instead insert a transparent panel. This avoids clicking on background controls. However, this does not handle keyboard input (tab-ing to controls). To fix the keyboard input you need to make sure that the keyboard focus is trapped in the popup (MSDN on WPF Focus concepts).
Adding the following focus attributes to the popup region should do the trick:
KeyboardNavigation.DirectionalNavigation="None"
KeyboardNavigation.ControlTabNavigation="None"
KeyboardNavigation.TabNavigation="Cycle"
KeyboardNavigation.TabIndex="-1"
If you are using WPF + MVVM with Prism you can take a look at this Message View overlay controller. The nice part about this approach is you can write unit tests on you view model using a mock overlay controller and have the mock controller return the result that the user would choose in the overlay.
You can find it here: http://presentationlayer.wordpress.com/2011/05/24/wpf-overlay-message-view-controller/
Hope this helps