I Have UserControl called "Footer.xaml" and "Header.xaml" Both User Control are place to different window.
Footer.xaml have two button :-
btnBasic
btnStandard
Header.xaml have one button :-
lobby
When i click on Lobby button from the Header.xaml i want to change the IsEnabled property of the both button [ btnBasic and btnStandard ] on my condition.
I Try the below things [ Footer.xaml.cs ] by default the both button IsEnabled = true
public partial class Footer : UserControl
{
static Footer objFooter = new Footer();
public Footer()
{
InitializeComponent();
objFooter = this;
}
public static Footer GetFooterInstance()
{
return objFooter;
}
}
and on Header.xaml.cs
private void btnLobby_Click(object sender, RoutedEventArgs e)
{
Footer objFooter;
objFooter = Footer.GetFooterInstance();
objFooter.btnBasic.IsEnabled = false;
objFooter.btnStandard.IsEnabled = false;
}
But nothings is effect with button.
You tagged your question for MVVM but posted code is completely violating the rules of MVVM here. You can achieve this by stricting to the rules of MVVM in following manner -
Create a ViewModel class which will serve as DataContext for both of your views.
Create a bool property inside it and bind IsEnabled DP for your buttons namely btnBasic and btnStandard with this property.
Create an ICommand in your ViewModel class which will be invoked on lobby button click and will set this bool property to true or false depending on your situation.
But as you posted in comment above, you already have seperate ViewModels for both Views, you can use Event Aggregator to communicate between two ViewModels.
Related
Background : I have a Window having a tab control with each tab having a separate UserControl. I have followed MVVM for each user control and MEF to obtain the controls to be displayed in the tab at runtime. This is my implementation
interface ITabControl
{
}
[Export(typeof(UserControl1ViewModel))]
class UserControl1ViewModel
{
}
class UserControl1: ITabControl
{
[Import(typeof(UserControl1ViewModel))]
public UserControl1ViewModel ViewModel
{
get { return this.DataContext as UserControl1ViewModel; }
set { this.DataContext = value; }
}
}
//Other user controls have similar implementation
public class WindowViewModel
{
//Import all type of ITabControl and set the TabCollection(bound to ItemSource property of tab control)
}
Problem : Now I have some validations to be done on a particular set of tabs based on the user action in the main window. So I have used another interface called IConfiguration which is implemented by some user control ViewModels.
interface IConfiguration
{
public void Action1();
public void Action2();
------------------- (many more)
}
public class Window
{
//Import all type of IConfiguration and call Action1/Action2 for all these types based on user actions.
}
Now, if an error is encountered during validation (IConfigure actions impelemented in different ViewModels) in any of the above tabs, I need to set the SelectedTabItem property of the tab control to that particular tab. Since these actions are implemeted in the ViewModel, I'm unable to obtain the UserControl to set the SelectedTabItem property. How do I achieve this?
PS: I know I can achieve this by implementing IConfiguration in UserControl view instead of ViewModel this way
public class UserControl1 : IConfiguration
{
public void Action1
{
this.ViewModel.Action1();
}
public void Action2
{
this.ViewModel.Action2();
}
//--------
}
I wonder if there is a better way to achieve this.
Use an overarching viewmodel which contains a collection of ViewModels (one per tab) and a property which represents the active tab.
When you need to swap the active tab you can do it in the viewmodel just by updating the property that represents the active tab. This answer here shows you how to bind the active tab in the TabControl.
I need your help! Following is basically what I have in my main XAML view :
<Button x:Name="button1" Content= "{Binding Customer1, Mode=TwoWay}" Margin="271,52,103,106" Click="button1_Click" />
The code-behind of the main XAML (Code-behind, since it's not a 100% pure MVVM, and a rather hybrid one) goes like this :
public MainWindow()
{
InitializeComponent();
this.DataContext = new MyViewModel();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
DXDialog d = new DXDialog("Information", DialogButtons.OkCancel,true);
d.Content = new PropertyGrid();
d.SizeToContent = System.Windows.SizeToContent.WidthAndHeight;
d.Owner = this;
d.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterOwner;
var result = d.ShowDialog();
if (result == true)
{
}
}
As you can see, I have a Button whose content is bound to a String property in the ViewModel Class. Upon Clicking the button, I'm opening a DXDialog which contains a PropertyGrid with the Properties of the ViewModel class. Let me show you my ViewModel Class below :
public class MyViewModel : ViewModelBase, INotifyPropertyChanged
{
Customer currentCustomer;
protected string _customer1;
public string Customer1 {
get { return this._customer1; }
set { this.SetProperty(ref this._customer1, value, "Customer1"); }
}
public MyViewModel()
{
//Customers = new ObservableCollection<Customer>();
//Customers.Add(new Customer() { Name = "Name1" });
Customer1 = "ABC";
}
}
In the Dialog I'm being able to edit the value of the property but don't yet know how I can save it in a way that it immediately reflects even on the button of the main View {Reflects everywhere it must be bound to, I mean}. I can see the execution coming to the following line in the main code behind
if (result == true)
{
}
But I don't know how to get the edited values and plug them into the right place.
Basically, My requirement is to have multiple controls (Buttons, in this case) bound to multiple instances of a ViewModel class, and then, upon clicking the buttons, I should be able to edit those specific ViewModel instances inside the PropertyGrid of the DXDialogue, and after clicking "Ok", the changes should reflect on the relevant buttons as well.
-Ron
To display ViewModel's properties in the PropertyGrid, assign the ViewModel to its SelectedObject property,and make sure that the ShowProperties option is set to All.
Changes will be reflected in buttons bound to the ViewModel only of you use one and the same ViewModel instance in the main and the dialog windows.
var grid = new PropertyGrid();
grid.SelectedObject = this.DataContext;
grid.ShowProperties = ShowPropertiesMode.All;
d.Content = grid;
I am building a WPF application with the aid of MVVM light and Unity.
I have a ribbon control in the main form, with one tab without tab category, and two tabs in a tab category. User control 3 includes user control 2 and user control 1.
I would like to make visible the Tab Category and tabs 2 and 3 when I click in user control 2 and make them invisible when click in user control 3 or 1.
I confused a little bit with the event handling in mvvm structure.
I would like to do this properly with the MVVM rules. Could you give me an example or some really helpful directions how to do it?
Check how it looks like
Your Ribbon or tabs for that matter, should be backed up by a ViewModel, let's say TabCategoryViewModel or Tab2ViewModel and Tab3ViewModel. Inside these ViewModels you inject the IMessanger service (of course register it before if not already done) and create a POCO event message, like SelectedViewMessage
public class SelectedViewMessage
{
public string ViewName { get; set; }
}
Inside your TabCategoryViewModel you would register to listen to this message
public class TabCategoryViewModel : ViewModelBase
{
public readonly IMessanger messageService;
public TabCategoryViewModel(IMessanger messageService)
{
if(messageService == null)
{
throw ArgumentNullException("messageService");
}
this.messageService = messageService;
this.messageService.Register<GoToPageMessage>(this, OnSelectedViewChanged);
}
protected void OnSelectedViewChanged(SelectedViewMessage message)
{
this.IsVisible = message.ViewName == "UserControl2";
}
private bool isVisible;
public bool IsVisible
{
get { return isVisible; }
set
{
if(isVisible != value)
{
isVisible = value;
RaisePropertyChanged();
}
}
}
}
You inject the same IMessanger service into your ViewModel you use to Bind your UserControl2 and fire the message via
var message = new SelectedViewMessage {
ViewName = "UserControl2";
};
this.messangerService.Send<SelectedViewMessage>(message);
This code can be placed inside a ViewSelectedCommand or something similar, and you can use Blend Interactivity Triggers/Actions to bind this to certain events on the View/UserControl
This can be achieved by adding event onPropertyChange whenever user clicks on the tab and add that property in xaml under Visibility tag. Also look at Handling UI Control to understand that mapping in xaml and ti understand event handling from Here
Hope it helps.
I see example on this link, how to switch between two views. Easiest sollution and perfect for my application - I will also have only two views.
So we have one parent View (MainWindow) and two children Views. Parent View have dedicadet two buttons to swtich between this two Views ("First View" and "Second View") which are located in "DockPanel".
My question is how to use any button in "First View" to switch to the second View and in "Second View" button to come back to the "First View". What I want is get rid of DockPanel and use buttons from View.
Please for advices, how to do that. If any question please ask. THANKS!
You can use an event from each child viewmodel to signal the parent to change views. So in the code below ButtonOnViewModel1Command is pressed on View1 (which is bound to ViewModel1) which raises the SwitchViewModel2Request event. The MainViewModel subscribes to this event and switches the CurrentViewModel collection to ViewModel2. You can do this same thing on ViewModel2 to switch back to ViewModel1.
public class MainViewModel
{
private ViewModel1 _viewModel1 = new ViewModel1();
private ViewModel2 _viewModel2 = new ViewModel2();
public MainViewModel()
{
//event from ViewModel1
_viewModel1.SwitchViewModel2Request += NavigateToView2;
}
//switch View to ViewModel2
private void NavigateToView2(object sender, EventArgs e)
{
CurrentViewModel = _viewModel2;
}
}
public class ViewModel1
{
public ViewModel1()
{
ButtonOnViewModel1Command = new RelayCommand(Button1Method);
}
//some button on child view 1
public RelayCommand ButtonOnViewModel1Command { get; set; }
private void Button1Method(object obj)
{
OnSwitchViewModel2Request();
}
//event that MainViewModel will subscribe to
public event EventHandler SwitchViewModel2Request = delegate { };
private void OnSwitchViewModel2Request()
{
SwitchViewModel2Request(this, EventArgs.Empty);
}
}
Since you're using MVVM light you should look to using the messenger system ( Good tutorial here ). A simple way would be on first view to send a NotificationMessage as follows:
Messenger.Default.Send<NotificationMessage>(new NotificationMessage("GotoSecondView"));
Then in your main window you would register to receive it as follows:
Messenger.Default.Register<NotificationMessage>(this, NotificationReceived);
Followed by a function to handle them:
private void NotificationReceived(NotificationMessage message)
{
string notice = message.Notification;
switch (notice)
{
case "GotoSecondView":
ExecuteSecondViewCommand
break;
}
}
Repeat the same idea for the other view and add it to your switch. Then you can trigger from anywhere and mainview will handle the change without directly having to link your viewmodels.
I have mainPage.xaml and userControl.xaml.I called userControl in mainPage. mainPage has a Grid named "grd" and userControl has a button named "btn". Now when I will click on button then click event of userControl will be raised. In this event, I want to hide the Grid(that in mainPage.xaml). How can I access mainPage controls in userControls ?
For windows Phone 8 try this:
(((Application.Current as App).RootVisual as PhoneApplicationFrame).Content as Page)
You can access currently displayed Page using this code :
var mainPage = (PhoneApplicationPage)((App)Application.Current).RootFrame.Content;
Check out my answer, in that OP wanted to set visibility of appbar, my answer will work for Grid also.
how to programatically open and close bottomappbar using a eventhandler that exist in a usercontrol back code?
If you are using MVVM (as you stated in your comment to #har07's answer) you should not hide the grid in the main page using an event handler in your user control page. Instead you should bind a command to the button in the control page. This command should change the view model of the main page and this change should be notified by that view model to the main page.
In the next example I use MVVM Light but other MVVM libraries probably work almost the same.
Add a property to the view model of your main page:
public class MainViewModel : BaseViewModel
{
…your code here
private bool _isValid;
public bool IsValid
{
get
{
return _isValid;
}
set
{
_isValid = value;
RaisePropertyChange("IsValid");
}
}
}
In the main page bind Visibility to IsValid.
<Grid Visibility="{Binding IsValid, Converter={StaticResource converter}}">
…content here
</Grid>
Now, the grid is visible if IsValid is true.
Add a command to the view model of the user control:
public class UserControlViewModel : BaseViewModel
{
…your code here
public RelayCommand InvalidateGridCommand { get; private set; }
public UserControlViewModel()
{
InvalidateGridCommand = new RelayCommand( () => InvalidateGrid() );
}
private void InvalidateGrid()
{
var mainvm = SimpleIoc.Default.GetInstance(MainViewModel);
mainvm.IsValid = false;
}
}
In the user control page bind the Button to the Command:
<Button Command="{Binding InvalidateGridCommand}">
Invalidate
</Button>
Now, clicking the button will set IsValid on the MainViewModel to false, which will, in turn, hide the Grid.
I came here looking for an answer for this question and after some tries I could access the main page of my Windows Phone 8.1 app using:
var mainPage = (MainPage)(Window.Current.Content as Frame).Content.
To access the controls declared in the MainPage, you need also to give them a x:Name and change their x:FieldModifier to "Internal" or "Public".