User Control Button acces to MainWindow.xaml.cs [duplicate] - c#

This question already has answers here:
Changing content dynamically in WPF window from UserControl
(1 answer)
Change MainWindow content from other pages
(2 answers)
Closed last month.
So my question is:
I've 1 Main Window and 1 User Control. I created a Button in the User Control and want to Call a Void Created in MainWindow.xaml.cs
UserControl.xaml
<UserControl x:Class="VIBN_Wizard.MVVM.View.Home"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VIBN_Wizard.MVVM.View"
xmlns:viewModel="clr-namespace:VIBN_Wizard.MVVM.ViewModel"
xmlns:c="clr-namespace:VIBN_Wizard">
<UserControl.DataContext>
<c:MainWindow/>
</UserControl.DataContext>
<Grid>
<StackPanel>
<Button Content="Connect"
FontFamily="/Fonts/#Poppins"
Background="#0096A9"
Foreground="White"
FontSize="18"
Margin="20"
**Click="ConnectApi"**
Width="120"
Height="50" />
</StackPanel>
</Grid>
</UserControl>
MainWindow.xaml.cs
public partial class MainWindow : INotifyPropertyChanged
{
public static LoggerModelSample LoggerModel { get; set; } = new LoggerModelSample();
public CoreApi Api { get; set; }
public MainWindow()
{
// Those references are needed for the correct usage of the API:
// FS.API -> Directory C:\Program Files\fe.screen-sim V4\Core
// FS.Content -> Directory C:\Program Files\fe.screen-sim V4\Core
// FS.SDK -> Directory C:\Program Files\fe.screen-sim V4\Core
// FS.SDK.Network -> Directory C:\Program Files\fe.screen-sim V4\Core
// FS.SDK.WPF -> Directory C:\Program Files\fe.screen-sim V4\Core
// FS.SDK.Mathematics -> Directory C:\Program Files\fe.screen-sim V4\Core
// FS.SDK.Localization -> Directory C:\Program Files\fe.screen-sim V4\Core
Api = new CoreApi();
Api.ApiNetwork.PropertyChanged += ApiNetworkOnPropertyChanged;
InitializeComponent();
public void ApiConnect(object sender, RoutedEventArgs e)
{
if (!IsApiConnected)
{
//Port 4078 is always the same
Api.ApiNetwork.PropertyChanged += ApiNetworkOnPropertyChanged;
Api.Connect(IPAddress, Port, Username, Password);
}
}
}
}
Firstly I had been searching about my problem and can't find \help.

Related

2 identical bindings....One works and the other not [duplicate]

This question already has answers here:
Issue with DependencyProperty binding
(3 answers)
How to correctly bind to a dependency property of a usercontrol in a MVVM framework
(4 answers)
Datacontext conflicts
(1 answer)
Closed 3 years ago.
I have a MainWindow which contains 2 user controls: Ready and Welcome. I want to show either one of them, depending on an enum value in my view model.
When the application starts, only the Welcome should be visible, but both sections are shown. In debug, I see that the ShowWelcome property value is being called, but never the ShowReady, it's like it's not bound.
I don't understand why the Ready user control is still shown, even if the ShowReady property of the viewmodel is set to false.
MainWindow.xaml:
<Window x:Class="xyz.Views.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:xyz.Views"
mc:Ignorable="d"
Title="app" Icon="/Assets/images/wcC.png"
Height="800" Width="240" ResizeMode="NoResize"
Loaded="Window_Loaded">
<StackPanel Orientation="Vertical">
<StackPanel.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
</StackPanel.Resources>
<local:Ready x:Name="ucReady" Visibility="{Binding ShowReady, Converter={StaticResource BoolToVisConverter}}" />
<local:Welcome x:Name="ucWelcome" Visibility="{Binding ShowWelcome, Converter={StaticResource BoolToVisConverter}}" />
</StackPanel>
</Window>
MainWindow.xaml.cs
namespace xyz.Views
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
//ServerApiCaller api;
ConfigModelApp configApp;
MainWindowVM vm;
public MainWindow(IOptionsMonitor<ConfigModelApp> configApp, ServerApiCaller api)
{
this.configApp = configApp.CurrentValue;
vm = new MainWindowVM();
DataContext = vm;
InitializeComponent();
}
void Window_Loaded(object sender, RoutedEventArgs e)
{
vm.UpdateWindowContext(this.configApp.UserId);
}
internal void UpdateWindowContext(ConfigModelApp newConfig)
{
configApp = newConfig;
vm.UpdateWindowContext(newConfig.UserId);
}
}
}
MainWindowVM.cs
namespace xyz.ViewModels
{
public enum MainWindowContextEnum
{
Unknown,
Welcome,
Ready,
Drafting,
Playing,
}
public class MainWindowVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public MainWindowContextEnum MainWindowContext { get; set; } = MainWindowContextEnum.Welcome;
public bool ShowWelcome => MainWindowContext == MainWindowContextEnum.Welcome;
public bool ShowReady => MainWindowContext == MainWindowContextEnum.Ready;
public void UpdateWindowContext(string userId)
{
MainWindowContext = Guid.TryParse(userId, out Guid g) ? MainWindowContextEnum.Ready : MainWindowContextEnum.Welcome;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowReady)));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(ShowWelcome)));
}
}
}
If Visibility="{Binding DataContext.ShowReady, RelativeSource={RelativeSource AncestorType=Window}, Converter={StaticResource BoolToVisConverter}}" works, you are explicitly setting the DataContext of Ready.
You shouldn't do this as it means that the UserControl will no longer inherit its DataContext from the window where the ShowReady property is defined. That's why the binding fails.
A UserControl is generally supposed to inherit its DataContext.

