I have a form in Xamarin with two <Entry> (entry controls) one of them, when doing Tap it opens a modal window that contains a list and the other has a normal operation, everything works well until the user opens the normal Entry keyboard first and then call the modal, when this happens the keyboard is up and the list is shown blocking the view of the user as follows...
I would like to change this behavior, so I attach the XAML code of the view
MyView.XAML:
<Entry
Placeholder="Nombre Sustancia Química"
Margin="15,5,15,5"
HorizontalOptions="FillAndExpand"
Text="{Binding NombreSustancia, Mode=TwoWay}"
IsEnabled="{Binding EntryEnabled}">
</Entry>
<Entry
x:Name="Make"
Placeholder="Seleccione Fabricante"
Margin="15,5,15,5"
Focused="Entry_Focused"
HorizontalOptions="FillAndExpand"
Text="{Binding NombreFabricante, Mode=TwoWay}"
IsEnabled="{Binding EntryEnabled}">
</Entry>
MyView.XAML.CS:
public partial class FiltrosSisquimView : ContentPage
{
public ObservableCollection<Fabricante> Fabricantes { get; set; }
public FiltrosSisquimView ()
{
InitializeComponent();
}
private async void Entry_Focused(object sender, FocusEventArgs e)
{
//prevents the keyboard from opening when calling the modal
Make.Unfocus();
var mainViewModel = MainViewModel.GetInstance();
Fabricantes = mainViewModel.Filtros.Fabricantes;
mainViewModel.FabricantesModal = new FabricantesModalViewModel(Fabricantes);
await Application.Current.MainPage.Navigation.PushModalAsync(new FabricantesModalView());
}
}
I must say, that this problem only happens in iOS, and that Android has the expected behavior (when opening the modal the keyboard is automatically lowered), how could the keyboard go down when the user has already opened the list? Where should I control this event? on the modal page? in the codebehind? I am occupying MVVM as architectural pattern
any help for me?
It seems a native iOS design issue.I use the similar code on Xcode and get the same issue.So you can use the custom renderer and to solve it.
in Forms
using System;
using Xamarin.Forms;
namespace app1
{
public class MyEntry:Entry
{
public MyEntry()
{
}
}
}
in xaml
<Entry
Placeholder="Nombre Sustancia Química"
Margin="15,5,15,5"
HorizontalOptions="FillAndExpand"
>
</Entry>
<local:MyEntry
x:Name="Make"
Placeholder="Seleccione Fabricante"
Margin="15,5,15,5"
Focused="Entry_Focused"
HorizontalOptions="FillAndExpand"
>
</local:MyEntry>
in iOS project
using System;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
using app1;
using app1.iOS;
using UIKit;
using Foundation;
[assembly: ExportRenderer(typeof(MyEntry), typeof(MyEntryRenderer))]
namespace app1.iOS
{
public class MyEntryRenderer:EntryRenderer,IUITextFieldDelegate
{
public MyEntryRenderer()
{
}
protected override void OnElementChanged(ElementChangedEventArgs<Entry> e)
{
base.OnElementChanged(e);
if(Control!=null)
{
Control.WeakDelegate = this;
}
}
[Export("textFieldShouldBeginEditing:")]
public bool ShouldBeginEditing(UITextField textField)
{
MessagingCenter.Send<Object>(this, "finish");
return false;
}
}
}
Now ,subscribe the message in your contentPage.
public partial class FiltrosSisquimView : ContentPage
{
public ObservableCollection<Fabricante> Fabricantes { get; set; }
public FiltrosSisquimView ()
{
InitializeComponent();
MessagingCenter.Subscribe<Object>(this, "finish", (obj) => {
var mainViewModel = MainViewModel.GetInstance();
Fabricantes = mainViewModel.Filtros.Fabricantes;
mainViewModel.FabricantesModal = new FabricantesModalViewModel(Fabricantes);
await Application.Current.MainPage.Navigation.PushModalAsync(new FabricantesModalView());
});
}
private async void Entry_Focused(object sender, FocusEventArgs e)
{
//prevents the keyboard from opening when calling the modal
Make.Unfocus();
var mainViewModel = MainViewModel.GetInstance();
Fabricantes = mainViewModel.Filtros.Fabricantes;
mainViewModel.FabricantesModal = new FabricantesModalViewModel(Fabricantes);
await Application.Current.MainPage.Navigation.PushModalAsync(new FabricantesModalView());
}
}
Related
when I try to display in a webView one of my web page in Landscape mode ( https://web-labosims.org/animations/App_refraction_reflexion/App_refraction&reflexion.html ) it works correctly on Android.
Screenshots
But when it's not the first page and I change orientation between pages it doesn't work properly anymore on Android (display problem) ...
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
private List<Anim> lesAnimations;
public MainPage()
{
InitializeComponent();
String animsJson = "[{\"Nom\":\"Réfraction et réfexion\",\"url\":\"https://web-labosims.org/animations/App_refraction_reflexion/App_refraction&reflexion.html\",\"imageUrl\":\"App_refraction.png\"},{\"Nom\":\"Synthèse soustractive\",\"url\":\"https://web-labosims.org/animations/App_lumiere3/App_lumiere3.html\",\"imageUrl\":\"App_soustractive.png\"}]";
lesAnimations = JsonConvert.DeserializeObject<List<Anim>>(animsJson);
maListView.ItemsSource = lesAnimations;
maListView.ItemSelected += (sender, e) =>
{
if (maListView.SelectedItem != null)
{
Anim item = maListView.SelectedItem as Anim;
GoAnimation(item.url);
}
maListView.SelectedItem = null;
};
}
private async Task GoAnimation(String url)
{
await this.Navigation.PushAsync(new Animation(url));
}
protected override void OnAppearing()
{
base.OnAppearing();
DependencyService.Get<IOrientationHandler>().ForcePortrait();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
DependencyService.Get<IOrientationHandler>().ForceLandscape();
}
}
Animation.xaml
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:LaboSims;assembly=LaboSims"
x:Class="LaboSims.Animation">
<ContentPage.Content>
<WebView x:Name="maWebView"
WidthRequest="1000"
HeightRequest="1000"
/>
</ContentPage.Content>
</ContentPage>
Animation.xaml.cs
public partial class Animation : ContentPage
{
public Animation(String url)
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
maWebView.Source = url;
}
}
IOrientationHandler.cs
namespace LaboSims
{
public interface IOrientationHandler
{
void ForceLandscape();
void ForcePortrait();
}
}
And on Android
using Android.Content.PM;
using LaboSims.Droid;
using Plugin.CurrentActivity;
[assembly: Xamarin.Forms.Dependency(typeof(OrientationHandler))]
namespace LaboSims.Droid
{
public class OrientationHandler : IOrientationHandler
{
public void ForceLandscape()
{
CrossCurrentActivity.Current.Activity.RequestedOrientation = ScreenOrientation.Landscape;
}
public void ForcePortrait()
{
CrossCurrentActivity.Current.Activity.RequestedOrientation = ScreenOrientation.Portrait;
}
}
}
Screenshots
I don't understand where I make an error...
I was sure that the problem should be simple and indeed it is a simple mistake ... I had made a small mistake in my meta tag on my web page.
I changed it to :
<meta name="viewport" content="user-scalable=no, width=device-width, initial-scale=1, maximum-scale=1">
And everything is working properly
I have an already build Xamarin App but now I want to add the Sign Up / Login Page at the Start. When I open the App, first It open a Sign up Page.
I add a Blank Page with Title "Welcome to App" and Add a Button, but the Button doesn't work and only It works when it uses the Navigation of Other Pages, why? and how to add a sign up form on blank page?
IMAGE: It now looks like this.
I want to remove these Credentials, Accounts e.t.c from the top and just have an blank page of Sign Up.
Here is the Code, I hope it helps you to understand it better. If you need anything else, kindly ask for it.
Thanks :)
UPDATE: #Jason Comment : I removed Login Code from MainPage.xml, now the Navigation Tabs are no longer there but now the Button isn't working (when I click on it, nothing happens).
LoginPage.xml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:converters="clr-namespace:Osma.Mobile.App.Converters;assembly=Osma.Mobile.App"
xmlns:behaviours="clr-namespace:Osma.Mobile.App.Behaviors;assembly=Osma.Mobile.App"
xmlns:components="clr-namespace:Osma.Mobile.App.Views.Components;assembly=Osma.Mobile.App"
x:Class="Osma.Mobile.App.Views.Login.LoginPage"
Title="Login"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
ios:Page.LargeTitleDisplay="Always"
>
<ContentPage.Content>
<StackLayout>
<Label Text="Welcome to App"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
<Button Text="Enter"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
Command="{Binding ButtonClickedCommand}"
/>
</StackLayout>
</ContentPage.Content>
</ContentPage>
LoginPage.xml.cs
using System;
using System.Collections.Generic;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Osma.Mobile.App.Views.Login
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class LoginPage : ContentPage
{
public LoginPage()
{
InitializeComponent();
}
}
}
LoginViewMode.cs
using System;
using System.Reactive.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using System.Threading.Tasks;
using Acr.UserDialogs;
using Hyperledger.Aries.Contracts;
using Hyperledger.Aries.Features.DidExchange;
using Hyperledger.Aries.Utils;
using Osma.Mobile.App.Events;
using Osma.Mobile.App.Extensions;
using Osma.Mobile.App.Services;
using Osma.Mobile.App.Services.Interfaces;
using ReactiveUI;
using Xamarin.Forms;
using Xamarin.Essentials;
using Osma.Mobile.App.ViewModels.Credentials;
namespace Osma.Mobile.App.ViewModels.Login
{
public class LoginViewModel : ABaseViewModel
{
private readonly ICustomAgentContextProvider _agentContextProvider;
private readonly IConnectionService _connectionService;
public LoginViewModel(
IUserDialogs userDialogs,
INavigationService navigationService,
ICustomAgentContextProvider agentContextProvider,
IConnectionService defaultConnectionService) :
base("Login", userDialogs, navigationService)
{
_agentContextProvider = agentContextProvider;
_connectionService = defaultConnectionService;
}
public ICommand ButtonClickedCommand => new Command(async () => await NavigationService.NavigateToAsync<CredentialsViewModel>());
}
}
App.xaml.css
using System.Threading.Tasks;
using Autofac;
using Microsoft.AppCenter;
using Microsoft.AppCenter.Analytics;
using Microsoft.AppCenter.Crashes;
using Osma.Mobile.App.Services.Interfaces;
using Osma.Mobile.App.Utilities;
using Osma.Mobile.App.ViewModels;
using Osma.Mobile.App.ViewModels.Login;
using Osma.Mobile.App.ViewModels.Account;
using Osma.Mobile.App.ViewModels.Connections;
using Osma.Mobile.App.ViewModels.CreateInvitation;
using Osma.Mobile.App.ViewModels.Credentials;
using Osma.Mobile.App.Views;
using Osma.Mobile.App.Views.Login;
using Osma.Mobile.App.Views.Account;
using Osma.Mobile.App.Views.Connections;
using Osma.Mobile.App.Views.CreateInvitation;
using Osma.Mobile.App.Views.Credentials;
using Xamarin.Forms;
using Xamarin.Forms.Internals;
using Xamarin.Forms.Xaml;
using LoginPage = Osma.Mobile.App.Views.Login.LoginPage;
[assembly: XamlCompilation(XamlCompilationOptions.Compile)]
namespace Osma.Mobile.App
{
public partial class App : Application
{
public new static App Current => Application.Current as App;
public Palette Colors;
private readonly INavigationService _navigationService;
private readonly ICustomAgentContextProvider _contextProvider;
public App(IContainer container)
{
InitializeComponent();
MainPage = new LoginPage();
Colors.Init();
_navigationService = container.Resolve<INavigationService>();
_contextProvider = container.Resolve<ICustomAgentContextProvider>();
InitializeTask = Initialize();
}
Task InitializeTask;
private async Task Initialize()
{
//Pages
_navigationService.AddPageViewModelBinding<MainViewModel, MainPage>();
_navigationService.AddPageViewModelBinding<LoginViewModel, LoginPage>();
_navigationService.AddPageViewModelBinding<ConnectionsViewModel, ConnectionsPage>();
_navigationService.AddPageViewModelBinding<ConnectionViewModel, ConnectionPage>();
_navigationService.AddPageViewModelBinding<RegisterViewModel, RegisterPage>();
_navigationService.AddPageViewModelBinding<AcceptInviteViewModel, AcceptInvitePage>();
_navigationService.AddPageViewModelBinding<CredentialsViewModel, CredentialsPage>();
_navigationService.AddPageViewModelBinding<CredentialViewModel, CredentialPage>();
_navigationService.AddPageViewModelBinding<AccountViewModel, AccountPage>();
_navigationService.AddPageViewModelBinding<CreateInvitationViewModel, CreateInvitationPage>();
if (_contextProvider.AgentExists())
{
await _navigationService.NavigateToAsync<LoginViewModel>();
}
else
{
await _navigationService.NavigateToAsync<LoginViewModel>();
}
}
protected override void OnStart()
{
#if !DEBUG
AppCenter.Start("ios=" + AppConstant.IosAnalyticsKey + ";" +
"android=" + AppConstant.AndroidAnalyticsKey + ";",
typeof(Analytics), typeof(Crashes));
#endif
}
protected override void OnSleep()
{
// Handle when your app sleeps
}
protected override void OnResume()
{
// Handle when your app resumes
}
}
}
MainPage.xml
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:connections="clr-namespace:Osma.Mobile.App.Views.Connections;assembly=Osma.Mobile.App"
xmlns:credentials="clr-namespace:Osma.Mobile.App.Views.Credentials;assembly=Osma.Mobile.App"
xmlns:account="clr-namespace:Osma.Mobile.App.Views.Account;assembly=Osma.Mobile.App"
xmlns:ios="clr-namespace:Xamarin.Forms.PlatformConfiguration.iOSSpecific;assembly=Xamarin.Forms.Core"
x:Class="Osma.Mobile.App.Views.MainPage"
CurrentPageChanged="CurrentPageChanged"
Appearing="Appearing"
>
<connections:ConnectionsPage
Icon="connection_icon.png"
ios:NavigationPage.PrefersLargeTitles="true"
BindingContext="{Binding Connections}">
</connections:ConnectionsPage>
<credentials:CredentialsPage
Icon="credentials_icon.png"
ios:NavigationPage.PrefersLargeTitles="true"
BindingContext="{Binding Credentials}">
</credentials:CredentialsPage>
<account:AccountPage
Icon="account_icon.png"
ios:NavigationPage.PrefersLargeTitles="true"
BindingContext="{Binding Account}">
</account:AccountPage>
</TabbedPage>
MainViewModel.cs
using System.Threading.Tasks;
using Acr.UserDialogs;
using Osma.Mobile.App.Services.Interfaces;
using Osma.Mobile.App.ViewModels.Login;
using Osma.Mobile.App.ViewModels.Account;
using Osma.Mobile.App.ViewModels.Connections;
using Osma.Mobile.App.ViewModels.CreateInvitation;
using Osma.Mobile.App.ViewModels.Credentials;
using ReactiveUI;
namespace Osma.Mobile.App.ViewModels
{
public class MainViewModel : ABaseViewModel
{
public MainViewModel(
IUserDialogs userDialogs,
INavigationService navigationService,
LoginViewModel loginViewModel,
ConnectionsViewModel connectionsViewModel,
CredentialsViewModel credentialsViewModel,
AccountViewModel accountViewModel,
CreateInvitationViewModel createInvitationViewModel)
: base(
nameof(MainViewModel),
userDialogs,
navigationService
)
{
Login = loginViewModel;
Connections = connectionsViewModel;
Credentials = credentialsViewModel;
Account = accountViewModel;
CreateInvitation = createInvitationViewModel;
}
public override async Task InitializeAsync(object navigationData)
{
await Login.InitializeAsync(null);
await Connections.InitializeAsync(null);
await Credentials.InitializeAsync(null);
await Account.InitializeAsync(null);
await CreateInvitation.InitializeAsync(null);
await base.InitializeAsync(navigationData);
}
#region Bindable Properties
private LoginViewModel _login;
public LoginViewModel Login
{
get => _login;
set => this.RaiseAndSetIfChanged(ref _login, value);
}
private ConnectionsViewModel _connections;
public ConnectionsViewModel Connections
{
get => _connections;
set => this.RaiseAndSetIfChanged(ref _connections, value);
}
private CredentialsViewModel _credentials;
public CredentialsViewModel Credentials
{
get => _credentials;
set => this.RaiseAndSetIfChanged(ref _credentials, value);
}
private AccountViewModel _account;
public AccountViewModel Account
{
get => _account;
set => this.RaiseAndSetIfChanged(ref _account, value);
}
private CreateInvitationViewModel _createInvitation;
public CreateInvitationViewModel CreateInvitation
{
get => _createInvitation;
set => this.RaiseAndSetIfChanged(ref _createInvitation, value);
}
#endregion
}
}
I do not see that you have a NavigationPage instance anywhere, so how does your NavigationService works?
NavigationService usually inserts a page to a stack of pages on a NaviagtionPage instance.
I see in App.xaml.cs you make the LoginPage your main page, but where do you switch it to a NavigationPage, or to your TabbedPage?
You need to check what your MainPage should really be.
I have the following problem:
in the application, when the user returns to the computer, I have to process the event and show him a modal window in which to offer 3 possible answers.
I do this using the service:
public WinUserReturnDialogServiceImpl(ISettingsManager
settingsManager) : base(settingsManager)
{
_dialogPage = new UserReturnDialogPage();
_dialogPage.AddButton.Click += OnAddButtonClick;
_dialogPage.DivideButton.Click += OnDivideButtonClick;
_dialogPage.CancelButton.Click += OnCancelButtonClick;
_dialogWindow = new DialogWindow()
{
Content = _dialogPage
};
}
protected override void ShowCustomDialog(UserReturnDialogData dialogData)
{
_pauseDuration = Math.Floor(dialogData._userAfkMinuites);
Application.Current.Dispatcher.Invoke(() =>
{
_dialogPage.AFKMessage.Text = string.Format("Вы отсутствовали {0} мин", _pauseDuration);
_dialogWindow.Show();
});
return;
}
private void OnAddButtonClick(object sender, RoutedEventArgs e)
{
CloseCustomDialog();
}
Page Code behind:
//[MvxViewFor(typeof(UserReturnDialogViewModel))]
//[WinContentPresentation(IsSheet = true, TransitionForwardType = TransitionType.ToRight, TransitionReturnType = TransitionType.FromRigth, WindowIdentifier = nameof(DialogWindow))]
[MvxContentPresentation(WindowIdentifier = nameof(DialogWindow), StackNavigation = false)]
public partial class UserReturnDialogPage : MvxWpfView<UserReturnDialogViewModel>
{
public UserReturnDialogPage()
{
InitializeComponent();
}
and page xaml:
<views:MvxWpfView
x:Class="SmlHours.Win.Presentation.Views.Pages.Dialogs.UserReturnDialogPage"
x:TypeArguments="vm:UserReturnDialogViewModel"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:MvvmCross.Platforms.Wpf.Views;assembly=MvvmCross.Platforms.Wpf"
xmlns:vm="clr-namespace:SmlHours.Core.Presentation.ViewModels.Dialogs;assembly=SmlHours.Core"
...
<Button
x:Name="AddButton"
HorizontalAlignment="Left"
Visibility="Visible"
Width="85"
Height="32"
Template="{DynamicResource BaseNavigationButtonTemplate}"
Command="{Binding AddTimeAfterUserReturn}"
ViewModel:
public class UserReturnDialogViewModel : BaseViewModel
{
private IMonitoringInteractor _monitoringInteractor;
public IMvxCommand AddTimeAfterUserReturn { get; private set; }
public UserReturnDialogViewModel(IMonitoringInteractor monitoringInteractor)
{
_monitoringInteractor = monitoringInteractor;
AddTimeAfterUserReturn = CreateAsyncCommand(AddTimeAfterReturnTask);
}
//I need to fire this command after button pressed!!!
private Task AddTimeAfterReturnTask() => Task.Run(async () =>
{
var model = _monitoringInteractor.FixationTimeAfterUserReturn();
});
}
The event is triggered, the page is displayed, but the viewmodel is not attached to the page and does not respond to button presses. However, the OnAddButtonClick, etc. service commands that close the window react to pressing the buttons.
How do I bind view and viewmodel, so that pressing the buttons works in the viewmodel?
Thanks a lot to those who responded
Problem was that I try to create new Window/Page by manual. For binding vm and view should use ViewDispatcher:
var ViewDispatcher = Mvx.Resolve<IMvxViewDispatcher>();
ViewDispatcher.ShowViewModel(newMvxViewModelRequest(typeof(UserReturnDialogViewModel)));
I'm working on a C# WPF project in Visual Studio in which I allow the user to add a user control (with two text boxes in the code below), which creates a class (with data stored within the user control so that multiple user controls can be created with a single button) and adds it to a list stored in the main window file to be written to a csv file later. I'm getting the following error when I hit the button to create a new user control:
An unhandled exception of type 'System.NullReferenceException' occurred in MasterListErrorTest.exe
Additional information: Object reference not set to an instance of an object.
I created a simplified version of my project that contains just the elements needed to reproduce the error. Here's all my code so you can plug it straight in and get the error for yourself. What am I doing wrong?
MainWindow.xaml:
<Window x:Class="MasterListErrorTest.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:MasterListErrorTest"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel x:Name="UserControlContainer" HorizontalAlignment="Left" Height="216" Margin="24,83,0,0" VerticalAlignment="Top" Width="471" Orientation="Horizontal"/>
<Button x:Name="CreateNewControl" Content="Create New" HorizontalAlignment="Left" Margin="76,37,0,0" VerticalAlignment="Top" Width="75" Click="CreateNewControl_Click"/>
<Button x:Name="GiveStringFromList" Content="Give String" HorizontalAlignment="Left" Margin="360,37,0,0" VerticalAlignment="Top" Width="75" Click="GiveStringFromList_Click"/>
</Grid>
</Window>
MainWindow.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MasterListErrorTest
{
public partial class MainWindow : Window
{
int MultipleTextBoxControlID = 1;
public MainWindow()
{
InitializeComponent();
}
public static class TextBoxControlList
{
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList;
}
private void CreateNewControl_Click(object sender, RoutedEventArgs e)
{
MultipleTextBoxControl newUserControl = new MultipleTextBoxControl(MultipleTextBoxControlID);
UserControlContainer.Children.Add(newUserControl);
}
private void GiveStringFromList_Click(object sender, RoutedEventArgs e)
{
foreach (MultipleTextBoxControl.TextBoxData textBoxPanel in TextBoxControlList.MasterDataList)
{
List<string> userControlLine = new List<string>();
userControlLine.Add(textBoxPanel.Identifier.ToString());
userControlLine.Add(textBoxPanel.TextBox1Data);
userControlLine.Add(textBoxPanel.TextBox2Data);
MessageBox.Show(string.Join(",", userControlLine));
}
}
}
}
MultipleTextBoxControl.xaml:
<UserControl x:Class="MasterListErrorTest.MultipleTextBoxControl"
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:MasterListErrorTest"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="300">
<Grid>
<TextBox x:Name="textBox1" HorizontalAlignment="Left" Height="23" Margin="0,10,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" TextChanged="textBox1_TextChanged"/>
<TextBox x:Name="textBox2" HorizontalAlignment="Left" Height="23" Margin="153,10,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Width="120" TextChanged="textBox2_TextChanged"/>
</Grid>
</UserControl>
MultipleTextBoxControl.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace MasterListErrorTest
{
public partial class MultipleTextBoxControl : UserControl
{
TextBoxData newTextBoxGroup = new TextBoxData();
public MultipleTextBoxControl(int identifier)
{
InitializeComponent();
newTextBoxGroup.Identifier = identifier;
MainWindow.TextBoxControlList.MasterDataList.Add(newTextBoxGroup);
}
public class TextBoxData
{
public int Identifier { get; set; }
public string TextBox1Data { get; set; }
public string TextBox2Data { get; set; }
public TextBoxData()
{
TextBox1Data = "Unchanged Textbox 1";
TextBox2Data = "Unchanged Textbox 2";
}
}
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
newTextBoxGroup.TextBox1Data = textBox1.Text;
}
private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
{
newTextBoxGroup.TextBox2Data = textBox2.Text;
}
}
}
Change your TextBoxControlList class to :
public static class TextBoxControlList
{
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList;
static TextBoxControlList() {
MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
}
}
A better way to do :
Refactor#1
MultipleTextBoxControl.xaml.cs
public partial class MultipleTextBoxControl : UserControl
{
TextBoxData _newTextBoxGroup;
public TextBoxData TextBoxGroup { get { return _newTextBoxGroup; } }
public MultipleTextBoxControl(int identifier)
{
InitializeComponent();
_newTextBoxGroup = new TextBoxData(identifier);
}
public class TextBoxData
{
public int Identifier { get; set; }
public string TextBox1Data { get; set; }
public string TextBox2Data { get; set; }
public TextBoxData(int identifier)
{
Identifier = identifier;
TextBox1Data = "Unchanged Textbox 1";
TextBox2Data = "Unchanged Textbox 2";
}
}
private void textBox1_TextChanged(object sender, TextChangedEventArgs e)
{
_newTextBoxGroup.TextBox1Data = textBox1.Text;
}
private void textBox2_TextChanged(object sender, TextChangedEventArgs e)
{
_newTextBoxGroup.TextBox2Data = textBox2.Text;
}
}
MainWindow.cs
public partial class MainWindow : Window
{
int MultipleTextBoxControlID = 1;
public static List<MultipleTextBoxControl.TextBoxData> MasterDataList;
static MainWindow() {
MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
}
public MainWindow()
{
InitializeComponent();
}
private void CreateNewControl_Click(object sender, RoutedEventArgs e)
{
MultipleTextBoxControl newUserControl = new MultipleTextBoxControl(MultipleTextBoxControlID);
UserControlContainer.Children.Add(newUserControl);
MasterDataList.Add(newUserControl.TextBoxGroup);
}
private void GiveStringFromList_Click(object sender, RoutedEventArgs e)
{
foreach (MultipleTextBoxControl.TextBoxData textBoxPanel in MasterDataList)
{
List<string> userControlLine = new List<string>();
userControlLine.Add(textBoxPanel.Identifier.ToString());
userControlLine.Add(textBoxPanel.TextBox1Data);
userControlLine.Add(textBoxPanel.TextBox2Data);
MessageBox.Show(string.Join(",", userControlLine));
}
}
}
If you put a try/catch exception block around the code in your CreateNewControl_Click then the caught exception will give you more information about what's going on. The StackTrace says this:
at GuiTest.MultipleTextBoxControl..ctor(Int32 identifier) in c:\Dev\GuiTest\MultipleTextBoxControl.xaml.cs:line 31
at GuiTest.MainWindow25.CreateNewControl_Click(Object sender, RoutedEventArgs e) in c:\Dev\GuiTest\MainWindow25.xaml.cs:line 43
So the most recent item on the list is MultipleTextBoxControl.xaml.cs line 31:
MainWindow25.TextBoxControlList.MasterDataList.Add(newTextBoxGroup);
Placing a breakpoint here and examining the contents reveals that MasterDataList is null, because you're not initializing it in TextBoxControlList:
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList;
So do so:
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
Personally I would strongly advise against the use of static classes members, especially in cases like this, but either way this is the answer to your question.
EDIT:
I totally agree with the main points that AnjumSKhan is making, although I personally would go about it using Inversion of Control (IoC). What you're really trying to do is get the child controls to register their data in a way that the Main Window code can access later. As AnjumSKhan points out the children shouldn't know anything about their parent, but you should also be able to create and unit test this behaviour in your child class without needing to create a parent. Inversion of control involves passing in an interface to the child that it should use to register itself, a very simple example might be this:
public interface IDataRegistrationService
{
void Register(MultipleTextBoxControl.TextBoxData data);
}
Your child window can accept a reference to such a service in its constructor and do the registration as it was before but using this service instead:
public MultipleTextBoxControl(int identifier, IDataRegistrationService service)
{
InitializeComponent();
newTextBoxGroup.Identifier = identifier;
service.Register(newTextBoxGroup); // <---------
}
Your MainWindow class can now inherit from this and pass a reference to itself in when the child is created (note I've also made MasterDataList a regular property of MainWindow):
public static List <MultipleTextBoxControl.TextBoxData> MasterDataList = new List<MultipleTextBoxControl.TextBoxData>();
public void Register(MultipleTextBoxControl.TextBoxData data)
{
MasterDataList.Add(data);
}
private void CreateNewControl_Click(object sender, RoutedEventArgs e)
{
MultipleTextBoxControl newUserControl = new MultipleTextBoxControl(MultipleTextBoxControlID, this);
UserControlContainer.Children.Add(newUserControl);
}
By doing this you've formalized the relationship between the parent and child and prevented yourself or others adding more relationships between the two that might be difficult to untangle or change later. You're also now in a position where you can create an instance of your child and use a mocked object (e.g. using the Moq library) to test that it behaves as expected. And by maintaining good separation of concerns you have the freedom to pass in any service you want...maybe later on you'll decide that you need multiple panels with one server per panel.
The one downside to IoC is that you wind up passing references to service provider all over your project, with middle layers keeping references to objects higher up the hierarchy for the sole purpose of passing them lower down. This is what Dependency Injection frameworks solve (e.g. Ninject). They get rid of all that parameter passing and your final code winds up looking something like this:
public partial class MultipleTextBoxControl : UserControl
{
// this gets created by the DI framework, with identifier set automatically
[Inject] private TextBoxData newTextBoxGroup { get; set; }
// this get injected automatically when the class is create
[Inject] private IDataRegistrationService DataService {get; set;}
public MultipleTextBoxControl()
{
InitializeComponent();
}
// this gets called immediately after the constructor
public void Initialize()
{
// and you do any custom initialization here, using injected components
this.DataService.Register(newTextBoxGroup);
}
I used semiglobal reference to MainWindow in user control like this:
public partial class MainWindow : Window
{
public static MainWindow Me = null;
public MainWindow()
{
Me = this;
InitializeComponent();
Then I used this "Me" in User control:
public partial class UserControlTable : UserControl
{
DataCenterSender m_DataCenterSender = new DataCenterSender(MainWindow.Me.Get_DataCenter());
And had a Null Pointer in XAML Editor.
Looks like constructor of MainWindow has not been called in XAML editor and since MainWindow.Me==null in this case User Control ctor failed.
i have one wpf window called usermanagement and there is a listbox showing all the users, i have one button in usermanagement window called add user and when i click on that new window opens called adduser, in this window there are input fields to add new user, what i need when i save data and this adduser window close then the usermanagement window update the listbox, means users again update (the new added user should show there after adding). at the moment i needed to open the usermanagement window again to see the new added user. Thanks!
here is the code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Collections;
using Model;
namespace Views
{
/// <summary>
/// Interaction logic for frmUserManagement.xaml
/// </summary>
public partial class frmUserManagement : Window
{
public frmUserManagement()
{
InitializeComponent();
}
public void window_loaded(object sender, RoutedEventArgs e)
{
load_users();
}
public void load_users()
{
RST_DBDataContext conn = new RST_DBDataContext();
var users = (from s in conn.TblUsers
select s.UserName).ToList();
Login_Names.ItemsSource = users;
}
private void add_user(object sender, RoutedEventArgs e)
{
adduser AddUserWindow = new adduser();
AddUserWindow.ShowDialog();
}
}
}
in xaml file there is
<Grid>
<ListBox Name="Login_Names" HorizontalAlignment="Left" Height="337" Margin="10,47,0,0" Padding="0,0,0,0" VerticalAlignment="Top" Width="156">
<Button Content="Add" HorizontalAlignment="Left" Margin="10,404,0,0" VerticalAlignment="Top" Width="75" Click="add_user"/>
</Grid>
Do insert operations inside main window (UserManagmentWindow):
UserManagmentWindow.cs:
// Inside add button handler open adduser window as dialog box...
var result = adduser.ShowDialog();
if(result == true){
// user pressed OK button...
// insert new user in database
// refresh UserManagmentWindow
}
Post your code if you need more details...
You can declare an event in Your AddUser window, and trigger the event when you press the button.
First define your EventArgs child class
public class AddUserEventArgs : EventArgs
{
public User AddInfo { get; private set; }
public AddUserEventArgs(User info)
{
this.AddInfo = info;
}
}
In your AddUser class:
public event EventHandler<AddUserEventArgs> AddedUser;
private void Button_Click(Object sender, RoutedEventArgs)
{
User info = new User();
// Realize your validation here...
// If validation is Okay, then..
if (OK)
{
if (this.AddedUser != null)
this.AddedUser(this, new AddUserEventArgs(info));
this.Close();
}
}
In your UserManagement class:
var window = new AddUserWindow();
window.AddedUser += (sender, e) =>
{
// Add the info to your ObservableCollection.
this.collection.Add(e.AddInfo);
}
window.ShowDialog();