Redirect to another page in WPF on certain conditions

Hi i am making a WPF application.
I have a mainwindow, which i have my navigation in, then i also have a stackpanel, with this:
<Frame x:Name="_mainFrame" NavigationUIVisibility="Hidden"/>
inside, where i place my pages inside.
In My mainwindow i navigate to other pages using the following to for example move to the gameWindow:
private void NavigateGameWindow(object sender, RoutedEventArgs e)
{
_mainFrame.Navigate(new GameWindow());
}
This works fine, but now that i am inside that window (gameWindow), i am checking if a "player" is set, if not, i want to navigate to another page, where i can set certain values.
and then navigate back to GameWindow.
But how do i get a hold of _mainFrame, when it is a part of the mainwindow ?
It says in GameWindow on _mainFrame
The name _mainFrame, does not exist in the current context
Game Window
public partial class GameWindow
{
private int numberOfPlayers;
private Player[] players;
private INavigator _navigator;
public GameWindow(INavigator navigator)
{
_navigator = navigator; //assign navigator so i can navigate _mainframe to other pages.
// initialize game properties, check if they are set.
var gameProp = new GameProperties();
this.numberOfPlayers = 2;
this.players = gameProp.CheckPlayerIsSet(this.players);
//check if a player has been set
if (this.players != null)
{ // Player is set or has been set. proceed or start the game.
InitializeComponent();
}
else
{ // redirect to settings window because players has not been set!
_navigator.Navigate(new GameSettings());
}
}
}
Main Window
public partial class MainWindow : Window, INavigator
{
public MainWindow()
{
InitializeComponent();
}
private void ExitGame(object sender, RoutedEventArgs e)
{
System.Windows.Application.Current.Shutdown();
}
public void Navigate(Page p)
{
_mainFrame.Navigate(p);
}
private void NavigateRulesWindow(object sender, RoutedEventArgs e)
{
Navigate(new GameRulesWindow());
}
private void NavigateGameWindow(object sender, RoutedEventArgs e)
{
Navigate(new GameWindow(this));
}
}
GameSettings
public partial class GameSettings : Page
{
public GameSettings()
{
InitializeComponent();
//var gameProps = new GameProperties();
// set number of players,, should prompt user, and get value!
//gameProps.SetNumberOfPlayers(2);
}
}
View for gamesettings
<Page x:Class="ITD.OOP_Projekt.WPF.Menu.GameSettings"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ITD.OOP_Projekt.WPF.Menu"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="GameSettings">
<Grid Background="white">
<TextBox HorizontalAlignment="Left" Height="23" Margin="229,144,0,0" TextWrapping="Wrap" Text="This is game settings" VerticalAlignment="Top" Width="120"/>
</Grid>
</Page>
One very easy solution is this:
So with the following code you have only one Window (Mainwindow) and inside that Window you display your pages. You can compare it with your internet browser. You have one window and inside that window you can navigate between pages (settings, game, highscore, ...).
I hope this helps and you can get it to work!
If not i can try to upload a simple example to github in the evening.
Just get rid of your GameWindow and implement it as a page.
MainWindow
xaml:
<Window x:Class="PageSwitcher.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PageSwitcher"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Frame x:Name="MainFrame" NavigationUIVisibility="Hidden" />
</Grid>
cs:
public partial class MainWindow : INavigator
{
public MainWindow()
{
InitializeComponent();
Navigate( new Page1(this) );
}
public void Navigate( Page p )
{
MainFrame.Navigate( p );
}
}
Page1
xaml:
<Page x:Class="PageSwitcher.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PageSwitcher"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="Page1">
<Grid Background="Green">
<Button Width="150" Height="30" Click="ButtonBase_OnClick" Content="Go to Page2" />
</Grid>
cs:
public partial class Page1 : Page
{
private INavigator _navigator;
public Page1(INavigator navigator)
{
_navigator = navigator;
InitializeComponent();
}
private void ButtonBase_OnClick( object sender, RoutedEventArgs e )
{
_navigator.Navigate(new Page2(_navigator));
}
}
Page2
xaml:
<Page x:Class="PageSwitcher.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:PageSwitcher"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="Page2">
<Grid Background="Blue">
<Button Width="150" Height="30" Click="ButtonBase_OnClick" Content="Go to Page1"/>
</Grid>
cs:
public partial class Page2 : Page
{
private INavigator _navigator;
public Page2(INavigator navigator)
{
_navigator = navigator;
InitializeComponent();
}
private void ButtonBase_OnClick( object sender, RoutedEventArgs e )
{
_navigator.Navigate(new Page1(_navigator ));
}
}
Thats all you really need.
In this example you can switch between two pages on button click events.
Just start a new wpf project and copy the code.
Play around with it until you understand it and then try to implement it in your game :)
If you want to redirect the page from one page to another you can create one method or function in which you can write the conditions and use the below code for redirection. It will take care of the directory also.
NavigationService.Navigate(new Settings.LatestActiveUsers());

Can I set text-wrapping mode for a long-text mesage to transfer the text to the next line in Prism 6.2. modal dialog?

Sometimes the text of notification message for modal dialog is very long as you can see on the figure below.This is not custom modal dialog but simple notification modal dialog which has a very long text mesage. This is the exception error-message produced by MODBUS protocol library that I use in my application. But SQL Server exceptions can also have such very long text messages about errors. By default, Prism 6.2 modal notification dialod displays a none-wrapped text. As a result of it, the modal dialog is very long and not all of the text of error-message is placed and displayed in the dialog. Below is the XAML markup for this modal dialog:
<prism:InteractionRequestTrigger SourceObject="{Binding NotificationRequest, Mode=OneWay}">
<prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True"/>
</prism:InteractionRequestTrigger>
And below is View Model C#-code for this dialog:
public InteractionRequest<INotification> NotificationRequest { get; private set; }
public String NotificationStatus
{
get { return this._notificationStatus; }
set { SetProperty(ref this._notificationStatus, value); }
}
The folowing line of code is from View Modal constructor:
this.NotificationRequest = new InteractionRequest<INotification>();
And the following is method displaying modal notification dialog:
private void raiseNotification(string message, string caption)
{
this.NotificationRequest.Raise(
new Notification { Content = message, Title = caption },
n => { this.NotificationStatus = "The user was notified."; });
}
Can I set text-wrapping mode for a long-text mesage (in XAML or in View Model) to transfer the text to the next lines in Prism 6.2. modal dialog?
You can show any view that you want inside the PopupWindowAction, just add content to the PopupWindowAction:
<prism:InteractionRequestTrigger SourceObject="{Binding NotificationRequest, Mode=OneWay}">
<prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="True">
<prism:PopupWindowAction.WindowContent>
<views:MyFancyErrorPopup/>
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
Now MyFancyErrorPopup can show your error message as a multi-line textbox or whatever you like...
EDIT:
<UserControl x:Class="ClientModule.Views.MyFancyErrorPopup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Orientation="Vertical">
<TextBlock Text={Binding Message}" TextWrapping="Wrap"/>
<Button Content="Ok" Command="{Binding OkCommand}"/>
</StackPanel>
</UserControl>
class MyFancyErrorPopupViewModel : BindableBase, IInteractionRequestAware
{
public MyFancyErrorPopupViewModel()
{
OkCommand = new DelegateCommand( OnOk );
}
public DelegateCommand OkCommand
{
get;
}
public string Message
{
get { return (_notification?.Content as string) ?? "null"; }
}
#region IInteractionRequestAware
public INotification Notification
{
get { return _notification; }
set
{
SetProperty( ref _notification, value as Notification );
OnPropertyChanged( () => Message );
}
}
public Action FinishInteraction
{
get;
set;
}
#endregion
#region private
private Notification _notification;
private void OnOk()
{
FinishInteraction();
}
#endregion
}

Refer to a xaml element in xaml.cs file in Windows 8.1 project

Hello I am currently learning Windows 8.1 development with Visual Studio 2015.
How can I refer to a xaml element in a .xaml file from the associated .xaml.cs file.
MainPage.xaml file:
<Page
x:Class="project.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:project"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<HubSection Width="600" x:Uid="Section1Header" Header="Map">
<DataTemplate>
<Grid>
<Button x:Name="mapButton" Content="Find my location"/>
</Grid>
</DataTemplate>
</HubSection>
//...
MainPage.xaml.cs file:
namespace project
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
mapButton.Click += mapButton_Click;
}
}
On mapButton I get the error : The name 'mapButton' doesn't exist in the actual context.
I thought x:Name was a way to give a name with wich I can access the xaml element from the .xaml.cs file.
The problem here is that you are trying to access the name of a button from a generated content. mapButton is not in the scope of the Page but in the scope of HubSection. What you really have to do, if you want to access the button element is to use the VisualTreeHelper to get the button at runtime.
Here is an example.
Helper function:
internal static void FindChildren<T>(List<T> results, DependencyObject startNode) where T : DependencyObject
{
int count = VisualTreeHelper.GetChildrenCount(startNode);
for (int i = 0; i < count; i++)
{
DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
if ((current.GetType()).Equals(typeof(T)) || (current.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))
{
T asType = (T)current;
results.Add(asType);
}
FindChildren<T>(results, current);
}
}
Accessing the button:
public MainPage()
{
this.InitializeComponent();
Loaded += (sender, e) =>
{
List<Button> results = new List<Button>();
FindChildren(results, Hub);
var mapButton = results.Find(item => item.Name.Equals("mapButton"));
mapButton.Click += mapButton_Click;
};
}
private void mapButton_Click(object sender, RoutedEventArgs arg)
{
// Do something...
}
Although if you really wanted to map a command to Click, you should consider doing it in the XAML through binding.

make bindings work without running application

<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="260">
<StackPanel>
<TextBox Height="23" x:Name="TextBox" TextWrapping="Wrap" Text="{Binding Test, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Window>
static class Program
{
[STAThread]
static void Main()
{
var win = new MainWindow();
var vm = new ViewModel();
win.DataContext = vm;
vm.Test = "Testing";
//var app = new Application();
//app.Run(win);
var text = win.TextBox.Text;
}
public class ViewModel
{
public string Test { get; set; }
}
If I run the application as is, the value of the variable text will be an empty string. If I uncomment the two lines that run the window as a WPF application, it will be "Testing", which means the TextBox's binding to the property Test on class ViewModel works only if I 'run' the application.
Is there any way to make that binding work without actually running the application?
If you manually set a binding on a DependencyObject (using BindingOperations.SetBinding) with the Source specified, the binding works fine, even if the application is not running.
So in this case, I think the problem is that the Window hasn't been loaded yet, so the visual tree is not ready, so DataContext propagation doesn't work, so the binding doesn't have a source.
It is possible but you have to do this:
var win = new MainWindow();
var vm = new ViewModel(); // Remove this line
win.DataContext = vm; // Remove this line
vm.Test = "Testing"; // Remove this line
In your XAML, change this:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:YourViewModelNameSpace" // Add this, change to correct namespace
Title="MainWindow" Height="350" Width="260">
<Window.DataContext> // Add this tag and contents
<local:ViewModel/> // This instantiates the ViewModel class and assigns it to DataContext
</Window.DataContext>
<StackPanel>
<TextBox Height="23" x:Name="TextBox" TextWrapping="Wrap" Text="{Binding Test, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
And your class:
public class ViewModel
{
public ViewModel() // Add this constructor
{
Test = "Testing";
}
public string Test { get; set; }
}
In the XAML probably you have to remove the explaining comments.
This is how I get it:

Categories